Files
gnucash/gnucash/gnucash.cpp
Robert Fewell 43c2b7e9d7 Bug 797997 - Gnucash File can not be found on Windows from command line.
If the path to the Gnucash file is like C:\Temp\Comité\myfile.gnucash on
a Windows PC, the file will not be found. This also applies to the log
file when --logto C:\Temp\Comité\mylog.txt
2021-03-07 11:28:41 +00:00

409 lines
13 KiB
C++

/*
* gnucash.cpp -- The program entry point for GnuCash
*
* Copyright (C) 2006 Chris Shoemaker <c.shoemaker@cox.net>
*
* 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, contact:
*
* Free Software Foundation Voice: +1-617-542-5942
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
* Boston, MA 02110-1301, USA gnu@gnu.org
*/
#include <config.h>
#include <libguile.h>
#include <guile-mappings.h>
#ifdef __MINGW32__
#include <Windows.h>
#include <fcntl.h>
#endif
#include "gnucash-commands.hpp"
#include "gnucash-core-app.hpp"
extern "C" {
#include <dialog-new-user.h>
#include <gfec.h>
#include <gnc-file.h>
#include <gnc-filepath-utils.h>
#include <gnc-gnome-utils.h>
#include <gnc-gsettings.h>
#include <gnc-module.h>
#include <gnc-path.h>
#include <gnc-plugin-bi-import.h>
#include <gnc-plugin-csv-export.h>
#include <gnc-plugin-csv-import.h>
#include <gnc-plugin-customer-import.h>
#include <gnc-plugin-file-history.h>
#include <gnc-plugin-log-replay.h>
#include <gnc-plugin-qif-import.h>
#include <gnc-plugin-report-system.h>
#include <gnc-prefs.h>
#include <gnc-prefs-utils.h>
#include <gnc-report.h>
#include <gnc-session.h>
#include <gnc-splash.h>
#include <gnucash-register.h>
#include <search-core-type.h>
#include <top-level.h>
}
#include <boost/locale.hpp>
#include <boost/optional.hpp>
#ifdef __MINGW32__
#include <boost/nowide/args.hpp>
#endif
#include <iostream>
#include <gnc-locale-utils.hpp>
namespace bl = boost::locale;
/* This static indicates the debugging module that this .o belongs to. */
static QofLogModule log_module = GNC_MOD_GUI;
static gchar *userdata_migration_msg = NULL;
static void
update_message(const gchar *msg)
{
gnc_update_splash_screen(msg, GNC_SPLASH_PERCENTAGE_UNKNOWN);
g_message("%s", msg);
}
static void
load_system_config(void)
{
static int is_system_config_loaded = FALSE;
gchar *system_config_dir;
gchar *system_config;
if (is_system_config_loaded) return;
update_message("loading system configuration");
system_config_dir = gnc_path_get_pkgsysconfdir();
system_config = g_build_filename(system_config_dir, "config", nullptr);
is_system_config_loaded = gfec_try_load(system_config);
g_free(system_config_dir);
g_free(system_config);
}
static void
load_user_config(void)
{
/* Don't continue adding to this list. When 3.0 rolls around bump
the 2.4 files off the list. */
static const gchar *saved_report_files[] =
{
SAVED_REPORTS_FILE, SAVED_REPORTS_FILE_OLD_REV, NULL
};
static const gchar *stylesheet_files[] = { "stylesheets-2.0", NULL};
static int is_user_config_loaded = FALSE;
if (is_user_config_loaded)
return;
else is_user_config_loaded = TRUE;
update_message("loading user configuration");
{
gchar *config_filename;
config_filename = g_build_filename (gnc_userconfig_dir (),
"config-user.scm", (char *)NULL);
gfec_try_load(config_filename);
g_free(config_filename);
}
}
static void
load_gnucash_plugins()
{
gnc_plugin_bi_import_create_plugin ();
gnc_plugin_csv_export_create_plugin ();
gnc_plugin_csv_import_create_plugin();
gnc_plugin_customer_import_create_plugin ();
gnc_plugin_qif_import_create_plugin ();
gnc_plugin_log_replay_create_plugin ();
}
static void
load_gnucash_modules()
{
int i, len;
struct
{
const gchar * name;
int version;
gboolean optional;
} modules[] =
{
{ "gnucash/import-export/ofx", 0, TRUE },
{ "gnucash/import-export/aqbanking", 0, TRUE },
{ "gnucash/python", 0, TRUE },
};
/* module initializations go here */
len = sizeof(modules) / sizeof(*modules);
for (i = 0; i < len; i++)
{
DEBUG("Loading module %s started", modules[i].name);
gnc_update_splash_screen(modules[i].name, GNC_SPLASH_PERCENTAGE_UNKNOWN);
if (modules[i].optional)
gnc_module_load_optional(modules[i].name, modules[i].version);
else
gnc_module_load(modules[i].name, modules[i].version);
DEBUG("Loading module %s finished", modules[i].name);
}
}
static char *
get_file_to_load (const char* file_to_load)
{
if (file_to_load && *file_to_load != '\0')
return g_strdup(file_to_load);
else
/* Note history will always return a valid (possibly empty) string */
return gnc_history_get_last();
}
extern SCM scm_init_sw_gnome_module(void);
struct t_file_spec {
int nofile;
const char *file_to_load;
};
static void
scm_run_gnucash (void *data, [[maybe_unused]] int argc, [[maybe_unused]] char **argv)
{
auto user_file_spec = static_cast<t_file_spec*>(data);
SCM main_mod;
char* fn = NULL;
scm_c_eval_string("(debug-set! stack 200000)");
main_mod = scm_c_resolve_module("gnucash utilities");
scm_set_current_module(main_mod);
scm_c_use_module("gnucash app-utils");
/* Check whether the settings need a version update */
gnc_gsettings_version_upgrade ();
gnc_gnome_utils_init();
gnc_search_core_initialize ();
gnc_hook_add_dangler(HOOK_UI_SHUTDOWN, (GFunc)gnc_search_core_finalize, NULL, NULL);
gnucash_register_add_cell_types ();
gnc_report_init ();
load_gnucash_plugins();
load_gnucash_modules();
/* Load the config before starting up the gui. This insures that
* custom reports have been read into memory before the Reports
* menu is created. */
load_system_config();
load_user_config();
/* Setting-up the report menu must come after the module
loading but before the gui initializat*ion. */
gnc_plugin_report_system_new();
/* TODO: After some more guile-extraction, this should happen even
before booting guile. */
gnc_main_gui_init();
gnc_hook_add_dangler(HOOK_UI_SHUTDOWN, (GFunc)gnc_file_quit, NULL, NULL);
/* Install Price Quote Sources */
auto msg = bl::translate ("Checking Finance::Quote...").str(gnc_get_boost_locale());
gnc_update_splash_screen (msg.c_str(), GNC_SPLASH_PERCENTAGE_UNKNOWN);
scm_c_use_module("gnucash price-quotes");
scm_c_eval_string("(gnc:price-quotes-install-sources)");
gnc_hook_run(HOOK_STARTUP, NULL);
if (!user_file_spec->nofile && (fn = get_file_to_load (user_file_spec->file_to_load)) && *fn )
{
auto msg = bl::translate ("Loading data...").str(gnc_get_boost_locale());
gnc_update_splash_screen (msg.c_str(), GNC_SPLASH_PERCENTAGE_UNKNOWN);
gnc_file_open_file(gnc_get_splash_screen(), fn, /*open_readonly*/ FALSE);
g_free(fn);
}
else if (gnc_prefs_get_bool(GNC_PREFS_GROUP_NEW_USER, GNC_PREF_FIRST_STARTUP))
{
g_free(fn); /* fn could be an empty string ("") */
gnc_destroy_splash_screen();
gnc_ui_new_user_dialog();
}
if (userdata_migration_msg)
{
GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"%s",
userdata_migration_msg);
gnc_destroy_splash_screen();
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy (dialog);
g_free (userdata_migration_msg);
}
/* Ensure temporary preferences are temporary */
gnc_prefs_reset_group (GNC_PREFS_GROUP_WARNINGS_TEMP);
gnc_destroy_splash_screen();
gnc_main_window_show_all_windows();
gnc_hook_run(HOOK_UI_POST_STARTUP, NULL);
gnc_ui_start_event_loop();
gnc_hook_remove_dangler(HOOK_UI_SHUTDOWN, (GFunc)gnc_file_quit);
gnc_shutdown(0);
return;
}
namespace Gnucash {
class Gnucash : public CoreApp
{
public:
Gnucash (const char* app_name);
void parse_command_line (int argc, char **argv);
int start (int argc, char **argv);
private:
void configure_program_options (void);
bool m_nofile = false;
bool m_show_help_gtk = false;
bool m_add_quotes; // Deprecated will be removed in gnucash 5.0
boost::optional <std::string> m_namespace; // Deprecated will be removed in gnucash 5.0
std::string m_gtk_help_msg;
};
}
Gnucash::Gnucash::Gnucash (const char *app_name) : Gnucash::CoreApp (app_name)
{
configure_program_options();
}
void
Gnucash::Gnucash::parse_command_line (int argc, char **argv)
{
Gnucash::CoreApp::parse_command_line (argc, argv);
if (m_show_help_gtk)
{
std::cout << m_gtk_help_msg;
exit(0);
}
if (m_namespace)
gnc_prefs_set_namespace_regexp (m_namespace->c_str());
}
// Define command line options specific to gnucash.
void
Gnucash::Gnucash::configure_program_options (void)
{
// The g_option context dance below is done to be able to show a help message
// for gtk's options. The options themselves are already parsed out by
// gtk_init_check by the time this function is called though. So it really only
// serves to be able to display a help message.
g_set_prgname ("gnucash");
auto context = g_option_context_new (m_tagline.c_str());
auto gtk_options = gtk_get_option_group(FALSE);
g_option_context_add_group (context, gtk_options);
m_gtk_help_msg = g_option_context_get_help (context, FALSE, gtk_options);
g_option_context_free (context);
bpo::options_description app_options(_("Application Options"));
app_options.add_options()
("nofile", bpo::bool_switch (&m_nofile),
_("Do not load the last file opened"))
("help-gtk", bpo::bool_switch (&m_show_help_gtk),
_("Show help for gtk options"));
bpo::options_description depr_options(_("Deprecated Options"));
depr_options.add_options()
("add-price-quotes", bpo::bool_switch (&m_add_quotes),
_("Add price quotes to given GnuCash datafile.\n"
"Note this option has been deprecated and will be removed in GnuCash 5.0.\n"
"Please use 'gnucash-cli --quotes get <datafile>' instead."))
("namespace", bpo::value (&m_namespace),
_("Regular expression determining which namespace commodities will be retrieved.\n"
"Note this option has been deprecated and will be removed in GnuCash 5.0.\n"
"Please use 'gnucash-cli --quotes get --namespace <namespace> <datafile>' instead."));
m_opt_desc_display->add (app_options).add (depr_options);
m_opt_desc_all.add (app_options).add (depr_options);
}
int
Gnucash::Gnucash::start ([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
{
Gnucash::CoreApp::start();
// Test for the deprecated add-price-quotes option and run it
// Will be removed in 5.0
if (m_add_quotes)
{
std::cerr << bl::translate ("The '--add-price-quotes' option to gnucash has been deprecated and will be removed in GnuCash 5.0. "
"Please use 'gnucash-cli --quotes get <datafile>' instead.") << "\n";
if (!m_file_to_load || m_file_to_load->empty())
{
std::cerr << bl::translate("Missing data file parameter") << "\n\n"
<< *m_opt_desc_display.get();
return 1;
}
else
return add_quotes (m_file_to_load);
}
/* Now the module files are looked up, which might cause some library
initialization to be run, hence gtk must be initialized b*eforehand. */
gnc_module_system_init();
gnc_gui_init();
auto user_file_spec = t_file_spec {
m_nofile,
m_file_to_load ? m_file_to_load->c_str() : ""};
scm_boot_guile (argc, argv, scm_run_gnucash, &user_file_spec);
return 0;
}
int
main(int argc, char ** argv)
{
Gnucash::Gnucash application (argv[0]);
#ifdef __MINGW32__
boost::nowide::args a(argc, argv); // Fix arguments - make them UTF-8
#endif
/* We need to initialize gtk before looking up all modules */
if(!gtk_init_check (&argc, &argv))
{
std::cerr << bl::format (bl::translate ("Run '{1} --help' to see a full list of available command line options.")) % *argv[0]
<< "\n"
<< bl::translate ("Error: could not initialize graphical user interface and option add-price-quotes was not set.\n"
" Perhaps you need to set the $DISPLAY environment variable?");
return 1;
}
application.parse_command_line (argc, argv);
return application.start (argc, argv);
}