Commit 6e3cce14 authored by Andrew Hodgkinson's avatar Andrew Hodgkinson
Browse files

Forgot to add in ImgHistory.c / h last time. Note also that only the Browse...

Forgot to add in ImgHistory.c / h last time. Note also that only the Browse and Ursula resources are up to date at this point - bits are missing from the other builds.
parent 2a2b2672
/* Copyright 1997 Acorn Computers Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***************************************************/
/* File : ImgHistory.c */
/* */
/* Purpose: Remembering image sizes, in case the */
/* HTML doesn't specify it. */
/* */
/* Author : A.D.Hodgkinson */
/* */
/* History: 22-Nov-97: Created. */
/***************************************************/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "kernel.h"
#include "swis.h"
#include "flex.h"
#include "wimp.h"
#include "wimplib.h"
#include "event.h"
#include "toolbox.h"
#include "svcprint.h"
#include "Global.h"
#include "Utils.h"
#include "ChoiceDefs.h"
#include "Images.h"
#include "ImgHistory.h"
/* Image history structure. It's so small that these */
/* are kept in an array (one malloc block). */
typedef struct imghistory_entry
{
char * url;
int os_x;
int os_y;
unsigned int last_accessed;
}
imghistory_entry;
/* Static variables */
static imghistory_entry * imghistory_base = NULL;
int imghistory_entries = 0;
/* Local statics */
static int imghistory_find_entry (const char ** url_base, int url_offset);
static void imghistory_remove_entry (int entry);
static void imghistory_expire (unsigned int time);
static int imghistory_count (void);
static void imghistory_limit (unsigned int size);
/*************************************************/
/* imghistory_find_entry() */
/* */
/* Searches for a given image in the image */
/* history, and returns an array index for that */
/* image if it is present, else -1. */
/* */
/* If the parameters seem odd, it may help to */
/* realise that this allows a flex block to hold */
/* the URL without any worries about flex */
/* shifting. */
/* */
/* Parameters: Pointer to a pointer to a block */
/* containing the image's full URL; */
/* */
/* Offset into the block at which */
/* the image lies. */
/* */
/* Returns: Index in the image history array */
/* of the entry representing the */
/* image if found, else -1. */
/*************************************************/
static int imghistory_find_entry(const char ** url_base, int url_offset)
{
int entry;
if (!imghistory_entries || !url_base) return -1;
/* Go through the array. Slow linear search for the moment... */
for (entry = 0; entry < imghistory_entries; entry++)
{
/* Use strcmp. We're going to be very strict in this; strcmp is not */
/* a technically valid way to compare URLs, but it's fast and you */
/* don't need much storage space for the URLs themselves. The image */
/* history is not sufficiently important to warrant anything more */
/* robust than this. */
if (!strcmp(imghistory_base[entry].url, *url_base + url_offset)) return entry;
}
/* Nothing found */
return -1;
}
/*************************************************/
/* imghistory_record() */
/* */
/* Records a given image in the image history. */
/* If an entry is already present for the image, */
/* it just updates the entry's last_accessed */
/* field and ensures the size is set to the */
/* given values. */
/* */
/* Parameters: Pointer to a pointer to a block */
/* containing the image's full URL; */
/* */
/* Offset into the block at which */
/* the image lies; */
/* */
/* x size of the image, in OS units; */
/* */
/* y size of the image, in OS units. */
/*************************************************/
_kernel_oserror * imghistory_record(const char ** url_base, int url_offset, int os_x, int os_y)
{
imghistory_entry * new_base;
char * new_url;
int entry;
if (!url_base) return NULL;
/* Try to find the item */
entry = imghistory_find_entry(url_base, url_offset);
/* Found it */
if (entry >= 0)
{
imghistory_base[entry].last_accessed = time(NULL);
/* Ensure the recorded size matches that given! */
imghistory_base[entry].os_x = os_x;
imghistory_base[entry].os_y = os_y;
/* That's all we need to do in this case */
return NULL;
}
/* Oh well, it wasn't there. So have to make a new entry */
new_base = realloc(imghistory_base, sizeof(imghistory_entry) * (imghistory_entries + 1));
/* Claim failed, so exit with error */
if (!new_base) return make_no_memory_error(28);
/* OK, managed that; set imghistory_base to whatever was returned */
/* by realloc but don't increment the items counter yet */
imghistory_base = new_base;
/* Try to allocate space for the URL too */
new_url = malloc(strlen(*url_base + url_offset) + 1);
/* If this claim fails, don't bother shrinking the array back; */
/* we haven't increased the item count, so things will take */
/* care of themselves on the next addition (assuming that the */
/* lack of memory doesn't prove catastrophic elsewhere!). */
if (!new_url) return make_no_memory_error(28);
/* If we reach here, both claims were successful */
imghistory_base[imghistory_entries].url = new_url;
imghistory_base[imghistory_entries].os_x = os_x;
imghistory_base[imghistory_entries].os_y = os_y;
imghistory_base[imghistory_entries].last_accessed = time(NULL);
strcpy(new_url, *url_base + url_offset);
imghistory_entries ++;
/* Call expiry functions */
if (choices.image_expiry_age) imghistory_expire(time(NULL) - choices.image_expiry_age);
if (choices.image_max_size) imghistory_limit(choices.image_max_size);
/* Finished; exit by saving, if required */
if (choices.save_image_history == Choices_SaveImageHistory_Always)
{
return imghistory_save(lookup_choice("ImageHistoryPath:Browse:User.Images",0,0));
}
/* Otherwise, exit quietly */
else return NULL;
}
/*************************************************/
/* imghistory_return_size() */
/* */
/* Returns the size of an image based on the */
/* given URL. If the image has no entry in the */
/* image history, -1 is returned for the x and */
/* y sizes. */
/* */
/* Parameters: Pointer to a pointer to a block */
/* containing the image's full URL; */
/* */
/* Offset into the block at which */
/* the image lies; */
/* */
/* Pointer to an int, in which the x */
/* size of the image is returned in */
/* OS units, or -1 if the image has */
/* no entry in the image history; */
/* */
/* Similarly, pointer to an int for */
/* the y size. */
/* */
/* Assumes: The int pointers may be NULL (but */
/* this would of course be pretty */
/* pointless!). */
/*************************************************/
void imghistory_return_size(const char ** url_base, int url_offset, int * os_x, int * os_y)
{
int entry;
if (os_x) *os_x = -1;
if (os_y) *os_y = -1;
if (!url_base) return;
/* Try and find the entry for this image */
entry = imghistory_find_entry(url_base, url_offset);
/* Not found */
if (entry < 0) return;
/* Found, so return the sizes and exit */
if (os_x) *os_x = imghistory_base[entry].os_x;
if (os_y) *os_y = imghistory_base[entry].os_y;
return;
}
/*************************************************/
/* imghistory_remove_entry() */
/* */
/* Removes an entry from the image history */
/* array by copying the last item over it and */
/* shrinking the array size. */
/* */
/* Parameters: Entry number. */
/*************************************************/
static void imghistory_remove_entry(int entry)
{
if (entry < 0 || entry >= imghistory_entries) return;
/* If this is the last item, only need to shrink */
/* the array and decrement the item counter. Else, */
/* copy the top item over the one being removed */
/* and then shrink the array. */
if (entry < imghistory_entries - 1)
{
memcpy(&imghistory_base[entry],
&imghistory_base[imghistory_entries - 1],
sizeof(imghistory_entry));
}
imghistory_entries --;
/* Shouldn't fail, but if it does... Well, we ditch the history. */
imghistory_base = realloc(imghistory_base,
imghistory_entries * sizeof(imghistory_entry));
/* Finished */
return;
}
/*************************************************/
/* imghistory_expire() */
/* */
/* Remove all entiries for images which have */
/* last been seen before a given time (i.e. are */
/* greater than a certain age). */
/* */
/* Parameters: Time (in time() function format) */
/* which an image must not have been */
/* visited on or since for expiry to */
/* take place - so to expire 1 day */
/* old images, say, you'd pass */
/* time() - 60*60*24. */
/*************************************************/
static void imghistory_expire(unsigned int time)
{
int entry = 0;
/* Go through removing items. The removal routine copies the last */
/* array item over the one being removed, so we only imcrement */
/* the entry number if nothing has been removed. */
while (entry < imghistory_entries)
{
if (imghistory_base[entry].last_accessed <= time) imghistory_remove_entry(entry);
else entry++;
}
return;
}
/*************************************************/
/* imghistory_count() */
/* */
/* Count the total space used by the image */
/* history. */
/* */
/* Returns: Space occupied by the image */
/* history array and strings */
/* attached to this, including their */
/* terminators, in bytes. */
/*************************************************/
static int imghistory_count(void)
{
int count = 0;
int entry;
for (entry = 0; entry < imghistory_entries; entry ++)
{
count += sizeof(imghistory_entry);
count += imghistory_base[entry].url ? strlen(imghistory_base[entry].url) + 1 : 0;
}
return count;
}
/*************************************************/
/* imghistory_limit() */
/* */
/* Limit the space occupied by the image history */
/* to a given amount. */
/* */
/* Parameters: Maximum size the history may be, */
/* in bytes. */
/*************************************************/
static void imghistory_limit(unsigned int size)
{
int entry;
int oldest;
int found;
/* Keep removing items until we come in under the required size */
while (size <= imghistory_count())
{
/* Find the oldest entry */
oldest = 0;
found = 0;
for (entry = 0; entry < imghistory_entries; entry++)
{
if (
imghistory_base[entry].last_accessed < oldest ||
!oldest
)
oldest = imghistory_base[entry].last_accessed, found = entry;
}
/* Remove the oldest entry, if found */
if (oldest) imghistory_remove_entry(found);
}
/* Finished */
return;
}
/*************************************************/
/* imghistory_load() */
/* */
/* Loads the global history from the given path. */
/* Will raise errors (usually, due to RISC OS */
/* C's file I/O, the wrong ones...) if there is */
/* a failure during loading, but not if the file */
/* refuses to open or the number of items cannot */
/* be read from it (i.e. a missing or zero */
/* length History file). */
/* */
/* Parameters: Pointer to the full pathname for */
/* the history file. */
/*************************************************/
_kernel_oserror * imghistory_load(const char * pathname)
{
FILE * file;
char * url = NULL;
static char * local_path = NULL;
int result;
int last_accessed, os_x, os_y, url_len;
int items, item;
int cc, ch;
if (!pathname || !*pathname) return NULL;
local_path = malloc(strlen(pathname) + 1);
if (!local_path) return NULL;
strcpy(local_path, pathname);
file = fopen(local_path, "rb");
if (!file)
{
free(local_path);
return NULL; /* Fail silently - there may be no History file; this is OK */
}
/* Read how many items there are - again file silently, the */
/* file may just be zero bytes long. */
result = fscanf(file, "%d\n", &items);
if (result == EOF)
{
fclose(file);
free(local_path);
return NULL;
}
/* Allocate space for the array */
imghistory_base = malloc(sizeof(imghistory_entry) * items);
if (!imghistory_base)
{
fclose(file);
free(local_path);
return make_no_memory_error(29);
}
imghistory_entries = 0; /* We'll increment this as each gets loaded successfully */
/* Now load each entry's details */
for (item = 0; item < items; item++)
{
/* Read the last accessed time and required string lengths */
result = fscanf(file, "%d,%d,%d,%d\n", &last_accessed, &os_x, &os_y, &url_len);
if (result == EOF) goto imghistory_load_exit;
/* Allocate buffers for the strings */
url = malloc(url_len + 1);
if (!url)
{
imghistory_entries = item; /* E.g. if item 0 fails to load, we say there are zero entries */
fclose(file);
free(local_path);
return make_no_memory_error(29);
}
/* Read the URL */
for (cc = 0; cc < url_len; cc++)
{
int ch = fgetc(file);
if (result == ch) goto imghistory_load_exit;
url[cc] = (char) ch;
}
url[url_len] = 0;
/* Skip the '\n' */
ch = fgetc(file);
if (result == ch) goto imghistory_load_exit;
/* Now make the entry */
imghistory_base[item].url = url;
url = NULL; /* Make sure we don't go and free it or something! */
imghistory_base[item].os_x = os_x;
imghistory_base[item].os_y = os_y;
imghistory_base[item].last_accessed = last_accessed;
/* Successful addition */
imghistory_entries ++;
/* (Closure of 'for' loop) */
}
fclose(file);
free(local_path);
if (choices.image_expiry_age) imghistory_expire(time(NULL) - choices.image_expiry_age);
if (choices.image_max_size) imghistory_limit(choices.image_max_size);
return NULL;
/* Error condition exit */
imghistory_load_exit:
fclose(file);
free(url);
free(local_path);
RetLastE;
}
/*************************************************/
/* imghistory_save() */
/* */
/* Saves the global history to the given path. */
/* */
/* Parameters: Pointer to the full pathname for */
/* the history file. */
/*************************************************/
_kernel_oserror * imghistory_save(const char * pathname)
{
static char * local_path = NULL;
FILE * file;
int entry;
int wrote;
if (!pathname || !*pathname) return NULL;
local_path = malloc(strlen(pathname) + 1);
if (!local_path) return NULL;
strcpy(local_path, pathname);
/* Create the file */
file = fopen(local_path, "wb");
if (!file)
{
free(local_path);
RetLastE;
}
/* Write the number of items */
wrote = fprintf(file, "%d\n", imghistory_entries);
if (wrote <= 0)
{
fclose(file);
free(local_path);
RetLastE;
}
/* Write the item contents */
if (imghistory_entries)
{
for (entry = 0; entry < imghistory_entries; entry++)
{
wrote = fprintf(file,
"%d,%d,%d,%d\n%s\n",
imghistory_base[entry].last_accessed,
imghistory_base[entry].os_x,
imghistory_base[entry].os_y,
imghistory_base[entry].url ? strlen(imghistory_base[entry].url) : 0,
imghistory_base[entry].url ? imghistory_base[entry].url : "");
if (wrote <= 0)
{
fclose(file);
free(local_path);
RetLastE;
}
}
}
/* Close the file and exit */
fclose(file);
free(local_path);
return NULL;
}
/* Copyright 1997 Acorn Computers Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/***************************************************/
/* File : ImgHistory.h */
/* */
/* Purpose: Remembering image sizes, in case the */
/* HTML doesn't specify it. */
/* */
/* Author : A.D.Hodgkinson */
/* */
/* History: 22-Nov-97: Created. */
/***************************************************/
/* Function prototypes */
_kernel_oserror * imghistory_record (const char ** url_base, int url_offset, int os_x, int os_y);
void imghistory_return_size (const char ** url_base, int url_offset, int * os_x, int * os_y);
_kernel_oserror * imghistory_load (const char * pathname);
_kernel_oserror * imghistory_save (const char * pathname);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment