summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;