Rewrite several file path routines to use boost::filesystem

This is a basis for moving .gnucash to a more modern location for
application specific user data (following the xdg spec).
This commit is contained in:
Geert Janssens 2017-08-22 16:33:34 +02:00
parent 2006155985
commit ae75bc963f
26 changed files with 437 additions and 227 deletions

View File

@ -438,7 +438,7 @@ SET (Boost_FIND_QUIETLY ON)
IF (NOT DEFINED ${BOOST_ROOT})
SET(BOOST_ROOT $ENV{BOOST_ROOT})
ENDIF()
FIND_PACKAGE (Boost 1.54.0 REQUIRED COMPONENTS date_time regex locale)
FIND_PACKAGE (Boost 1.54.0 REQUIRED COMPONENTS date_time regex locale filesystem)
IF (Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})

View File

@ -430,7 +430,7 @@ show_session_error (QofBackendError io_error,
fmt = _("You attempted to save in\n%s\nor a subdirectory thereof. "
"This is not allowed as %s reserves that directory for internal use.\n\n"
"Please try again in a different directory.");
gnc_error_dialog (parent, fmt, gnc_dotgnucash_dir(), PACKAGE_NAME);
gnc_error_dialog (parent, fmt, gnc_userdata_dir(), PACKAGE_NAME);
break;
case ERR_SQL_DB_TOO_OLD:
@ -1139,7 +1139,7 @@ check_file_path (const char *path)
{
/* Remember the directory as the default. */
gchar *dir = g_path_get_dirname(path);
const gchar *dotgnucash = gnc_dotgnucash_dir();
const gchar *dotgnucash = gnc_userdata_dir();
char *dirpath = dir;
/* Prevent user from storing file in GnuCash' private configuration

View File

@ -719,7 +719,7 @@ gnc_gui_init(void)
gnc_window_set_progressbar_window (GNC_WINDOW(main_window));
#ifdef MAC_INTEGRATION
map = gnc_build_dotgnucash_path(ACCEL_MAP_NAME);
map = gnc_build_userdata_path(ACCEL_MAP_NAME);
if (!g_file_test (map, G_FILE_TEST_EXISTS))
{
g_free (map);
@ -728,7 +728,7 @@ gnc_gui_init(void)
g_free(data_dir);
}
#else
map = gnc_build_dotgnucash_path(ACCEL_MAP_NAME);
map = gnc_build_userdata_path(ACCEL_MAP_NAME);
#endif /* MAC_INTEGRATION */
gtk_accel_map_load(map);
g_free(map);
@ -765,7 +765,7 @@ gnc_gui_shutdown (void)
if (gnome_is_running && !gnome_is_terminating)
{
gnome_is_terminating = TRUE;
map = gnc_build_dotgnucash_path(ACCEL_MAP_NAME);
map = gnc_build_userdata_path(ACCEL_MAP_NAME);
gtk_accel_map_save(map);
g_free(map);
gtk_main_quit();

View File

@ -799,7 +799,7 @@ pcd_save_custom_data(PrintCheckDialog *pcd, const gchar *title)
pcd->splits_account_x, pcd->splits_account_y);
filename = g_strconcat(title, CHECK_NAME_EXTENSION, NULL);
pathname = g_build_filename(gnc_dotgnucash_dir(), CHECK_FMT_DIR,
pathname = g_build_filename(gnc_userdata_dir(), CHECK_FMT_DIR,
filename, NULL);
if (gnc_key_file_save_to_file(pathname, key_file, &error))
@ -1558,7 +1558,7 @@ read_formats(PrintCheckDialog *pcd, GtkListStore *store)
g_free(dirname);
g_free(pkgdatadir);
dirname = gnc_build_dotgnucash_path(CHECK_FMT_DIR);
dirname = gnc_build_userdata_path(CHECK_FMT_DIR);
/* Translators: This is a directory name. It may be presented to
* the user to indicate that some data file was defined by a
* user herself. */
@ -1901,7 +1901,7 @@ read_image (const gchar *filename)
if (!g_file_test(tmp_name, G_FILE_TEST_EXISTS))
{
g_free(tmp_name);
dirname = gnc_build_dotgnucash_path(CHECK_FMT_DIR);
dirname = gnc_build_userdata_path(CHECK_FMT_DIR);
tmp_name = g_build_filename(dirname, filename, (char *)NULL);
g_free(dirname);
}

View File

@ -344,7 +344,7 @@ try_load_config_array(const gchar *fns[])
for (i = 0; fns[i]; i++)
{
filename = gnc_build_dotgnucash_path(fns[i]);
filename = gnc_build_userdata_path(fns[i]);
if (gfec_try_load(filename))
{
g_free(filename);
@ -703,7 +703,7 @@ gnc_log_init()
{
gchar *log_config_filename;
log_config_filename = gnc_build_dotgnucash_path("log.conf");
log_config_filename = gnc_build_userdata_path("log.conf");
if (g_file_test(log_config_filename, G_FILE_TEST_EXISTS))
qof_log_parse_log_config(log_config_filename);
g_free(log_config_filename);

View File

@ -91,7 +91,7 @@
(false-if-exception
(read)))
(let* ((pref-filename (gnc-build-dotgnucash-path "qif-accounts-map"))
(let* ((pref-filename (gnc-build-userdata-path "qif-accounts-map"))
(results '()))
;; Get the user's saved mappings.
@ -293,7 +293,7 @@
;; This procedure does all the work. We'll define it, then call it safely.
(define (private-save)
(with-output-to-file (gnc-build-dotgnucash-path "qif-accounts-map")
(with-output-to-file (gnc-build-userdata-path "qif-accounts-map")
(lambda ()
(display ";;; qif-accounts-map")
(newline)

View File

@ -1116,7 +1116,7 @@ gnc_plugin_page_report_constr_init(GncPluginPageReport *plugin_page, gint report
GncPluginPage *parent;
gboolean use_new;
gchar *name;
gchar *saved_reports_path = gnc_build_dotgnucash_path (SAVED_REPORTS_FILE);
gchar *saved_reports_path = gnc_build_userdata_path (SAVED_REPORTS_FILE);
gchar *report_save_str = g_strdup_printf (
_("Update the current report's saved configuration. "
"The report will be saved in the file %s. "), saved_reports_path);

View File

@ -82,7 +82,7 @@
;; Then look in Gnucash's standard report directory.
;; If no file is found, returns just 'fname' for use in error messages.
;; Note: this has been tested on Linux and Windows Vista so far...
(let* ((userpath (gnc-build-dotgnucash-path fname))
(let* ((userpath (gnc-build-userdata-path fname))
(syspath (gnc-build-report-path fname)))
; make sure there's a trailing delimiter
(if (access? userpath R_OK)

View File

@ -279,8 +279,8 @@ gnc_saved_reports_write_internal (const gchar *file, const gchar *contents, gboo
gboolean gnc_saved_reports_backup (void)
{
gboolean success = FALSE;
gchar *saved_rpts_path = gnc_build_dotgnucash_path (SAVED_REPORTS_FILE);
gchar *saved_rpts_bkp_path = g_strconcat (saved_rpts_path, "-backup", NULL);
gchar *saved_rpts_path = gnc_build_userdata_path (SAVED_REPORTS_FILE);
gchar *saved_rpts_bkp_path = gnc_build_userdata_path (SAVED_REPORTS_FILE "-backup");
gchar *contents = NULL;
GError *save_error = NULL;
@ -310,7 +310,7 @@ gboolean
gnc_saved_reports_write_to_file (const gchar* report_def, gboolean overwrite)
{
gboolean success = FALSE;
gchar *saved_rpts_path = gnc_build_dotgnucash_path (SAVED_REPORTS_FILE);
gchar *saved_rpts_path = gnc_build_userdata_path (SAVED_REPORTS_FILE);
if (report_def)
{

View File

@ -127,7 +127,7 @@
(record-accessor <html-style-sheet> 'style))
(define gnc:current-saved-stylesheets
(gnc-build-dotgnucash-path "stylesheets-2.0"))
(gnc-build-userdata-path "stylesheets-2.0"))
(define (gnc:save-style-sheet-options)
(let ((port (false-if-exception

View File

@ -30,7 +30,6 @@
(use-modules (gnucash report report-system))
(use-modules (gnucash app-utils))
(use-modules (gnucash engine))
(use-modules (sw_engine))
(use-modules (gnucash report report-system collectors))
(use-modules (gnucash report report-system list-extras))

View File

@ -228,7 +228,7 @@ error_handler(const char *msg)
}
gboolean
gfec_try_load(gchar *fn)
gfec_try_load(const gchar *fn)
{
g_debug("looking for %s", fn);
if (g_file_test(fn, G_FILE_TEST_EXISTS))

View File

@ -18,6 +18,6 @@ typedef void (*gfec_error_handler)(const char *error_message);
SCM gfec_eval_file(const char *file, gfec_error_handler error_handler);
SCM gfec_eval_string(const char *str, gfec_error_handler error_handler);
SCM gfec_apply(SCM proc, SCM arglist, gfec_error_handler error_handler);
gboolean gfec_try_load(gchar *fn);
gboolean gfec_try_load(const gchar *fn);
#endif

View File

@ -61,7 +61,7 @@ static gboolean parser_inited = FALSE;
static gchar *
gnc_exp_parser_filname (void)
{
return gnc_build_dotgnucash_path("expressions-2.0");
return gnc_build_userdata_path("expressions-2.0");
}
void

View File

@ -16,7 +16,7 @@ SET (core_utils_SOURCES
binreloc.c
gnc-prefs.c
gnc-environment.c
gnc-filepath-utils.c
gnc-filepath-utils.cpp
gnc-gkeyfile-utils.c
gnc-glib-utils.c
gnc-guile-utils.c
@ -117,7 +117,7 @@ SET(core_utils_noinst_HEADERS
)
SET(core_utils_ALL_SOURCES ${core_utils_SOURCES} ${core_utils_noinst_HEADERS})
SET(core_utils_ALL_LIBRARIES ${GUILE_LDFLAGS} ${GLIB2_LDFLAGS} ${GOBJECT_LDFLAGS} ${GTK_MAC_LDFLAGS})
SET(core_utils_ALL_LIBRARIES ${Boost_LIBRARIES} -lboost_filesystem ${GUILE_LDFLAGS} ${GLIB2_LDFLAGS} ${GOBJECT_LDFLAGS} ${GTK_MAC_LDFLAGS})
SET(core_utils_ALL_INCLUDES
${CMAKE_SOURCE_DIR}/common
${CMAKE_BINARY_DIR}/common

View File

@ -8,7 +8,7 @@ libgnc_core_utils_la_SOURCES = \
binreloc.c \
gnc-prefs.c \
gnc-environment.c \
gnc-filepath-utils.c \
gnc-filepath-utils.cpp \
gnc-gkeyfile-utils.c \
gnc-glib-utils.c \
gnc-guile-utils.c \
@ -21,7 +21,8 @@ libgnc_core_utils_la_LIBADD = \
${GUILE_LIBS} \
${GLIB_LIBS} \
${BINRELOC_LIBS} \
${GTK_MAC_LIBS}
${GTK_MAC_LIBS} \
${BOOST_LDFLAGS} -lboost_filesystem
noinst_HEADERS = \
@ -58,7 +59,8 @@ AM_CPPFLAGS = \
${GLIB_CFLAGS} \
${GTK_MAC_CFLAGS} \
-I${top_builddir}/common \
-I${top_srcdir}/common
-I${top_srcdir}/common \
$(BOOST_CPPFLAGS)
gncscmmoddir = ${GNC_SCM_INSTALL_DIR}/gnucash
gncscmmod_DATA = core-utils.scm

View File

@ -65,8 +65,8 @@ gchar * gnc_path_get_stdreportsdir(void);
%newobject gnc_path_find_localized_html_file;
gchar * gnc_path_find_localized_html_file(const gchar *);
%newobject gnc_build_dotgnucash_path;
gchar * gnc_build_dotgnucash_path(const gchar *);
%newobject gnc_build_userdata_path;
gchar * gnc_build_userdata_path(const gchar *);
gchar * gnc_build_report_path(const gchar *);
gchar * gnc_build_stdreports_path(const gchar *);

View File

@ -41,7 +41,7 @@
(re-export gnc-path-get-bindir)
(re-export gnc-path-get-stdreportsdir)
(re-export gnc-path-find-localized-html-file)
(re-export gnc-build-dotgnucash-path)
(re-export gnc-build-userdata-path)
(re-export gnc-build-report-path)
(re-export gnc-build-stdreports-path)
(re-export gnc-utf8?)

View File

@ -26,6 +26,7 @@
* @author Copyright (c) 2000 Dave Peticolas
*/
extern "C" {
#include "config.h"
#include <platform.h>
@ -55,6 +56,12 @@
#include <glib/gwin32.h>
#define PATH_MAX MAXPATHLEN
#endif
}
#include <boost/filesystem.hpp>
namespace bfs = boost::filesystem;
namespace bst = boost::system;
/**
* Scrubs a filename by changing "strange" chars (e.g. those that are not
@ -164,7 +171,7 @@ gnc_resolve_file_path (const gchar * filefrag)
return fullpath;
/* Look in the users config dir (e.g. $HOME/.gnucash/data) */
fullpath = gnc_build_data_path(filefrag);
fullpath = g_strdup(gnc_build_data_path(filefrag));
if (g_file_test(fullpath, G_FILE_TEST_IS_REGULAR))
return fullpath;
@ -196,7 +203,7 @@ gnc_path_find_localized_html_file_internal (const gchar * file_name)
const gchar *env_doc_path = g_getenv("GNC_DOC_PATH");
const gchar *default_dirs[] =
{
gnc_build_dotgnucash_path ("html"),
gnc_build_userdata_path ("html"),
gnc_path_get_pkgdocdir (),
gnc_path_get_pkgdatadir (),
NULL
@ -292,190 +299,156 @@ gnc_path_find_localized_html_file (const gchar *file_name)
}
/* ====================================================================== */
/** @brief Check that the supplied directory path exists, is a directory, and
* that the user has adequate permissions to use it.
*
* @param dirname The path to check
*/
static gboolean
gnc_validate_directory (const gchar *dirname, gboolean create, gchar **msg)
static bool
gnc_validate_directory (const bfs::path &dirname, bool create)
{
GStatBuf statbuf;
gint rc;
if (dirname.empty())
return false;
*msg = NULL;
rc = g_stat (dirname, &statbuf);
if (rc)
{
switch (errno)
{
case ENOENT:
if (create)
{
rc = g_mkdir (dirname,
#ifdef G_OS_WIN32
0 /* The mode argument is ignored on windows */
#else
S_IRWXU /* perms = S_IRWXU = 0700 */
#endif
);
if (rc)
{
*msg = g_strdup_printf(
_("An error occurred while creating the directory:\n"
" %s\n"
"Please correct the problem and restart GnuCash.\n"
"The reported error was '%s' (errno %d).\n"),
dirname, g_strerror(errno) ? g_strerror(errno) : "", errno);
return FALSE;
if (!bfs::exists(dirname) && (!create))
return false;
/* Optionally create directories if they don't exist yet
* Note this will do nothing if the directory and its
* parents already exist, but will fail if the path
* points to a file or a softlink. So it serves as a test
* for that as well.
*/
bfs::create_directories(dirname);
auto d = bfs::directory_entry (dirname);
auto perms = d.status().permissions();
/* On Windows only write permission will be checked.
* So strictly speaking we'd need two error messages here depending
* on the platform. For simplicity this detail is glossed over though. */
if ((perms & bfs::owner_all) != bfs::owner_all)
throw (bfs::filesystem_error(
std::string(_("Insufficient permissions, at least write and access permissions required: "))
+ dirname.c_str(), dirname,
bst::error_code(bst::errc::permission_denied, bst::generic_category())));
return true;
}
}
else
static auto usr_conf_dir = bfs::path();
static void
gnc_filepath_init()
{
*msg = g_strdup_printf(
_("Note: the directory\n"
" %s\n"
"doesn't exist. This is however not fatal.\n"),
dirname);
return FALSE;
auto try_home_dir = true;
auto env_var = g_getenv("GNC_DOT_DIR");
if (env_var)
usr_conf_dir = env_var;
if (!usr_conf_dir.empty())
{
try
{
gnc_validate_directory(usr_conf_dir, true);
try_home_dir = false;
}
g_stat (dirname, &statbuf);
break;
case EACCES:
*msg = g_strdup_printf(
_("The directory\n"
" %s\n"
"exists but cannot be accessed. This program \n"
"must have full access (read/write/execute) to \n"
"the directory in order to function properly.\n"),
dirname);
return FALSE;
case ENOTDIR:
*msg = g_strdup_printf(
_("The path\n"
" %s\n"
"exists but it is not a directory. Please delete\n"
"the file and start GnuCash again.\n"),
dirname);
return FALSE;
default:
*msg = g_strdup_printf(
_("An unknown error occurred when validating that the\n"
" %s\n"
"directory exists and is usable. Please correct the\n"
"problem and restart GnuCash. The reported error \n"
"was '%s' (errno %d)."),
dirname, g_strerror(errno) ? g_strerror(errno) : "", errno);
return FALSE;
catch (const bfs::filesystem_error& ex)
{
g_warning("%s is not a suitable base directory for the user configuration."
"Trying home directory instead.\nThe failure is\n%s",
usr_conf_dir.c_str(), ex.what());
}
}
if ((statbuf.st_mode & S_IFDIR) != S_IFDIR)
if (try_home_dir)
{
*msg = g_strdup_printf(
_("The path\n"
" %s\n"
"exists but it is not a directory. Please delete\n"
"the file and start GnuCash again.\n"),
dirname);
return FALSE;
}
#ifndef G_OS_WIN32
/* The mode argument is ignored on windows anyway */
if ((statbuf.st_mode & S_IRWXU) != S_IRWXU)
usr_conf_dir = g_get_home_dir();
try
{
*msg = g_strdup_printf(
_("The permissions are wrong on the directory\n"
" %s\n"
"They must be at least 'rwx' for the user.\n"),
dirname);
return FALSE;
if (!gnc_validate_directory(usr_conf_dir, false))
usr_conf_dir = g_get_tmp_dir();
}
#endif
catch (const bfs::filesystem_error& ex)
{
g_warning("Cannot find suitable home directory. Using tmp directory instead.\n"
"The failure is\n%s", ex.what());
usr_conf_dir = g_get_tmp_dir();
}
}
g_assert(!usr_conf_dir.empty());
return TRUE;
usr_conf_dir /= ".gnucash";
if (!gnc_validate_directory(usr_conf_dir, true))
{
g_warning("Cannot find suitable .gnucash directory in home directory. Using tmp directory instead.");
usr_conf_dir = g_get_tmp_dir();
g_assert(!usr_conf_dir.empty());
usr_conf_dir /= ".gnucash";
/* This may throw and end the program! */
gnc_validate_directory(usr_conf_dir, true);
}
/** @fn const gchar * gnc_dotgnucash_dir ()
/* Since we're in code that is only executed once....
* Note these calls may throw and end the program! */
gnc_validate_directory(usr_conf_dir / "books", true);
gnc_validate_directory(usr_conf_dir / "checks", true);
gnc_validate_directory(usr_conf_dir / "translog", true);
}
/** @fn const gchar * gnc_userdata_dir ()
* @brief Ensure that the user's configuration directory exists and is minimally populated.
*
* Note that the default path is $HOME/.gnucash; This can be changed
* by the environment variable $GNC_DOT_DIR.
*
* @return An absolute path to the configuration directory
* @return An absolute path to the configuration directory. This string is
* by the gnc_filepath_utils code and should not be freed by the user.
*/
const gchar *
gnc_dotgnucash_dir (void)
gnc_userdata_dir (void)
{
static gchar *dotgnucash = NULL;
gchar *tmp_dir;
gchar *errmsg = NULL;
if (usr_conf_dir.empty())
gnc_filepath_init();
if (dotgnucash)
return dotgnucash;
dotgnucash = g_strdup(g_getenv("GNC_DOT_DIR"));
if (!dotgnucash)
{
const gchar *home = g_get_home_dir();
if (!home || !gnc_validate_directory(home, FALSE, &errmsg))
{
g_free(errmsg);
g_warning("Cannot find suitable home directory. Using tmp directory instead.");
home = g_get_tmp_dir();
}
g_assert(home);
dotgnucash = g_build_filename(home, ".gnucash", (gchar *)NULL);
}
if (!gnc_validate_directory(dotgnucash, TRUE, &errmsg))
{
const gchar *tmp = g_get_tmp_dir();
g_free(errmsg);
g_free(dotgnucash);
g_warning("Cannot find suitable .gnucash directory in home directory. Using tmp directory instead.");
g_assert(tmp);
dotgnucash = g_build_filename(tmp, ".gnucash", (gchar *)NULL);
if (!gnc_validate_directory(dotgnucash, TRUE, &errmsg))
exit(1);
return usr_conf_dir.c_str();
}
/* Since we're in code that is only executed once.... */
tmp_dir = g_build_filename(dotgnucash, "books", (gchar *)NULL);
if (!gnc_validate_directory(tmp_dir, TRUE, &errmsg))
exit(1);
g_free(tmp_dir);
tmp_dir = g_build_filename(dotgnucash, "checks", (gchar *)NULL);
if (!gnc_validate_directory(tmp_dir, TRUE, &errmsg))
exit(1);
g_free(tmp_dir);
tmp_dir = g_build_filename(dotgnucash, "translog", (gchar *)NULL);
if (!gnc_validate_directory(tmp_dir, TRUE, &errmsg))
exit(1);
g_free(tmp_dir);
static const bfs::path&
gnc_userdata_dir_as_path (void)
{
if (usr_conf_dir.empty())
gnc_filepath_init();
return dotgnucash;
return usr_conf_dir;
}
/** @fn gchar * gnc_build_dotgnucash_path (const gchar *filename)
/** @fn gchar * gnc_build_userdata_path (const gchar *filename)
* @brief Make a path to filename in the user's configuration directory.
*
* @param filename The name of the file
*
* @return An absolute path.
* @return An absolute path. The returned string should be freed by the user
* using g_free().
*/
gchar *
gnc_build_dotgnucash_path (const gchar *filename)
gnc_build_userdata_path (const gchar *filename)
{
return g_build_filename(gnc_dotgnucash_dir(), filename, (gchar *)NULL);
return g_strdup((gnc_userdata_dir_as_path() / filename).c_str());
}
static bfs::path
gnc_build_userdata_subdir_path (const gchar *subdir, const gchar *filename)
{
gchar* filename_dup = g_strdup(filename);
scrub_filename(filename_dup);
auto result = (gnc_userdata_dir_as_path() / subdir) / filename_dup;
g_free(filename_dup);
return result;
}
/** @fn gchar * gnc_build_book_path (const gchar *filename)
@ -483,20 +456,14 @@ gnc_build_dotgnucash_path (const gchar *filename)
*
* @param filename The name of the file
*
* @return An absolute path.
* @return An absolute path. The returned string should be freed by the user
* using g_free().
*/
gchar *
gnc_build_book_path (const gchar *filename)
{
gchar* filename_dup = g_strdup(filename);
gchar* result = NULL;
scrub_filename(filename_dup);
result = g_build_filename(gnc_dotgnucash_dir(), "books",
filename_dup, (gchar *)NULL);
g_free(filename_dup);
return result;
return g_strdup(gnc_build_userdata_subdir_path("books", filename).c_str());
}
/** @fn gchar * gnc_build_translog_path (const gchar *filename)
@ -504,20 +471,14 @@ gnc_build_book_path (const gchar *filename)
*
* @param filename The name of the file
*
* @return An absolute path.
* @return An absolute path. The returned string should be freed by the user
* using g_free().
*/
gchar *
gnc_build_translog_path (const gchar *filename)
{
gchar* filename_dup = g_strdup(filename);
gchar* result = NULL;
scrub_filename(filename_dup);
result = g_build_filename(gnc_dotgnucash_dir(), "translog",
filename_dup, (gchar *)NULL);
g_free(filename_dup);
return result;
return g_strdup(gnc_build_userdata_subdir_path("translog", filename).c_str());
}
/** @fn gchar * gnc_build_data_path (const gchar *filename)
@ -525,19 +486,14 @@ gnc_build_translog_path (const gchar *filename)
*
* @param filename The name of the file
*
* @return An absolute path.
* @return An absolute path. The returned string should be freed by the user
* using g_free().
*/
gchar *
gnc_build_data_path (const gchar *filename)
{
gchar* filename_dup = g_strdup(filename);
gchar* result;
scrub_filename(filename_dup);
result = g_build_filename(gnc_dotgnucash_dir(), "data", filename_dup, (gchar *)NULL);
g_free(filename_dup);
return result;
return g_strdup(gnc_build_userdata_subdir_path("data", filename).c_str());
}
/** @fn gchar * gnc_build_report_path (const gchar *filename)
@ -545,7 +501,8 @@ gnc_build_data_path (const gchar *filename)
*
* @param filename The name of the file
*
* @return An absolute path.
* @return An absolute path. The returned string should be freed by the user
* using g_free().
*/
gchar *
@ -560,7 +517,8 @@ gnc_build_report_path (const gchar *filename)
*
* @param filename The name of the file
*
* @return An absolute path.
* @return An absolute path. The returned string should be freed by the user
* using g_free().
*/
gchar *

View File

@ -75,8 +75,8 @@ gchar *gnc_resolve_file_path (const gchar *filefrag);
*/
gchar *gnc_path_find_localized_html_file (const gchar *file_name);
const gchar *gnc_dotgnucash_dir (void);
gchar *gnc_build_dotgnucash_path (const gchar *filename);
const gchar *gnc_userdata_dir (void);
gchar *gnc_build_userdata_path (const gchar *filename);
gchar *gnc_build_book_path (const gchar *filename);
gchar *gnc_build_translog_path (const gchar *filename);
gchar *gnc_build_data_path (const gchar *filename);

View File

@ -14,5 +14,8 @@ ENDMACRO()
ADD_CORE_UTILS_TEST(test-gnc-glib-utils test-gnc-glib-utils.c)
ADD_CORE_UTILS_TEST(test-resolve-file-path test-resolve-file-path.c)
ADD_CORE_UTILS_TEST(test-usr-conf-dir test-usr-conf-dir.c)
ADD_CORE_UTILS_TEST(test-usr-conf-dir-invalid-home test-usr-conf-dir-invalid-home.c)
SET_DIST_LIST(test_core_utils_DIST CMakeLists.txt Makefile.am test-gnc-glib-utils.c test-resolve-file-path.c)
SET_DIST_LIST(test_core_utils_DIST CMakeLists.txt Makefile.am test-gnc-glib-utils.c
test-resolve-file-path.c test-usr-conf-dir.c test-usr-conf-dir-invalid-home.c)

View File

@ -10,20 +10,24 @@ AM_CPPFLAGS = \
-I${top_srcdir}/libgnucash/core-utils \
-I${top_srcdir}/libgnucash/engine \
${GUILE_CFLAGS} \
${GLIB_CFLAGS}
${GLIB_CFLAGS} \
$(BOOST_CPPFLAGS)
LDADD = \
../libgnc-core-utils.la \
${top_builddir}/common/test-core/libtest-core.la \
${GLIB_LIBS}
${GLIB_LIBS} \
${BOOST_LDFLAGS}
# these tests are ordered kind more or less in the order
# that they should be executed, with more basic tests coming first.
#
TESTS = \
test-gnc-glib-utils \
test-resolve-file-path \
test-gnc-glib-utils
test-usr-conf-dir \
test-usr-conf-dir-invalid-home
GNC_TEST_DEPS = \
--library-dir ${top_builddir}/libgnucash/core-utils

View File

@ -29,16 +29,16 @@
#include "test-stuff.h"
#include "gnc-filepath-utils.h"
struct test_strings_struct
struct relpath_strings_struct
{
char *input;
char *output;
int prefix_home;
};
typedef struct test_strings_struct test_strings;
typedef struct relpath_strings_struct relpath_strings;
test_strings strs[] =
relpath_strings strs[] =
{
{
G_DIR_SEPARATOR_S ".gnucash" G_DIR_SEPARATOR_S "test-account-name",
@ -57,6 +57,18 @@ int
main(int argc, char **argv)
{
int i;
char *home_dir = NULL;
if (argc > 1)
/* One can pass a homedir on the command line. This
* will most likely cause the test to fail, but it can be
* used to pass invalid home directories manually. The
* test error messages should then show the system's temporary
* directory to be used instead */
home_dir = argv[1];
else
/* Set up a fake home directory to play with */
home_dir = g_dir_make_tmp("gnucashXXXXXX", NULL);
for (i = 0; strs[i].input != NULL; i++)
{
@ -66,15 +78,15 @@ main(int argc, char **argv)
if (strs[i].prefix_home == 1)
{
dain = g_build_filename(g_get_home_dir(), strs[i].input,
dain = g_build_filename(home_dir, strs[i].input,
(gchar *)NULL);
wantout = g_build_filename(g_get_home_dir(), strs[i].output,
wantout = g_build_filename(home_dir, strs[i].output,
(gchar *)NULL);
}
else if (strs[i].prefix_home == 2)
{
dain = g_strdup(strs[i].input);
wantout = g_build_filename(g_get_home_dir(), strs[i].output,
wantout = g_build_filename(home_dir, strs[i].output,
(gchar *)NULL);
}
else
@ -92,6 +104,7 @@ main(int argc, char **argv)
g_free(wantout);
g_free(daout);
}
print_test_results();
return get_rv();
}

View File

@ -0,0 +1,110 @@
/***************************************************************************
* test-resolve-file-path.c
*
* Thu Sep 29 22:48:57 2005
* Copyright 2005 GnuCash team
****************************************************************************/
/*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "test-stuff.h"
#include "gnc-filepath-utils.h"
struct usr_confpath_strings_struct
{
int func_num;
char *funcname;
char *output;
};
typedef struct usr_confpath_strings_struct usr_confpath_strings;
usr_confpath_strings strs2[] =
{
{
0, "gnc_build_userdata_path",
".gnucash"
},
{
1, "gnc_build_book_path",
".gnucash" G_DIR_SEPARATOR_S "books"
},
{
2, "gnc_build_translog_path",
".gnucash" G_DIR_SEPARATOR_S "translog"
},
{
3, "gnc_build_data_path",
".gnucash" G_DIR_SEPARATOR_S "data"
},
{ 0, NULL, NULL },
};
int
main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
{
int i;
const char *tmp_dir = g_get_tmp_dir();
/* Run usr conf dir tests with a valid and writable homedir */
g_setenv("HOME", "/notexist", TRUE);
for (i = 0; strs2[i].funcname != NULL; i++)
{
char *daout;
char *wantout;
if (strs2[i].func_num == 0)
{
wantout = g_build_filename(tmp_dir, strs2[i].output, "foo",
(gchar *)NULL);
daout = gnc_build_userdata_path("foo");
}
else if (strs2[i].func_num == 1)
{
wantout = g_build_filename(tmp_dir, strs2[i].output, "foo",
(gchar *)NULL);
daout = gnc_build_book_path("foo");
}
else if (strs2[i].func_num == 2)
{
wantout = g_build_filename(tmp_dir, strs2[i].output, "foo",
(gchar *)NULL);
daout = gnc_build_translog_path("foo");
}
else // if (strs2[i].prefix_home == 3)
{
wantout = g_build_filename(tmp_dir, strs2[i].output, "foo",
(gchar *)NULL);
daout = gnc_build_data_path("foo");
}
do_test_args(g_strcmp0(daout, wantout) == 0,
"gnc_build_x_path",
__FILE__, __LINE__,
"%s (%s) vs %s", daout, strs2[i].funcname, wantout);
g_free(wantout);
g_free(daout);
}
print_test_results();
return get_rv();
}

View File

@ -0,0 +1,121 @@
/***************************************************************************
* test-resolve-file-path.c
*
* Thu Sep 29 22:48:57 2005
* Copyright 2005 GnuCash team
****************************************************************************/
/*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "test-stuff.h"
#include "gnc-filepath-utils.h"
struct usr_confpath_strings_struct
{
int func_num;
char *funcname;
char *output;
};
typedef struct usr_confpath_strings_struct usr_confpath_strings;
usr_confpath_strings strs2[] =
{
{
0, "gnc_build_userdata_path",
".gnucash"
},
{
1, "gnc_build_book_path",
".gnucash" G_DIR_SEPARATOR_S "books"
},
{
2, "gnc_build_translog_path",
".gnucash" G_DIR_SEPARATOR_S "translog"
},
{
3, "gnc_build_data_path",
".gnucash" G_DIR_SEPARATOR_S "data"
},
{ 0, NULL, NULL },
};
int
main(int argc, char **argv)
{
int i;
char *home_dir = NULL;
if (argc > 1)
/* One can pass a homedir on the command line. This
* will most likely cause the test to fail, but it can be
* used to pass invalid home directories manually. The
* test error messages should then show the system's temporary
* directory to be used instead */
home_dir = argv[1];
else
/* Set up a fake home directory to play with */
home_dir = g_dir_make_tmp("gnucashXXXXXX", NULL);
/* Run usr conf dir tests with a valid and writable homedir */
g_setenv("HOME", home_dir, TRUE);
for (i = 0; strs2[i].funcname != NULL; i++)
{
char *daout;
char *wantout;
if (strs2[i].func_num == 0)
{
wantout = g_build_filename(home_dir, strs2[i].output, "foo",
(gchar *)NULL);
daout = gnc_build_userdata_path("foo");
}
else if (strs2[i].func_num == 1)
{
wantout = g_build_filename(home_dir, strs2[i].output, "foo",
(gchar *)NULL);
daout = gnc_build_book_path("foo");
}
else if (strs2[i].func_num == 2)
{
wantout = g_build_filename(home_dir, strs2[i].output, "foo",
(gchar *)NULL);
daout = gnc_build_translog_path("foo");
}
else // if (strs2[i].prefix_home == 3)
{
wantout = g_build_filename(home_dir, strs2[i].output, "foo",
(gchar *)NULL);
daout = gnc_build_data_path("foo");
}
do_test_args(g_strcmp0(daout, wantout) == 0,
"gnc_build_x_path",
__FILE__, __LINE__,
"%s (%s) vs %s", daout, strs2[i].funcname, wantout);
g_free(wantout);
g_free(daout);
}
print_test_results();
return get_rv();
}

View File

@ -598,7 +598,7 @@ libgnucash/backend/xml/sixtp-utils.cpp
libgnucash/core-utils/binreloc.c
libgnucash/core-utils/core-utils.scm
libgnucash/core-utils/gnc-environment.c
libgnucash/core-utils/gnc-filepath-utils.c
libgnucash/core-utils/gnc-filepath-utils.cpp
libgnucash/core-utils/gnc-gkeyfile-utils.c
libgnucash/core-utils/gnc-glib-utils.c
libgnucash/core-utils/gnc-guile-utils.c