summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2014-05-07 16:14:18 +0100
committerVincent Sanders <vince@kyllikki.org>2014-05-07 16:24:51 +0100
commitc56642819eed87431dff3446fe111f7f3eefaa7d (patch)
tree397126ca4baac425f9c1c44f3d5c56c681e2c4fe
parentc1e2da80dfa62793ea107cf12408c814e268a54b (diff)
downloadnetsurf-c56642819eed87431dff3446fe111f7f3eefaa7d.tar.gz
netsurf-c56642819eed87431dff3446fe111f7f3eefaa7d.tar.bz2
add file operations table and make all frontends use it.
This rationalises the path construction and basename file operations. The default implementation is POSIX which works for all frontends except windows, riscos and amiga which have differeing path separators and rules. These implementations are significantly more robust than the previous nine implementations and also do not use unsafe strncpy or buffers with arbitrary length limits. These implementations also carry full documentation comments.
-rw-r--r--amiga/gui.c143
-rw-r--r--atari/gui.c24
-rwxr-xr-xatari/misc.c34
-rwxr-xr-xatari/misc.h2
-rw-r--r--beos/gui.cpp40
-rw-r--r--cocoa/fetch.m16
-rw-r--r--content/fetchers/curl.c11
-rw-r--r--content/fetchers/file.c186
-rw-r--r--desktop/gui.h33
-rw-r--r--desktop/gui_factory.c35
-rw-r--r--desktop/save_complete.c78
-rw-r--r--framebuffer/fetch.c38
-rw-r--r--gtk/dialogs/preferences.c18
-rw-r--r--gtk/fetch.c42
-rw-r--r--gtk/gui.c55
-rw-r--r--gtk/scaffolding.c10
-rw-r--r--monkey/fetch.c41
-rw-r--r--riscos/gui.c188
-rw-r--r--utils/Makefile2
-rw-r--r--utils/file.c117
-rw-r--r--utils/file.h95
-rw-r--r--utils/filepath.c19
-rw-r--r--utils/filepath.h11
-rw-r--r--windows/gui.c82
-rw-r--r--windows/gui.h1
-rw-r--r--windows/main.c1
26 files changed, 778 insertions, 544 deletions
diff --git a/amiga/gui.c b/amiga/gui.c
index 47a7fbea9..9fce7b0e0 100644
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -36,6 +36,7 @@
#include "utils/utf8.h"
#include "utils/utils.h"
#include "utils/url.h"
+#include "utils/file.h"
#include "content/fetchers/resource.h"
/* NetSurf Amiga platform includes */
@@ -221,33 +222,126 @@ static void gui_window_place_caret(struct gui_window *g, int x, int y, int heigh
nsoptions[NSOPTION_##OPTION].value.i = VALUE; \
nsoptions_default[NSOPTION_##OPTION].value.i = VALUE
+
/**
- * Return the filename part of a full path
+ * Generate a posix path from one or more component elemnts.
+ *
+ * If a string is allocated it must be freed by the caller.
*
- * \param path full path and filename
- * \return filename (will be freed with free())
+ * @param[in,out] str pointer to string pointer if this is NULL enough
+ * storage will be allocated for the complete path.
+ * @param[in,out] size The size of the space available if \a str not
+ * NULL on input and if not NULL set to the total
+ * output length on output.
+ * @param[in] nemb The number of elements.
+ * @param[in] ... The elements of the path as string pointers.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
*/
-
-static char *filename_from_path(char *path)
+static nserror amiga_mkpath(char **str, size_t *size, size_t nelm, va_list ap)
{
- return strdup(FilePart(path));
+ const char *elm[16];
+ size_t elm_len[16];
+ size_t elm_idx;
+ char *fname;
+ size_t fname_len = 0;
+ char *curp;
+
+ /* check the parameters are all sensible */
+ if ((nelm == 0) || (nelm > 16)) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if ((*str != NULL) && (size == NULL)) {
+ /* if the caller is providing the buffer they must say
+ * how much space is available.
+ */
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* calculate how much storage we need for the complete path
+ * with all the elements.
+ */
+ for (elm_idx = 0; elm_idx < nelm; elm_idx++) {
+ elm[elm_idx] = va_arg(ap, const char *);
+ elm_len[elm_idx] = strlen(elm[elm_idx]);
+ fname_len += elm_len[elm_idx];
+ }
+ fname_len += nelm; /* allow for separators and terminator */
+
+ /* ensure there is enough space */
+ fname = *str;
+ if (fname != NULL) {
+ if (fname_len > *size) {
+ return NSERROR_NOSPACE;
+ }
+ } else {
+ fname = malloc(fname_len);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ /* copy the first element complete */
+ memmove(fname, elm[0], elm_len[0]);
+ fname[elm_len[0]] = 0;
+
+ /* add the remaining elements */
+ for (elm_idx = 1; elm_idx < nelm; elm_idx++) {
+ if (!AddPart(fname, elm[elm_idx], fname_len)) {
+ break;
+ }
+ }
+
+ *str = fname;
+ if (size != NULL) {
+ *size = fname_len;
+ }
+
+ return NSERROR_OK;
}
/**
- * Add a path component/filename to an existing path
+ * Get the basename of a file using posix path handling.
+ *
+ * This gets the last element of a path and returns it.
*
- * \param path buffer containing path + free space
- * \param length length of buffer "path"
- * \param newpart string containing path component to add to path
- * \return true on success
+ * @param[in] path The path to extract the name from.
+ * @param[in,out] str Pointer to string pointer if this is NULL enough
+ * storage will be allocated for the path element.
+ * @param[in,out] size The size of the space available if \a
+ * str not NULL on input and set to the total
+ * output length on output.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
*/
-
-static bool path_add_part(char *path, int length, const char *newpart)
+static nserror amiga_basename(const char *path, char **str, size_t *size)
{
- if(AddPart(path, newpart, length)) return true;
- else return false;
+ const char *leafname;
+ char *fname;
+
+ if (path == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ leafname = FilePart(path);
+ if (leafname == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ fname = strdup(leafname);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ *str = fname;
+ if (size != NULL) {
+ *size = strlen(fname);
+ }
+ return NSERROR_OK;
}
+
+
STRPTR ami_locale_langs(void)
{
struct Locale *locale;
@@ -290,12 +384,12 @@ bool ami_gui_map_filename(char **remapped, const char *path, const char *file, c
{
BPTR fh = 0;
char mapfile[1024];
+ size_t mapfile_size = 1024;
char buffer[1024];
char *realfname;
bool found = false;
- strcpy(mapfile, path);
- path_add_part(mapfile, 1024, map);
+ amiga_mkpath(&mapfile, &mapfile_size, 2, path, map);
if(fh = FOpen(mapfile, MODE_OLDFILE, 0))
{
@@ -331,9 +425,10 @@ bool ami_gui_check_resource(char *fullpath, const char *file)
bool found = false;
char *remapped;
BPTR lock = 0;
+ size_t fullpath_len = 1024;
ami_gui_map_filename(&remapped, fullpath, file, "Resource.map");
- path_add_part(fullpath, 1024, remapped);
+ amiga_mkpath(&fullpath, &fullpath_len, 2, fullpath, remapped);
LOG(("Checking for %s", fullpath));
@@ -356,6 +451,7 @@ bool ami_locate_resource(char *fullpath, const char *file)
BPTR lock = 0;
bool found = false;
char *remapped;
+ size_t fullpath_len = 1024;
/* Check NetSurf user data area first */
@@ -383,7 +479,7 @@ bool ami_locate_resource(char *fullpath, const char *file)
{
ami_gui_map_filename(&remapped, "PROGDIR:Resources",
locale->loc_PrefLanguages[i], "LangNames");
- path_add_part(fullpath, 1024, remapped);
+ amiga_mkpath(&fullpath, &fullpath_len, 2 fullpath, remapped);
found = ami_gui_check_resource(fullpath, file);
}
@@ -5097,9 +5193,13 @@ static struct gui_window_table amiga_window_table = {
.save_link = gui_window_save_link,
};
+/* amiga file handling operations */
+static struct gui_file_table amiga_file_table = {
+ .mkpath = amiga_mkpath,
+ .basename = amiga_basename,
+};
+
static struct gui_fetch_table amiga_fetch_table = {
- .filename_from_path = filename_from_path,
- .path_add_part = path_add_part,
.filetype = fetch_filetype,
.path_to_url = path_to_url,
.url_to_path = url_to_path,
@@ -5136,6 +5236,7 @@ int main(int argc, char** argv)
.clipboard = amiga_clipboard_table,
.download = amiga_download_table,
.fetch = &amiga_fetch_table,
+ .file = &amiga_file_table,
.utf8 = amiga_utf8_table,
.search = amiga_search_table,
};
diff --git a/atari/gui.c b/atari/gui.c
index c275bfdc4..0979f2974 100644
--- a/atari/gui.c
+++ b/atari/gui.c
@@ -114,28 +114,6 @@ short aes_msg_out[8];
bool gui_window_get_scroll(struct gui_window *w, int *sx, int *sy);
static void gui_window_set_url(struct gui_window *w, const char *url);
-/**
- * Return the filename part of a full path
- *
- * \param path full path and filename
- * \return filename (will be freed with free())
- */
-static char *filename_from_path(char *path)
-{
- char *leafname;
-
- leafname = strrchr(path, '\\');
- if( !leafname )
- leafname = strrchr(path, '/');
- if (!leafname)
- leafname = path;
- else
- leafname += 1;
-
- return strdup(leafname);
-}
-
-
static void gui_poll(bool active)
{
@@ -1071,8 +1049,6 @@ static struct gui_clipboard_table atari_clipboard_table = {
};
static struct gui_fetch_table atari_fetch_table = {
- .filename_from_path = filename_from_path,
- .path_add_part = path_add_part,
.filetype = fetch_filetype,
.path_to_url = path_to_url,
.url_to_path = url_to_path,
diff --git a/atari/misc.c b/atari/misc.c
index ca9e993d9..a8eff288b 100755
--- a/atari/misc.c
+++ b/atari/misc.c
@@ -70,24 +70,6 @@ void die(const char *error)
exit(1);
}
-/**
- * Add a path component/filename to an existing path
- *
- * \param path buffer containing path + free space
- * \param length length of buffer "path"
- * \param newpart string containing path component to add to path
- * \return true on success
- */
-
-bool path_add_part(char *path, int length, const char *newpart)
-{
- if(path[strlen(path) - 1] != '/')
- strncat(path, "/", length);
-
- strncat(path, newpart, length);
-
- return true;
-}
struct gui_window * find_guiwin_by_aes_handle(short handle){
@@ -242,25 +224,17 @@ hlcache_handle *load_icon(const char *name, hlcache_handle_callback cb,
if (!strncmp(name, "file://", 7)) {
icon_url = name;
} else {
- char *native_path;
+ char *native_path = NULL;
if (icons_dir == NULL)
return NULL;
- /* path + separator + leafname + '\0' */
- len = strlen(icons_dir) + 1 + strlen(name) + 1;
- native_path = malloc(len);
- if (native_path == NULL) {
- LOG(("malloc failed"));
- warn_user("NoMemory", 0);
+ err = netsurf_mkpath(&native_path, NULL, 2, icons_dir, name);
+ if (err != NSERROR_OK) {
+ warn_user(messages_get_errorcode(err));
return NULL;
}
- /* Build native path */
- memcpy(native_path, icons_dir,
- strlen(icons_dir) + 1);
- path_add_part(native_path, len, name);
-
/* Convert native path to URL */
url = path_to_url(native_path);
diff --git a/atari/misc.h b/atari/misc.h
index 1bb5e8131..8d1719ce8 100755
--- a/atari/misc.h
+++ b/atari/misc.h
@@ -66,6 +66,4 @@ const char * file_select(const char * title, const char * name);
*/
long nkc_to_input_key(short nkc, long * ucs4_out);
-bool path_add_part(char *path, int length, const char *newpart);
-
#endif
diff --git a/beos/gui.cpp b/beos/gui.cpp
index 365a35642..21bbf11f1 100644
--- a/beos/gui.cpp
+++ b/beos/gui.cpp
@@ -993,44 +993,6 @@ static void *myrealloc(void *ptr, size_t len, void *pw)
return realloc(ptr, len);
}
-/**
- * Return the filename part of a full path
- *
- * \param path full path and filename
- * \return filename (will be freed with free())
- */
-
-static char *filename_from_path(char *path)
-{
- char *leafname;
-
- leafname = strrchr(path, '/');
- if (!leafname)
- leafname = path;
- else
- leafname += 1;
-
- return strdup(leafname);
-}
-
-/**
- * Add a path component/filename to an existing path
- *
- * \param path buffer containing path + free space
- * \param length length of buffer "path"
- * \param newpart string containing path component to add to path
- * \return true on success
- */
-
-static bool path_add_part(char *path, int length, const char *newpart)
-{
- if(path[strlen(path) - 1] != '/')
- strncat(path, "/", length);
-
- strncat(path, newpart, length);
-
- return true;
-}
static struct gui_clipboard_table beos_clipboard_table = {
gui_get_clipboard,
@@ -1038,8 +1000,6 @@ static struct gui_clipboard_table beos_clipboard_table = {
};
static struct gui_fetch_table beos_fetch_table = {
- filename_from_path,
- path_add_part,
fetch_filetype,
path_to_url,
url_to_path,
diff --git a/cocoa/fetch.m b/cocoa/fetch.m
index 70d3805e1..8cc2cb966 100644
--- a/cocoa/fetch.m
+++ b/cocoa/fetch.m
@@ -107,20 +107,6 @@ static char *path_to_url(const char *path)
absoluteString] UTF8String] );
}
-static char *filename_from_path(char *path)
-{
- return strdup( [[[NSString stringWithUTF8String: path] lastPathComponent] UTF8String] );
-}
-
-static bool path_add_part(char *path, int length, const char *newpart)
-{
- NSString *newPath = [[NSString stringWithUTF8String: path] stringByAppendingPathComponent: [NSString stringWithUTF8String: newpart]];
-
- strncpy( path, [newPath UTF8String], length );
-
- return true;
-}
-
static nsurl *gui_get_resource_url(const char *path)
{
nsurl *url = NULL;
@@ -131,8 +117,6 @@ static nsurl *gui_get_resource_url(const char *path)
}
static struct gui_fetch_table fetch_table = {
- .filename_from_path = filename_from_path,
- .path_add_part = path_add_part,
.filetype = fetch_filetype,
.path_to_url = path_to_url,
.url_to_path = url_to_path,
diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c
index 612b77d0b..80ac5ec89 100644
--- a/content/fetchers/curl.c
+++ b/content/fetchers/curl.c
@@ -50,6 +50,7 @@
#include "utils/utils.h"
#include "utils/ring.h"
#include "utils/useragent.h"
+#include "utils/file.h"
#include "content/fetch.h"
#include "content/fetchers/curl.h"
@@ -1280,15 +1281,15 @@ fetch_curl_post_convert(const struct fetch_multipart_data *control)
{
struct curl_httppost *post = 0, *last = 0;
CURLFORMcode code;
+ nserror ret;
for (; control; control = control->next) {
if (control->file) {
- char *leafname = 0;
-
- leafname = guit->fetch->filename_from_path(control->value);
-
- if (leafname == NULL)
+ char *leafname = NULL;
+ ret = guit->file->basename(control->value, &leafname, NULL);
+ if (ret != NSERROR_OK) {
continue;
+ }
/* We have to special case filenames of "", so curl
* a) actually attempts the fetch and
diff --git a/content/fetchers/file.c b/content/fetchers/file.c
index 00d5cc5f1..93e3bf84c 100644
--- a/content/fetchers/file.c
+++ b/content/fetchers/file.c
@@ -18,6 +18,8 @@
/* file: URL handling. Based on the data fetcher by Rob Kendrick */
+#include "utils/config.h"
+
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -34,18 +36,12 @@
#include <limits.h>
#include <stdarg.h>
-#include "utils/config.h"
-
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
#include <libwapcaplet/libwapcaplet.h>
-#include "content/dirlist.h"
-#include "content/fetch.h"
-#include "content/fetchers/file.h"
-#include "content/urldb.h"
#include "desktop/netsurf.h"
#include "desktop/gui_factory.h"
#include "utils/corestrings.h"
@@ -56,6 +52,12 @@
#include "utils/url.h"
#include "utils/utils.h"
#include "utils/ring.h"
+#include "utils/file.h"
+
+#include "content/dirlist.h"
+#include "content/fetch.h"
+#include "content/urldb.h"
+#include "content/fetchers/file.h"
/* Maximum size of read buffer */
#define FETCH_FILE_MAX_BUF_SIZE (1024 * 1024)
@@ -489,6 +491,97 @@ static char *gen_nice_title(char *path)
return title;
}
+/**
+ * generate an output row of the directory listing.
+ *
+ * @param ent current directory entry.
+ */
+static nserror
+process_dir_ent(struct fetch_file_context *ctx,
+ struct dirent *ent,
+ bool even,
+ char *buffer,
+ size_t buffer_len)
+{
+ nserror ret;
+ char *path; /* url for list entries */
+ char *urlpath = NULL; /* buffer for leaf entry path */
+ struct stat ent_stat; /* stat result of leaf entry */
+ char datebuf[64]; /* buffer for date text */
+ char timebuf[64]; /* buffer for time text */
+
+ /* skip hidden files */
+ if (ent->d_name[0] == '.') {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ ret = netsurf_mkpath(&urlpath, NULL, 2, ctx->path, ent->d_name);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ if (stat(urlpath, &ent_stat) != 0) {
+ ent_stat.st_mode = 0;
+ datebuf[0] = 0;
+ timebuf[0] = 0;
+ } else {
+ /* Get date in output format */
+ if (strftime((char *)&datebuf, sizeof datebuf, "%a %d %b %Y",
+ localtime(&ent_stat.st_mtime)) == 0) {
+ datebuf[0] = '-';
+ datebuf[1] = 0;
+ }
+
+ /* Get time in output format */
+ if (strftime((char *)&timebuf, sizeof timebuf, "%H:%M",
+ localtime(&ent_stat.st_mtime)) == 0) {
+ timebuf[0] = '-';
+ timebuf[1] = 0;
+ }
+ }
+
+ if ((path = guit->fetch->path_to_url(urlpath)) == NULL) {
+ free(urlpath);
+ return NSERROR_NOMEM;
+ }
+
+ if (S_ISREG(ent_stat.st_mode)) {
+ /* regular file */
+ dirlist_generate_row(even,
+ false,
+ path,
+ ent->d_name,
+ guit->fetch->filetype(urlpath),
+ ent_stat.st_size,
+ datebuf, timebuf,
+ buffer, buffer_len);
+ } else if (S_ISDIR(ent_stat.st_mode)) {
+ /* directory */
+ dirlist_generate_row(even,
+ true,
+ path,
+ ent->d_name,
+ messages_get("FileDirectory"),
+ -1,
+ datebuf, timebuf,
+ buffer, buffer_len);
+ } else {
+ /* something else */
+ dirlist_generate_row(even,
+ false,
+ path,
+ ent->d_name,
+ "",
+ -1,
+ datebuf, timebuf,
+ buffer, buffer_len);
+ }
+
+ free(path);
+ free(urlpath);
+
+ return NSERROR_OK;
+}
static void fetch_file_process_dir(struct fetch_file_context *ctx,
struct stat *fdstat)
@@ -499,13 +592,7 @@ static void fetch_file_process_dir(struct fetch_file_context *ctx,
char *title; /* pretty printed title */
nserror err; /* result from url routines */
nsurl *up; /* url of parent */
- char *path; /* url for list entries */
- struct stat ent_stat; /* stat result of leaf entry */
- char datebuf[64]; /* buffer for date text */
- char timebuf[64]; /* buffer for time text */
- char urlpath[PATH_MAX]; /* buffer for leaf entry path */
- struct dirent *ent; /* current directory entry */
struct dirent **listing = NULL; /* directory entry listing */
int i; /* directory entry index */
int n; /* number of directory entries */
@@ -570,78 +657,17 @@ static void fetch_file_process_dir(struct fetch_file_context *ctx,
goto fetch_file_process_dir_aborted;
for (i = 0; i < n; i++) {
- ent = listing[i];
-
- if (ent->d_name[0] == '.')
- continue;
- strncpy(urlpath, ctx->path, sizeof urlpath);
- if (guit->fetch->path_add_part(urlpath, sizeof urlpath,
- ent->d_name) == false)
- continue;
-
- if (stat(urlpath, &ent_stat) != 0) {
- ent_stat.st_mode = 0;
- datebuf[0] = 0;
- timebuf[0] = 0;
- } else {
- /* Get date in output format */
- if (strftime((char *)&datebuf, sizeof datebuf,
- "%a %d %b %Y",
- localtime(&ent_stat.st_mtime)) == 0) {
- strncpy(datebuf, "-", sizeof datebuf);
- }
+ err = process_dir_ent(ctx, listing[i], even, buffer,
+ sizeof(buffer));
- /* Get time in output format */
- if (strftime((char *)&timebuf, sizeof timebuf,
- "%H:%M",
- localtime(&ent_stat.st_mtime)) == 0) {
- strncpy(timebuf, "-", sizeof timebuf);
- }
- }
-
- if((path = guit->fetch->path_to_url(urlpath)) == NULL)
- continue;
+ if (err == NSERROR_OK) {
+ msg.data.header_or_data.len = strlen(buffer);
+ if (fetch_file_send_callback(&msg, ctx))
+ goto fetch_file_process_dir_aborted;
- if (S_ISREG(ent_stat.st_mode)) {
- /* regular file */
- dirlist_generate_row(even,
- false,
- path,
- ent->d_name,
- guit->fetch->filetype(urlpath),
- ent_stat.st_size,
- datebuf, timebuf,
- buffer, sizeof(buffer));
- } else if (S_ISDIR(ent_stat.st_mode)) {
- /* directory */
- dirlist_generate_row(even,
- true,
- path,
- ent->d_name,
- messages_get("FileDirectory"),
- -1,
- datebuf, timebuf,
- buffer, sizeof(buffer));
- } else {
- /* something else */
- dirlist_generate_row(even,
- false,
- path,
- ent->d_name,
- "",
- -1,
- datebuf, timebuf,
- buffer, sizeof(buffer));
+ even = !even;
}
-
- free(path);
-
- msg.data.header_or_data.len = strlen(buffer);
- if (fetch_file_send_callback(&msg, ctx))
- goto fetch_file_process_dir_aborted;
-
- even = !even;
}
/* directory listing bottom */
diff --git a/desktop/gui.h b/desktop/gui.h
index 5f4ba1cdb..0d4135a93 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -68,6 +68,7 @@ struct ssl_cert_info;
struct hlcache_handle;
struct download_context;
struct nsurl;
+struct gui_file_table;
typedef struct nsnsclipboard_styles {
size_t start; /**< Start of run */
@@ -318,28 +319,6 @@ struct gui_fetch_table {
/* Mandantory entries */
/**
- * Return the filename part of a full path
- *
- * @note used in curl fetcher
- *
- * \param path full path and filename
- * \return filename (will be freed with free())
- */
- char *(*filename_from_path)(char *path);
-
- /**
- * Add a path component/filename to an existing path
- *
- * @note used in save complete and file fetcher
- *
- * \param path buffer containing path + free space
- * \param length length of buffer "path"
- * \param newpart string containing path component to add to path
- * \return true on success
- */
- bool (*path_add_part)(char *path, int length, const char *newpart);
-
- /**
* Determine the MIME type of a local file.
*
* @note used in file fetcher
@@ -398,6 +377,7 @@ struct gui_fetch_table {
};
+
/**
* User interface utf8 characterset conversion routines.
*/
@@ -568,6 +548,15 @@ struct gui_table {
struct gui_fetch_table *fetch;
/**
+ * File table
+ *
+ * Provides file and filename operations to the core. The
+ * table is optional and may be NULL in which case the default
+ * posix compliant operations will be used.
+ */
+ struct gui_file_table *file;
+
+ /**
* UTF8 table.
*
* Provides for conversion between the gui local character
diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c
index ecedf417b..8e3ce178d 100644
--- a/desktop/gui_factory.c
+++ b/desktop/gui_factory.c
@@ -19,6 +19,7 @@
#include "content/hlcache.h"
#include "desktop/download.h"
#include "desktop/gui_factory.h"
+#include "utils/file.h"
/** The global GUI interface table */
struct gui_table *guit = NULL;
@@ -418,12 +419,6 @@ static nserror verify_fetch_register(struct gui_fetch_table *gft)
}
/* check the mandantory fields are set */
- if (gft->filename_from_path == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
- if (gft->path_add_part == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
if (gft->filetype == NULL) {
return NSERROR_BAD_PARAMETER;
}
@@ -446,6 +441,25 @@ static nserror verify_fetch_register(struct gui_fetch_table *gft)
return NSERROR_OK;
}
+/** verify file table is valid */
+static nserror verify_file_register(struct gui_file_table *gft)
+{
+ /* check table is present */
+ if (gft == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* check the mandantory fields are set */
+ if (gft->mkpath == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if (gft->basename == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ return NSERROR_OK;
+}
+
static void gui_default_quit(void)
{
}
@@ -559,6 +573,15 @@ nserror gui_factory_register(struct gui_table *gt)
return err;
}
+ /* file table */
+ if (gt->file == NULL) {
+ gt->file = default_file_table;
+ }
+ err = verify_file_register(gt->file);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
/* download table */
if (gt->download == NULL) {
/* set default download table */
diff --git a/desktop/save_complete.c b/desktop/save_complete.c
index 99b1ac4b7..782e35841 100644
--- a/desktop/save_complete.c
+++ b/desktop/save_complete.c
@@ -21,8 +21,6 @@
* Save HTML document with dependencies (implementation).
*/
-#include "utils/config.h"
-
#include <assert.h>
#include <ctype.h>
#include <errno.h>
@@ -30,21 +28,23 @@
#include <string.h>
#include <sys/types.h>
#include <regex.h>
-
#include <dom/dom.h>
-#include "content/content.h"
-#include "content/hlcache.h"
-#include "css/css.h"
-#include "desktop/save_complete.h"
-#include "desktop/gui_factory.h"
-#include "render/box.h"
-#include "render/html.h"
+#include "utils/config.h"
#include "utils/corestrings.h"
#include "utils/log.h"
#include "utils/nsurl.h"
#include "utils/utf8.h"
#include "utils/utils.h"
+#include "utils/file.h"
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "css/css.h"
+#include "render/box.h"
+#include "render/html.h"
+
+#include "desktop/gui_factory.h"
+#include "desktop/save_complete.h"
regex_t save_complete_import_re;
@@ -143,19 +143,19 @@ static bool save_complete_save_buffer(save_complete_ctx *ctx,
const char *leafname, const char *data, size_t data_len,
lwc_string *mime_type)
{
+ nserror ret;
FILE *fp;
- bool error;
- char fullpath[PATH_MAX];
+ char *fname = NULL;
- strncpy(fullpath, ctx->path, sizeof fullpath);
- error = guit->fetch->path_add_part(fullpath, sizeof fullpath, leafname);
- if (error == false) {
- warn_user("NoMemory", NULL);
+ ret = netsurf_mkpath(&fname, NULL, 2, ctx->path, leafname);
+ if (ret != NSERROR_OK) {
+ warn_user("NoMemory", 0);
return false;
}
- fp = fopen(fullpath, "wb");
+ fp = fopen(fname, "wb");
if (fp == NULL) {
+ free(fname);
LOG(("fopen(): errno = %i", errno));
warn_user("SaveError", strerror(errno));
return false;
@@ -165,8 +165,10 @@ static bool save_complete_save_buffer(save_complete_ctx *ctx,
fclose(fp);
- if (ctx->set_type != NULL)
- ctx->set_type(fullpath, mime_type);
+ if (ctx->set_type != NULL) {
+ ctx->set_type(fname, mime_type);
+ }
+ free(fname);
return true;
}
@@ -1034,29 +1036,30 @@ static bool save_complete_node_handler(dom_node *node,
static bool save_complete_save_html_document(save_complete_ctx *ctx,
hlcache_handle *c, bool index)
{
- bool error;
+ nserror ret;
FILE *fp;
+ char *fname = NULL;
dom_document *doc;
lwc_string *mime_type;
char filename[32];
- char fullpath[PATH_MAX];
- strncpy(fullpath, ctx->path, sizeof fullpath);
-
- if (index)
+ if (index) {
snprintf(filename, sizeof filename, "index");
- else
+ } else {
snprintf(filename, sizeof filename, "%p", c);
+ }
- error = guit->fetch->path_add_part(fullpath, sizeof fullpath, filename);
- if (error == false) {
+ ret = netsurf_mkpath(&fname, NULL, 2, ctx->path, filename);
+ if (ret != NSERROR_OK) {
warn_user("NoMemory", NULL);
return false;
}
- fp = fopen(fullpath, "wb");
+ fp = fopen(fname, "wb");
if (fp == NULL) {
- warn_user("NoMemory", NULL);
+ free(fname);
+ LOG(("fopen(): errno = %i", errno));
+ warn_user("SaveError", strerror(errno));
return false;
}
@@ -1068,6 +1071,7 @@ static bool save_complete_save_html_document(save_complete_ctx *ctx,
if (save_complete_libdom_treewalk((dom_node *) doc,
save_complete_node_handler, ctx) == false) {
+ free(fname);
warn_user("NoMemory", 0);
fclose(fp);
return false;
@@ -1078,10 +1082,11 @@ static bool save_complete_save_html_document(save_complete_ctx *ctx,
mime_type = content_get_mime_type(c);
if (mime_type != NULL) {
if (ctx->set_type != NULL)
- ctx->set_type(fullpath, mime_type);
+ ctx->set_type(fname, mime_type);
lwc_string_unref(mime_type);
}
+ free(fname);
return true;
}
@@ -1119,19 +1124,18 @@ static bool save_complete_save_html(save_complete_ctx *ctx, hlcache_handle *c,
static bool save_complete_inventory(save_complete_ctx *ctx)
{
+ nserror ret;
FILE *fp;
- bool error;
+ char *fname = NULL;
save_complete_entry *entry;
- char fullpath[PATH_MAX];
- strncpy(fullpath, ctx->path, sizeof fullpath);
- error = guit->fetch->path_add_part(fullpath, sizeof fullpath, "Inventory");
- if (error == false) {
- warn_user("NoMemory", NULL);
+ ret = netsurf_mkpath(&fname, NULL, 2, ctx->path, "Inventory");
+ if (ret != NSERROR_OK) {
return false;
}
- fp = fopen(fullpath, "w");
+ fp = fopen(fname, "w");
+ free(fname);
if (fp == NULL) {
LOG(("fopen(): errno = %i", errno));
warn_user("SaveError", strerror(errno));
diff --git a/framebuffer/fetch.c b/framebuffer/fetch.c
index c39ab5819..7c8dcc589 100644
--- a/framebuffer/fetch.c
+++ b/framebuffer/fetch.c
@@ -34,42 +34,6 @@
#include "framebuffer/findfile.h"
#include "framebuffer/fetch.h"
-/**
- * Return the filename part of a full path
- *
- * \param path full path and filename
- * \return filename (will be freed with free())
- */
-static char *filename_from_path(char *path)
-{
- char *leafname;
-
- leafname = strrchr(path, '/');
- if (!leafname)
- leafname = path;
- else
- leafname += 1;
-
- return strdup(leafname);
-}
-
-/**
- * Add a path component/filename to an existing path
- *
- * \param path buffer containing path + free space
- * \param length length of buffer "path"
- * \param newpart string containing path component to add to path
- * \return true on success
- */
-static bool path_add_part(char *path, int length, const char *newpart)
-{
- if(path[strlen(path) - 1] != '/')
- strncat(path, "/", length);
-
- strncat(path, newpart, length);
-
- return true;
-}
/**
* Convert a pathname to a file: URL.
@@ -183,8 +147,6 @@ static const char *fetch_filetype(const char *unix_path)
/* table for fetch operations */
static struct gui_fetch_table fetch_table = {
- .filename_from_path = filename_from_path,
- .path_add_part = path_add_part,
.filetype = fetch_filetype,
.path_to_url = path_to_url,
.url_to_path = url_to_path,
diff --git a/gtk/dialogs/preferences.c b/gtk/dialogs/preferences.c
index fcf30c8fa..d36d0c68b 100644
--- a/gtk/dialogs/preferences.c
+++ b/gtk/dialogs/preferences.c
@@ -19,12 +19,12 @@
#include <stdint.h>
#include <math.h>
-#include "utils/filepath.h"
-#include "utils/log.h"
#include "utils/utils.h"
#include "utils/messages.h"
-#include "desktop/browser.h"
#include "utils/nsoption.h"
+#include "utils/file.h"
+#include "utils/log.h"
+#include "desktop/browser.h"
#include "desktop/searchweb.h"
#include "gtk/compat.h"
@@ -1002,10 +1002,10 @@ nsgtk_preferences_fileChooserDownloads_realize(GtkWidget *widget,
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_response(GtkDialog *dlg, gint resid)
{
- char *choices;
+ char *choices = NULL;
if (resid == GTK_RESPONSE_CLOSE) {
- choices = filepath_append(nsgtk_config_home, "Choices");
+ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
if (choices != NULL) {
nsoption_write(choices, NULL, NULL);
free(choices);
@@ -1018,9 +1018,9 @@ G_MODULE_EXPORT gboolean
nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg,
struct ppref *priv)
{
- char *choices;
+ char *choices = NULL;
- choices = filepath_append(nsgtk_config_home, "Choices");
+ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
if (choices != NULL) {
nsoption_write(choices, NULL, NULL);
free(choices);
@@ -1037,9 +1037,9 @@ nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg,
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_destroy(GtkDialog *dlg, struct ppref *priv)
{
- char *choices;
+ char *choices = NULL;
- choices = filepath_append(nsgtk_config_home, "Choices");
+ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
if (choices != NULL) {
nsoption_write(choices, NULL, NULL);
free(choices);
diff --git a/gtk/fetch.c b/gtk/fetch.c
index 8db102ce8..a76ad9f4d 100644
--- a/gtk/fetch.c
+++ b/gtk/fetch.c
@@ -226,45 +226,6 @@ const char *fetch_filetype(const char *unix_path)
return type;
}
-/**
- * Return the filename part of a full path
- *
- * \param path full path and filename
- * \return filename (will be freed with free())
- */
-static char *filename_from_path(char *path)
-{
- char *leafname;
-
- leafname = strrchr(path, '/');
- if (!leafname) {
- leafname = path;
- } else {
- leafname += 1;
- }
-
- return strdup(leafname);
-}
-
-/**
- * Add a path component/filename to an existing path
- *
- * \param path buffer containing path + free space
- * \param length length of buffer "path"
- * \param newpart string containing path component to add to path
- * \return true on success
- */
-static bool path_add_part(char *path, int length, const char *newpart)
-{
- if (path[strlen(path) - 1] != '/') {
- strncat(path, "/", length);
- }
-
- strncat(path, newpart, length);
-
- return true;
-}
-
char *path_to_url(const char *path)
{
int urllen;
@@ -337,14 +298,11 @@ static nsurl *gui_get_resource_url(const char *path)
}
static struct gui_fetch_table fetch_table = {
- .filename_from_path = filename_from_path,
- .path_add_part = path_add_part,
.filetype = fetch_filetype,
.path_to_url = path_to_url,
.url_to_path = url_to_path,
.get_resource_url = gui_get_resource_url,
-
};
struct gui_fetch_table *nsgtk_fetch_table = &fetch_table;
diff --git a/gtk/gui.c b/gtk/gui.c
index 3147bf1b8..bae3568c6 100644
--- a/gtk/gui.c
+++ b/gtk/gui.c
@@ -55,6 +55,14 @@
#include "desktop/textinput.h"
#include "desktop/tree.h"
#include "css/utils.h"
+#include "render/form.h"
+#include "utils/filepath.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utf8.h"
+#include "utils/utils.h"
+#include "utils/file.h"
#include "gtk/compat.h"
#include "gtk/completion.h"
@@ -71,13 +79,6 @@
#include "gtk/selection.h"
#include "gtk/search.h"
-#include "render/form.h"
-#include "utils/filepath.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/url.h"
-#include "utils/utf8.h"
-#include "utils/utils.h"
char *toolbar_indices_file_location;
char *res_dir_location;
@@ -253,33 +254,37 @@ static nserror set_defaults(struct nsoption_s *defaults)
char *fname;
/* cookie file default */
- fname = filepath_append(nsgtk_config_home, "Cookies");
+ fname = NULL;
+ netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies");
if (fname != NULL) {
nsoption_setnull_charp(cookie_file, fname);
}
/* cookie jar default */
- fname = filepath_append(nsgtk_config_home, "Cookies");
+ fname = NULL;
+ netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies");
if (fname != NULL) {
nsoption_setnull_charp(cookie_jar, fname);
}
/* url database default */
- fname = filepath_append(nsgtk_config_home, "URLs");
+ fname = NULL;
+ netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "URLs");
if (fname != NULL) {
nsoption_setnull_charp(url_file, fname);
}
/* bookmark database default */
- fname = filepath_append(nsgtk_config_home, "Hotlist");
+ fname = NULL;
+ netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Hotlist");
if (fname != NULL) {
nsoption_setnull_charp(hotlist_path, fname);
}
/* download directory default */
- fname = filepath_append(getenv("HOME"), "");
+ fname = getenv("HOME");
if (fname != NULL) {
- nsoption_setnull_charp(downloads_directory, fname);
+ nsoption_setnull_charp(downloads_directory, strdup(fname));
}
/* default path to certificates */
@@ -955,12 +960,12 @@ static nserror
check_dirname(const char *path, const char *leaf, char **dirname_out)
{
nserror ret;
- char *dirname;
+ char *dirname = NULL;
struct stat dirname_stat;
- dirname = filepath_append(path, leaf);
- if (dirname == NULL) {
- return NSERROR_NOMEM;
+ ret = netsurf_mkpath(&dirname, NULL, 2, path, leaf);
+ if (ret != NSERROR_OK) {
+ return ret;
}
/* ensure access is possible and the entry is actualy
@@ -1075,14 +1080,14 @@ static nserror create_config_home(char **config_home_out)
return NSERROR_NOT_DIRECTORY;
}
- config_home = filepath_append(home_dir, ".config/netsurf/");
- if (config_home == NULL) {
- return NSERROR_NOMEM;
+ ret = netsurf_mkpath(&config_home, NULL, 2, home_dir, ".config/netsurf/");
+ if (ret != NSERROR_OK) {
+ return ret;
}
} else {
- config_home = filepath_append(xdg_config_dir, "netsurf/");
- if (config_home == NULL) {
- return NSERROR_NOMEM;
+ ret = netsurf_mkpath(&config_home, NULL, 2, xdg_config_dir, "netsurf/");
+ if (ret != NSERROR_OK) {
+ return ret;
}
}
@@ -1113,8 +1118,8 @@ static nserror nsgtk_option_init(int *pargc, char** argv)
}
/* Attempt to load the user choices */
- choices = filepath_append(nsgtk_config_home, "Choices");
- if (choices != NULL) {
+ ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
+ if (ret == NSERROR_OK) {
nsoption_read(choices, nsoptions);
free(choices);
}
diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c
index 436830bd3..fde195657 100644
--- a/gtk/scaffolding.c
+++ b/gtk/scaffolding.c
@@ -30,6 +30,7 @@
#include "utils/url.h"
#include "utils/log.h"
#include "utils/nsoption.h"
+#include "utils/file.h"
#include "desktop/browser_history.h"
#include "desktop/browser_private.h"
#include "desktop/hotlist.h"
@@ -72,7 +73,6 @@
#include "gtk/tabs.h"
#include "gtk/schedule.h"
-
/** Macro to define a handler for menu, button and activate events. */
#define MULTIHANDLER(q)\
static gboolean nsgtk_on_##q##_activate(struct gtk_scaffolding *g);\
@@ -867,7 +867,7 @@ MULTIHANDLER(print)
GtkPrintSettings *print_settings;
GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR;
struct print_settings *nssettings;
- char *settings_fname;
+ char *settings_fname = NULL;
print_op = gtk_print_operation_new();
if (print_op == NULL) {
@@ -876,7 +876,7 @@ MULTIHANDLER(print)
}
/* use previously saved settings if any */
- settings_fname = filepath_append(nsgtk_config_home, "Print");
+ netsurf_mkpath(&settings_fname, NULL, 2, nsgtk_config_home, "Print");
if (settings_fname != NULL) {
print_settings = gtk_print_settings_new_from_file(settings_fname, NULL);
if (print_settings != NULL) {
@@ -1260,7 +1260,7 @@ MULTIHANDLER(downloads)
MULTIHANDLER(savewindowsize)
{
int x,y,w,h;
- char *choices;
+ char *choices = NULL;
gtk_window_get_position(g->window, &x, &y);
gtk_window_get_size(g->window, &w, &h);
@@ -1270,7 +1270,7 @@ MULTIHANDLER(savewindowsize)
nsoption_set_int(window_x, x);
nsoption_set_int(window_y, y);
- choices = filepath_append(nsgtk_config_home, "Choices");
+ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
if (choices != NULL) {
nsoption_write(choices, NULL, NULL);
free(choices);
diff --git a/monkey/fetch.c b/monkey/fetch.c
index 668ad0e64..e2530e710 100644
--- a/monkey/fetch.c
+++ b/monkey/fetch.c
@@ -78,45 +78,6 @@ static char *url_to_path(const char *url)
return respath;
}
-/**
- * Return the filename part of a full path
- *
- * \param path full path and filename
- * \return filename (will be freed with free())
- */
-
-static char *filename_from_path(char *path)
-{
- char *leafname;
-
- leafname = strrchr(path, '/');
- if (!leafname)
- leafname = path;
- else
- leafname += 1;
-
- return strdup(leafname);
-}
-
-/**
- * Add a path component/filename to an existing path
- *
- * \param path buffer containing path + free space
- * \param length length of buffer "path"
- * \param newpart string containing path component to add to path
- * \return true on success
- */
-
-static bool path_add_part(char *path, int length, const char *newpart)
-{
- if(path[strlen(path) - 1] != '/')
- strncat(path, "/", length);
-
- strncat(path, newpart, length);
-
- return true;
-}
-
static nsurl *gui_get_resource_url(const char *path)
{
char buf[PATH_MAX];
@@ -133,8 +94,6 @@ static nsurl *gui_get_resource_url(const char *path)
}
static struct gui_fetch_table fetch_table = {
- .filename_from_path = filename_from_path,
- .path_add_part = path_add_part,
.filetype = monkey_fetch_filetype,
.path_to_url = path_to_url,
.url_to_path = url_to_path,
diff --git a/riscos/gui.c b/riscos/gui.c
index db57ff68a..6447e4d90 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -67,6 +67,7 @@
#include "desktop/save_complete.h"
#include "desktop/treeview.h"
#include "render/font.h"
+#include "utils/file.h"
#include "riscos/content-handlers/artworks.h"
#include "riscos/bitmap.h"
@@ -2285,77 +2286,173 @@ void PDF_Password(char **owner_pass, char **user_pass, char *path)
*owner_pass = NULL;
}
+
+#define DIR_SEP ('.')
+
/**
- * Return the filename part of a full path
+ * Generate a riscos path from one or more component elemnts.
+ *
+ * Constructs a complete path element from passed components. The
+ * second (and subsequent) components have a slash substituted for all
+ * riscos directory separators.
*
- * \param path full path and filename
- * \return filename (will be freed with free())
+ * If a string is allocated it must be freed by the caller.
+ *
+ * @param[in,out] str pointer to string pointer if this is NULL enough
+ * storage will be allocated for the complete path.
+ * @param[in,out] size The size of the space available if \a str not
+ * NULL on input and if not NULL set to the total
+ * output length on output.
+ * @param[in] nemb The number of elements.
+ * @param[in] ap The elements of the path as string pointers.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
*/
-
-static char *filename_from_path(char *path)
+static nserror riscos_mkpath(char **str, size_t *size, size_t nelm, va_list ap)
{
- char *leafname;
- char *temp;
- int leaflen;
+ const char *elm[16];
+ size_t elm_len[16];
+ size_t elm_idx;
+ char *fname;
+ size_t fname_len = 0;
+ char *curp;
+ size_t idx;
+
+ /* check the parameters are all sensible */
+ if ((nelm == 0) || (nelm > 16)) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if ((*str != NULL) && (size == NULL)) {
+ /* if the caller is providing the buffer they must say
+ * how much space is available.
+ */
+ return NSERROR_BAD_PARAMETER;
+ }
- temp = strrchr(path, '.');
- if (!temp)
- temp = path; /* already leafname */
- else
- temp += 1;
+ /* calculate how much storage we need for the complete path
+ * with all the elements.
+ */
+ for (elm_idx = 0; elm_idx < nelm; elm_idx++) {
+ elm[elm_idx] = va_arg(ap, const char *);
+ elm_len[elm_idx] = strlen(elm[elm_idx]);
+ fname_len += elm_len[elm_idx];
+ }
+ fname_len += nelm; /* allow for separators and terminator */
+
+ /* ensure there is enough space */
+ fname = *str;
+ if (fname != NULL) {
+ if (fname_len > *size) {
+ return NSERROR_NOSPACE;
+ }
+ } else {
+ fname = malloc(fname_len);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+ }
- leaflen = strlen(temp);
+ /* copy the elements in with directory separator */
+ curp = fname;
- leafname = malloc(leaflen + 1);
- if (!leafname) {
- LOG(("malloc failed"));
- return NULL;
+ /* first element is not altered */
+ memmove(curp, elm[elm_idx], elm_len[elm_idx]);
+ curp += elm_len[elm_idx];
+ /* ensure there is a delimiter */
+ if (curp[-1] != DIR_SEP) {
+ *curp = DIR_SEP;
+ curp++;
}
- memcpy(leafname, temp, leaflen + 1);
- /* and s/\//\./g */
- for (temp = leafname; *temp; temp++)
- if (*temp == '/')
- *temp = '.';
+ /* subsequent elemnts have slashes substituted with directory
+ * separators.
+ */
+ for (elm_idx = 1; elm_idx < nelm; elm_idx++) {
+ for (idx = 0; idx < elm_len[elm_idx]; idx++) {
+ if (elm[elm_idx][idx] == DIR_SEP) {
+ *curp = '/';
+ } else {
+ *curp = elm[elm_idx][idx];
+ }
+ curp++;
+ }
+ *curp = DIR_SEP;
+ curp++;
+ }
+ curp[-1] = 0; /* NULL terminate */
+
+ assert((curp - fname) <= (int)fname_len);
+
+ *str = fname;
+ if (size != NULL) {
+ *size = fname_len;
+ }
+
+ return NSERROR_OK;
- return leafname;
}
+
/**
- * Add a path component/filename to an existing path
+ * Get the basename of a file using posix path handling.
+ *
+ * This gets the last element of a path and returns it. The returned
+ * element has all forward slashes translated into riscos directory
+ * separators.
*
- * \param path buffer containing platform-native format path + free space
- * \param length length of buffer "path"
- * \param newpart string containing unix-format path component to add to path
- * \return true on success
+ * @param[in] path The path to extract the name from.
+ * @param[in,out] str Pointer to string pointer if this is NULL enough
+ * storage will be allocated for the path element.
+ * @param[in,out] size The size of the space available if \a
+ * str not NULL on input and set to the total
+ * output length on output.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
*/
-
-static bool path_add_part(char *path, int length, const char *newpart)
+static nserror riscos_basename(const char *path, char **str, size_t *size)
{
- size_t path_len = strlen(path);
+ const char *leafname;
+ char *fname;
+ char *temp;
- /* Append directory separator, if there isn't one */
- if (path[path_len - 1] != '.') {
- strncat(path, ".", length);
- path_len += 1;
+ if (path == NULL) {
+ return NSERROR_BAD_PARAMETER;
}
- strncat(path, newpart, length);
+ leafname = strrchr(path, DIR_SEP);
+ if (!leafname) {
+ leafname = path;
+ } else {
+ leafname += 1;
+ }
- /* Newpart is either a directory name, or a file leafname
- * Either way, we must replace all dots with forward slashes */
- for (path = path + path_len; *path; path++) {
- if (*path == '.')
- *path = '/';
+ fname = strdup(leafname);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
}
- return true;
+ /** @todo check this leafname translation is actually required */
+ /* and s/\//\./g */
+ for (temp = fname; *temp != 0; temp++) {
+ if (*temp == '/') {
+ *temp = DIR_SEP;
+ }
+ }
+
+ *str = fname;
+ if (size != NULL) {
+ *size = strlen(fname);
+ }
+ return NSERROR_OK;
}
+static struct gui_file_table riscos_file_table = {
+ .mkpath = riscos_mkpath,
+ .basename = riscos_basename,
+};
+
static struct gui_fetch_table riscos_fetch_table = {
- .filename_from_path = filename_from_path,
- .path_add_part = path_add_part,
.filetype = fetch_filetype,
.path_to_url = path_to_url,
.url_to_path = url_to_path,
@@ -2392,6 +2489,7 @@ int main(int argc, char** argv)
.clipboard = riscos_clipboard_table,
.download = riscos_download_table,
.fetch = &riscos_fetch_table,
+ .file = &riscos_file_table,
.utf8 = riscos_utf8_table,
.search = riscos_search_table,
};
diff --git a/utils/Makefile b/utils/Makefile
index aef579948..c808b91ba 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -2,6 +2,6 @@
S_UTILS := base64.c corestrings.c filename.c filepath.c hashtable.c \
libdom.c locale.c log.c messages.c nsurl.c talloc.c url.c \
- utf8.c utils.c useragent.c bloom.c nsoption.c
+ utf8.c utils.c useragent.c bloom.c nsoption.c file.c
S_UTILS := $(addprefix utils/,$(S_UTILS))
diff --git a/utils/file.c b/utils/file.c
new file mode 100644
index 000000000..7b0a4677a
--- /dev/null
+++ b/utils/file.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2014 vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Table operations for files with posix compliant path separator.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "desktop/gui_factory.h"
+#include "utils/utils.h"
+
+#include "utils/file.h"
+
+/**
+ * Generate a posix path from one or more component elemnts.
+ *
+ * If a string is allocated it must be freed by the caller.
+ *
+ * @param[in,out] str pointer to string pointer if this is NULL enough
+ * storage will be allocated for the complete path.
+ * @param[in,out] size The size of the space available if \a str not
+ * NULL on input and if not NULL set to the total
+ * output length on output.
+ * @param[in] nemb The number of elements.
+ * @param[in] ... The elements of the path as string pointers.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
+ */
+static nserror posix_mkpath(char **str, size_t *size, size_t nelm, va_list ap)
+{
+ return vsnstrjoin(str, size, '/', nelm, ap);
+}
+
+/**
+ * Get the basename of a file using posix path handling.
+ *
+ * This gets the last element of a path and returns it.
+ *
+ * @param[in] path The path to extract the name from.
+ * @param[in,out] str Pointer to string pointer if this is NULL enough
+ * storage will be allocated for the path element.
+ * @param[in,out] size The size of the space available if \a
+ * str not NULL on input and set to the total
+ * output length on output.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
+ */
+static nserror posix_basename(const char *path, char **str, size_t *size)
+{
+ const char *leafname;
+ char *fname;
+
+ if (path == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ leafname = strrchr(path, '/');
+ if (!leafname) {
+ leafname = path;
+ } else {
+ leafname += 1;
+ }
+
+ fname = strdup(leafname);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ *str = fname;
+ if (size != NULL) {
+ *size = strlen(fname);
+ }
+ return NSERROR_OK;
+}
+
+/* exported interface documented in utils/file.h */
+nserror netsurf_mkpath(char **str, size_t *size, size_t nelm, ...)
+{
+ va_list ap;
+ nserror ret;
+
+ va_start(ap, nelm);
+ if (guit != NULL) {
+ ret = guit->file->mkpath(str, size, nelm, ap);
+ } else {
+ /* default to posix */
+ ret = vsnstrjoin(str, size, '/', nelm, ap);
+ }
+ va_end(ap);
+
+ return ret;
+}
+
+/* default to using the posix file handling */
+static struct gui_file_table file_table = {
+ .mkpath = posix_mkpath,
+ .basename = posix_basename,
+};
+
+struct gui_file_table *default_file_table = &file_table;
diff --git a/utils/file.h b/utils/file.h
new file mode 100644
index 000000000..f183337c5
--- /dev/null
+++ b/utils/file.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Default operations table for files.
+ */
+
+#ifndef NETSURF_UTILS_FILE_H
+#define NETSURF_UTILS_FILE_H
+
+#include <stdarg.h>
+
+/**
+ * function table for file and filename operations.
+ *
+ * function table implementing GUI interface to file and filename
+ * functionality appropriate for the OS.
+ */
+struct gui_file_table {
+ /* Mandantory entries */
+
+ /**
+ * Generate a path from one or more component elemnts.
+ *
+ * If a string is allocated it must be freed by the caller.
+ *
+ * @param[in,out] str pointer to string pointer if this is NULL enough
+ * storage will be allocated for the complete path.
+ * @param[in,out] size The size of the space available if \a str not
+ * NULL on input and if not NULL set to the total
+ * output length on output.
+ * @param[in] nemb The number of elements.
+ * @param[in] ... The elements of the path as string pointers.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
+ */
+ nserror (*mkpath)(char **str, size_t *size, size_t nemb, va_list ap);
+
+ /**
+ * Get the basename of a file.
+ *
+ * This gets the last element of a path and returns it.
+ *
+ * @param[in] path The path to extract the name from.
+ * @param[in,out] str Pointer to string pointer if this is NULL enough
+ * storage will be allocated for the path element.
+ * @param[in,out] size The size of the space available if \a
+ * str not NULL on input and set to the total
+ * output length on output.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
+ */
+ nserror (*basename)(const char *path, char **str, size_t *size);
+};
+
+/** Default (posix) file operation table. */
+struct gui_file_table *default_file_table;
+
+/**
+ * Generate a path from one or more component elemnts.
+ *
+ * If a string is allocated it must be freed by the caller.
+ *
+ * @warning If this is called before the gui operation tables are
+ * initialised the behaviour defaults to posix paths. Ensure this is
+ * the required behaviour.
+ *
+ * @param[in,out] str pointer to string pointer if this is NULL enough
+ * storage will be allocated for the complete path.
+ * @param[in,out] size The size of the space available if \a str not
+ * NULL on input and if not NULL set to the total
+ * output length on output.
+ * @param[in] nemb The number of elements.
+ * @param[in] ... The elements of the path as string pointers.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
+ */
+nserror netsurf_mkpath(char **str, size_t *size, size_t nelm, ...);
+
+#endif
diff --git a/utils/filepath.c b/utils/filepath.c
index 68e8d7e79..c28a821d7 100644
--- a/utils/filepath.c
+++ b/utils/filepath.c
@@ -326,25 +326,6 @@ void filepath_free_strvec(char **pathv)
}
/* exported interface documented in filepath.h */
-char *filepath_append(const char *path, const char *leaf)
-{
- int dirname_len;
- char *dirname;
-
- if ((path == NULL) || (leaf == NULL)) {
- return NULL;
- }
-
- dirname_len = strlen(path) + strlen(leaf) + 2;
- dirname = malloc(dirname_len);
- if (dirname != NULL) {
- snprintf(dirname, dirname_len, "%s/%s", path, leaf);
- }
-
- return dirname;
-}
-
-/* exported interface documented in filepath.h */
nserror filepath_mkdir_all(const char *fname)
{
char *dname;
diff --git a/utils/filepath.h b/utils/filepath.h
index 56e9eff74..61b7209cc 100644
--- a/utils/filepath.h
+++ b/utils/filepath.h
@@ -128,17 +128,6 @@ void filepath_free_strvec(char **pathv);
/**
- * generate a new filename from a path and leaf.
- *
- * @param path The base path.
- * @param leaf The leaf to add.
- * @return The combined path in a new string must be freed by caller
- * or NULL on failiure to allocte memory.
- */
-char *filepath_append(const char *path, const char *leaf);
-
-
-/**
* Ensure that all directory elements needed to store a filename exist.
*
* @param fname The filename to ensure the path to exists.
diff --git a/windows/gui.c b/windows/gui.c
index 0af54ee62..0be75e1e8 100644
--- a/windows/gui.c
+++ b/windows/gui.c
@@ -43,6 +43,7 @@
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utils.h"
+#include "utils/file.h"
#include "windows/window.h"
#include "windows/about.h"
@@ -1808,42 +1809,75 @@ nsws_create_main_class(HINSTANCE hinstance) {
}
/**
- * Return the filename part of a full path
+ * Generate a windows path from one or more component elemnts.
*
- * \param path full path and filename
- * \return filename (will be freed with free())
+ * If a string is allocated it must be freed by the caller.
+ *
+ * @param[in,out] str pointer to string pointer if this is NULL enough
+ * storage will be allocated for the complete path.
+ * @param[in,out] size The size of the space available if \a str not
+ * NULL on input and if not NULL set to the total
+ * output length on output.
+ * @param[in] nemb The number of elements.
+ * @param[in] ... The elements of the path as string pointers.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
*/
-static char *filename_from_path(char *path)
+static nserror windows_mkpath(char **str, size_t *size, size_t nelm, va_list ap)
{
- char *leafname;
-
- leafname = strrchr(path, '\\');
- if (!leafname)
- leafname = path;
- else
- leafname += 1;
-
- return strdup(leafname);
+ return vsnstrjoin(str, size, '\\', nelm, ap);
}
/**
- * Add a path component/filename to an existing path
+ * Get the basename of a file using windows path handling.
+ *
+ * This gets the last element of a path and returns it.
*
- * \param path buffer containing path + free space
- * \param length length of buffer "path"
- * \param newpart string containing path component to add to path
- * \return true on success
+ * @param[in] path The path to extract the name from.
+ * @param[in,out] str Pointer to string pointer if this is NULL enough
+ * storage will be allocated for the path element.
+ * @param[in,out] size The size of the space available if \a
+ * str not NULL on input and set to the total
+ * output length on output.
+ * @return NSERROR_OK and the complete path is written to str
+ * or error code on faliure.
*/
-static bool path_add_part(char *path, int length, const char *newpart)
+static nserror windows_basename(const char *path, char **str, size_t *size)
{
- if(path[strlen(path) - 1] != '\\')
- strncat(path, "\\", length);
+ const char *leafname;
+ char *fname;
- strncat(path, newpart, length);
+ if (path == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
- return true;
+ leafname = strrchr(path, '\\');
+ if (!leafname) {
+ leafname = path;
+ } else {
+ leafname += 1;
+ }
+
+ fname = strdup(leafname);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ *str = fname;
+ if (size != NULL) {
+ *size = strlen(fname);
+ }
+ return NSERROR_OK;
}
+/* default to using the posix file handling */
+static struct gui_file_table file_table = {
+ .mkpath = windows_mkpath,
+ .basename = windows_basename,
+};
+
+struct gui_file_table *win32_file_table = &file_table;
+
static struct gui_window_table window_table = {
.create = gui_window_create,
.destroy = gui_window_destroy,
@@ -1876,8 +1910,6 @@ struct gui_clipboard_table *win32_clipboard_table = &clipboard_table;
static struct gui_fetch_table fetch_table = {
- .filename_from_path = filename_from_path,
- .path_add_part = path_add_part,
.filetype = fetch_filetype,
.path_to_url = path_to_url,
.url_to_path = url_to_path,
diff --git a/windows/gui.h b/windows/gui.h
index d8e1b1d0b..82ae83642 100644
--- a/windows/gui.h
+++ b/windows/gui.h
@@ -24,6 +24,7 @@
#include "desktop/gui.h"
#include "windows/localhistory.h"
+struct gui_file_table *win32_file_table;
extern struct gui_window_table *win32_window_table;
extern struct gui_clipboard_table *win32_clipboard_table;
extern struct gui_fetch_table *win32_fetch_table;
diff --git a/windows/main.c b/windows/main.c
index 19cd44a43..22cb5207c 100644
--- a/windows/main.c
+++ b/windows/main.c
@@ -111,6 +111,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
.clipboard = win32_clipboard_table,
.download = win32_download_table,
.fetch = win32_fetch_table,
+ .file = win32_file_table,
.utf8 = win32_utf8_table,
};
win32_fetch_table->get_resource_url = gui_get_resource_url;