summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--riscos/filename.c284
-rw-r--r--riscos/filename.h22
2 files changed, 306 insertions, 0 deletions
diff --git a/riscos/filename.c b/riscos/filename.c
new file mode 100644
index 000000000..1265c8903
--- /dev/null
+++ b/riscos/filename.c
@@ -0,0 +1,284 @@
+/*
+ * This file is part of NetSurf, http://netsurf.sourceforge.net/
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ */
+
+/** \file
+ * Provides a central method of obtaining unique filenames.
+ *
+ * A maximum of 2^24 files can be allocated at any point in time.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "oslib/osfile.h"
+#include "netsurf/riscos/filename.h"
+#include "netsurf/utils/log.h"
+
+#define FULL_WORD (unsigned int)4294967295
+
+struct directory {
+ char prefix[10]; /** directory prefix, eg '00.11.52.' */
+ unsigned int low_used; /** first 32 files, 1 bit per file */
+ unsigned int high_used; /** last 32 files, 1 bit per file */
+ unsigned int low_persistent; /** first 32 files, 1 bit per file */
+ unsigned int high_persistent; /** last 32 files, 1 bit per file */
+ struct directory *next; /** next directory (sorted by prefix) */
+};
+
+
+static struct directory *root = NULL;
+static char ro_filename_buffer[12];
+static char ro_filename_directory[256];
+
+static struct directory *ro_filename_create_directory(const char *prefix);
+
+
+/**
+ * Request a new, unique, filename.
+ *
+ * \param persistent keep the filename allocated across sessions
+ * \return a pointer to a shared buffer containing the new filename
+ */
+char *ro_filename_request(bool persistent) {
+ struct directory *dir;
+ int i = -1;
+
+ for (dir = root; dir; dir = dir->next)
+ if ((dir->low_used & dir->high_used) != FULL_WORD) {
+ if (dir->low_used != FULL_WORD) {
+ for (i = 0; (dir->low_used & (1 << i)); i++);
+ } else {
+ for (i = 0; (dir->high_used & (1 << i)); i++);
+ i += 32;
+ }
+ break;
+ }
+ if (i == -1) {
+ /* no available slots - create a new directory */
+ dir = ro_filename_create_directory(NULL);
+ if (!dir) {
+ LOG(("Failed to create a new directory."));
+ return NULL;
+ }
+ i = 63;
+ }
+ if (i < 32) {
+ dir->low_used |= (1 << i);
+ if (persistent)
+ dir->low_persistent |= (1 << i);
+ } else {
+ dir->high_used |= (1 << (i - 32));
+ if (persistent)
+ dir->high_persistent |= (1 << (i - 32));
+ }
+ sprintf(ro_filename_buffer, "%s%i", dir->prefix, i);
+ return ro_filename_buffer;
+}
+
+
+/**
+ * Releases a filename for future use.
+ *
+ * \param filename the filename to release
+ */
+void ro_filename_release(const char *filename) {
+ char *last;
+ char dir_prefix[16];
+ int i;
+ struct directory *dir;
+
+ /* extract the prefix */
+ sprintf(dir_prefix, filename);
+ for (i = 0, last = dir_prefix; i < 3; i++)
+ while (*last++ != '.');
+ i = atoi(last);
+ last[0] = '\0';
+
+ /* modify the correct directory entry */
+ for (dir = root; dir; dir = dir->next)
+ if (!strcmp(dir->prefix, dir_prefix)) {
+ if (i < 32) {
+ dir->low_used &= ~(1 << i);
+ dir->low_persistent &= ~(1 << i);
+ } else {
+ dir->high_used &= ~(1 << (i - 32));
+ dir->high_persistent &= ~(1 << (i - 32));
+ }
+ return;
+ }
+}
+
+
+/**
+ * Initialise the filename provider and load the previous session state.
+ */
+bool ro_filename_initialise(void) {
+ char s[16];
+ struct directory *dir;
+ FILE *fp;
+ int version;
+
+ /* create the 'CACHE_FILENAME_PREFIX' structure */
+ xosfile_create_dir("<Wimp$ScrapDir>.WWW", 0);
+ xosfile_create_dir("<Wimp$ScrapDir>.WWW.NetSurf", 0);
+ xosfile_create_dir("<Wimp$ScrapDir>.WWW.NetSurf.Cache", 0);
+
+ /* load the persistent file list */
+ fp = fopen("Choices:WWW.NetSurf.Filename", "r");
+ if (!fp) {
+ LOG(("Unable to open filename record for reading."));
+ return true;
+ }
+
+ if (!fgets(s, 16, fp)) {
+ fclose(fp);
+ return false;
+ }
+ version = atoi(s);
+ if (version != 100) {
+ LOG(("Invalid or unsupported filename record."));
+ fclose(fp);
+ return false;
+ }
+ while (fgets(s, 16, fp)) {
+ if (s[strlen(s) - 1] == '\n')
+ s[strlen(s) - 1] = '\0';
+ dir = ro_filename_create_directory(s);
+ if (!dir) {
+ LOG(("Unable to load filename record for prefix '%s'.",
+ s));
+ fclose(fp);
+ return false;
+ }
+ if (!fgets(s, 16, fp)) {
+ fclose(fp);
+ return false;
+ }
+ dir->low_used = dir->low_persistent = (unsigned int)
+ strtoul(s, (char **)NULL, 10);
+ if (!fgets(s, 16, fp)) {
+ fclose(fp);
+ return false;
+ }
+ dir->high_used = dir->high_persistent = (unsigned int)
+ strtoul(s, (char **)NULL, 10);
+ }
+ fclose(fp);
+
+ ro_filename_finalise();
+ return true;
+}
+
+
+/**
+ * Finalise the filename provider and save the previous session state.
+ */
+bool ro_filename_finalise(void) {
+ struct directory *dir;
+ FILE *fp;
+
+ fp = fopen("<Choices$Write>.WWW.NetSurf.Filename", "w");
+ if (!fp) {
+ LOG(("Unable to open filename record for writing."));
+ return false;
+ }
+ fprintf(fp, "100\n");
+
+ /* dump the persistent files in the format of:
+ * [prefix]\n[low used word]\n[high used word]\n */
+ for (dir = root; dir; dir = dir->next)
+ if ((dir->low_persistent | dir->high_persistent) != 0)
+ fprintf(fp, "%s\n%u\n%u\n",
+ dir->prefix,
+ dir->low_persistent,
+ dir->high_persistent);
+ fclose(fp);
+ return true;
+}
+
+
+/**
+ * Deletes all files in the cache directory that are not accounted for.
+ */
+void ro_filename_flush(void) {
+ // todo: delete any files that aren't known of
+ // todo: delete any empty references (?)
+}
+
+
+/**
+ * Creates a new directory.
+ *
+ * \param prefix the prefix to use, or NULL to allocate a new one
+ * \return a new directory structure, or NULL on memory exhaustion
+ *
+ * Empty directories are never deleted, except by an explicit call to
+ * ro_filename_flush().
+ */
+static struct directory *ro_filename_create_directory(const char *prefix) {
+ char *last_1, *last_2;
+ int result, index;
+ struct directory *old_dir, *new_dir, *prev_dir = NULL;
+ char dir_prefix[16];
+
+ /* get the lowest unique prefix, or use the provided one */
+ if (prefix) {
+ strcpy(dir_prefix, prefix);
+ } else {
+ sprintf(dir_prefix, "00.00.00.");
+ for (index = 1, old_dir = root; old_dir;
+ index++, old_dir = old_dir->next) {
+ if (strcmp(old_dir->prefix, dir_prefix))
+ break;
+ sprintf(dir_prefix, "%.2i.%.2i.%.2i.",
+ ((index >> 12) & 63),
+ ((index >> 6) & 63),
+ ((index >> 0) & 63));
+ }
+ }
+
+ /* allocate a new directory */
+ new_dir = (struct directory *)calloc(1,
+ sizeof(struct directory));
+ if (!new_dir) {
+ LOG(("No memory for calloc()"));
+ return NULL;
+ }
+ strcpy(new_dir->prefix, dir_prefix);
+
+ /* link into the tree, sorted by prefix. */
+ for (old_dir = root; old_dir; prev_dir = old_dir,
+ old_dir = old_dir->next) {
+ result = strcmp(old_dir->prefix, dir_prefix);
+ if (result == 0) {
+ free(new_dir);
+ return old_dir;
+ } else if (result > 0)
+ break;
+ }
+ if (!prev_dir) {
+ new_dir->next = root;
+ root = new_dir;
+ } else {
+ new_dir->next = prev_dir->next;
+ prev_dir->next = new_dir;
+ }
+
+ /* create the directory structure */
+ sprintf(ro_filename_directory, "%s.", CACHE_FILENAME_PREFIX);
+ last_1 = ro_filename_directory + strlen(CACHE_FILENAME_PREFIX) + 1;
+ last_2 = new_dir->prefix;
+ for (int i = 0; i < 3; i++) {
+ *last_1++ = *last_2++;
+ while (*last_2 != '.')
+ *last_1++ = *last_2++;
+ last_1[0] = '\0';
+ xosfile_create_dir(ro_filename_directory, 0);
+ }
+ return new_dir;
+}
diff --git a/riscos/filename.h b/riscos/filename.h
new file mode 100644
index 000000000..8dd6b20ce
--- /dev/null
+++ b/riscos/filename.h
@@ -0,0 +1,22 @@
+/*
+ * This file is part of NetSurf, http://netsurf.sourceforge.net/
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2005 Richard Wilson <info@tinct.net>
+ */
+
+#ifndef _NETSURF_RISCOS_FILENAME_H_
+#define _NETSURF_RISCOS_FILENAME_H_
+
+#include <stdbool.h>
+
+#define CACHE_FILENAME_PREFIX "<Wimp$ScrapDir>.WWW.NetSurf.Cache"
+
+char *ro_filename_request(bool persistent);
+void ro_filename_release(const char *filename);
+bool ro_filename_initialise(void);
+bool ro_filename_finalise(void);
+void ro_filename_flush(void);
+
+
+#endif