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.
This commit is contained in:
Vincent Sanders 2014-05-07 16:14:18 +01:00
parent c1e2da80df
commit c56642819e
26 changed files with 790 additions and 556 deletions

View File

@ -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
*
* \param path full path and filename
* \return filename (will be freed with free())
*/
static char *filename_from_path(char *path)
/**
* 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 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.
*
* \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
* 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 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,
};

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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;
err = process_dir_ent(ctx, listing[i], even, buffer,
sizeof(buffer));
strncpy(urlpath, ctx->path, sizeof urlpath);
if (guit->fetch->path_add_part(urlpath, sizeof urlpath,
ent->d_name) == false)
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 (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);
}
/* Get time in output format */
if (strftime((char *)&timebuf, sizeof timebuf,
"%H:%M",
localtime(&ent_stat.st_mtime)) == 0) {
strncpy(timebuf, "-", sizeof timebuf);
}
even = !even;
}
if((path = guit->fetch->path_to_url(urlpath)) == NULL)
continue;
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));
}
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 */

View File

@ -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 */
@ -317,28 +318,6 @@ struct gui_clipboard_table {
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.
*
@ -398,6 +377,7 @@ struct gui_fetch_table {
};
/**
* User interface utf8 characterset conversion routines.
*/
@ -567,6 +547,15 @@ struct gui_table {
/** Fetcher 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.
*

View File

@ -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 */

View File

@ -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));

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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,

View File

@ -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;
}
/**
* 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)
#define DIR_SEP ('.')
/**
* 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.
*
* 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 nserror riscos_mkpath(char **str, size_t *size, size_t nelm, va_list ap)
{
char *leafname;
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;
}
/* 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 elements in with directory separator */
curp = fname;
/* 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++;
}
/* 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;
}
/**
* 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[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 riscos_basename(const char *path, char **str, size_t *size)
{
const char *leafname;
char *fname;
char *temp;
int leaflen;
temp = strrchr(path, '.');
if (!temp)
temp = path; /* already leafname */
else
temp += 1;
if (path == NULL) {
return NSERROR_BAD_PARAMETER;
}
leaflen = strlen(temp);
leafname = malloc(leaflen + 1);
leafname = strrchr(path, DIR_SEP);
if (!leafname) {
LOG(("malloc failed"));
return NULL;
leafname = path;
} else {
leafname += 1;
}
memcpy(leafname, temp, leaflen + 1);
fname = strdup(leafname);
if (fname == NULL) {
return NSERROR_NOMEM;
}
/** @todo check this leafname translation is actually required */
/* and s/\//\./g */
for (temp = leafname; *temp; temp++)
if (*temp == '/')
*temp = '.';
return leafname;
}
/**
* Add a path component/filename to an existing path
*
* \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
*/
static bool path_add_part(char *path, int length, const char *newpart)
{
size_t path_len = strlen(path);
/* Append directory separator, if there isn't one */
if (path[path_len - 1] != '.') {
strncat(path, ".", length);
path_len += 1;
for (temp = fname; *temp != 0; temp++) {
if (*temp == '/') {
*temp = DIR_SEP;
}
}
strncat(path, newpart, length);
/* 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 = '/';
*str = fname;
if (size != NULL) {
*size = strlen(fname);
}
return true;
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,
};

View File

@ -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))

117
utils/file.c Normal file
View File

@ -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;

95
utils/file.h Normal file
View File

@ -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

View File

@ -325,25 +325,6 @@ void filepath_free_strvec(char **pathv)
free(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)
{

View File

@ -127,17 +127,6 @@ char **filepath_path_to_strvec(const char *path);
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.
*

View File

@ -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.
*
* \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
* 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 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,

View File

@ -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;

View File

@ -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;