GnuCash 2.4.99
gnucash-bin.c
00001 /*
00002  * gnucash-bin.c -- The program entry point for GnuCash
00003  *
00004  * Copyright (C) 2006 Chris Shoemaker <c.shoemaker@cox.net>
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License as
00008  * published by the Free Software Foundation; either version 2 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, contact:
00018  *
00019  * Free Software Foundation           Voice:  +1-617-542-5942
00020  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00021  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00022  */
00023 #include "config.h"
00024 
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <libguile.h>
00029 #include <gtk/gtk.h>
00030 #include <glib/gi18n.h>
00031 #include <libgnome/libgnome.h>
00032 #include "glib.h"
00033 #include "gnc-module.h"
00034 #include "gnc-path.h"
00035 #include "binreloc.h"
00036 #include "gnc-locale-utils.h"
00037 #include "core-utils/gnc-version.h"
00038 #include "gnc-engine.h"
00039 #include "gnc-filepath-utils.h"
00040 #include "gnc-ui-util.h"
00041 #include "gnc-file.h"
00042 #include "gnc-hooks.h"
00043 #include "top-level.h"
00044 #include "gfec.h"
00045 #include "gnc-commodity.h"
00046 #include "gnc-main.h"
00047 #include "gnc-main-window.h"
00048 #include "gnc-splash.h"
00049 #include "gnc-gnome-utils.h"
00050 #include "gnc-plugin-file-history.h"
00051 #include "gnc-gconf-utils.h"
00052 #include "dialog-new-user.h"
00053 #include "gnc-session.h"
00054 #include "engine-helpers.h"
00055 #include "swig-runtime.h"
00056 
00057 /* This static indicates the debugging module that this .o belongs to.  */
00058 static QofLogModule log_module = GNC_MOD_GUI;
00059 
00060 #ifdef HAVE_GETTEXT
00061 #  include <libintl.h>
00062 #  include <locale.h>
00063 #endif
00064 
00065 #ifdef MAC_INTEGRATION
00066 #  include <Foundation/Foundation.h>
00067 #endif
00068 
00069 /* GNUCASH_SVN is defined whenever we're building from an SVN tree */
00070 #ifdef GNUCASH_SVN
00071 static int is_development_version = TRUE;
00072 #else
00073 static int is_development_version = FALSE;
00074 #endif
00075 
00076 /* Command-line option variables */
00077 static int gnucash_show_version = 0;
00078 static const char *add_quotes_file = NULL;
00079 static int nofile = 0;
00080 static const char *file_to_load = NULL;
00081 static gchar **log_flags = NULL;
00082 static gchar *log_to_filename = NULL;
00083 
00084 static void
00085 gnc_print_unstable_message(void)
00086 {
00087     if (!is_development_version) return;
00088 
00089     g_print("\n\n%s\n%s\n%s\n%s\n",
00090             _("This is a development version. It may or may not work."),
00091             _("Report bugs and other problems to gnucash-devel@gnucash.org"),
00092             _("You can also lookup and file bug reports at http://bugzilla.gnome.org"),
00093             _("To find the last stable version, please refer to http://www.gnucash.org"));
00094 }
00095 
00096 static gchar  *environment_expand(gchar *param)
00097 {
00098     gchar *search_start;
00099     gchar *opening_brace;
00100     gchar *closing_brace;
00101     gchar *result;
00102     gchar *tmp;
00103     gchar *expanded = NULL;
00104 
00105     if (!param)
00106         return NULL;
00107 
00108     /* Set an initial return value, so we can always use g_strconcat below) */
00109     result = g_strdup ("x");
00110 
00111     /* Look for matching pairs of { and }. Anything in between should be expanded */
00112     search_start = param;
00113     opening_brace = g_strstr_len (search_start, -1, "{");
00114     closing_brace = g_strstr_len (search_start, -1, "}");
00115 
00116     /* Note: the test on valid braces is fairly simple:
00117      *       * if no pair of opening/closing braces is found, no expansion occurs
00118      *       * braces can't be nested, this will give unexpected results
00119      *       * the string should contain no other braces than those used to mark
00120      *         expandable variables, or unexpected results will be returned.
00121      */
00122     while ( opening_brace && closing_brace && (closing_brace > opening_brace) )
00123     {
00124         /* Found a first matching pair */
00125         gchar *to_expand;
00126         const gchar *env_val;
00127 
00128         /* If the string had characters before the opening {, copy them first */
00129         if (opening_brace > search_start)
00130         {
00131             gchar *prefix = g_strndup (search_start, opening_brace - search_start);
00132 
00133             tmp = g_strconcat (result, prefix, NULL);
00134             g_free (result);
00135             result = tmp;
00136             g_free (prefix);
00137         }
00138 
00139         /* Expand the variable  we found and append it to the result */
00140         to_expand = g_strndup (opening_brace + 1, closing_brace - opening_brace - 1);
00141         env_val = g_getenv (to_expand);
00142         tmp = g_strconcat (result, env_val, NULL);
00143         g_free (result);
00144         result = tmp;
00145         g_free (to_expand);
00146 
00147         /* Look for matching pairs of { and }. Anything in between should be expanded */
00148         search_start = closing_brace + 1;
00149         opening_brace = g_strstr_len (search_start, -1, "{");
00150         closing_brace = g_strstr_len (search_start, -1, "}");
00151     }
00152 
00153     /* No more braces found, append the remaining characters */
00154     tmp = g_strconcat (result, search_start, NULL);
00155     g_free (result);
00156     result = tmp;
00157 
00158     /* Remove the "x" from our result */
00159     if (g_strcmp0 (result, "x"))
00160         expanded = g_strdup (result + 1);
00161     g_free (result);
00162 
00163     return expanded;
00164 }
00165 
00166 static void
00167 environment_override()
00168 {
00169     const gchar *path;
00170     gchar *config_path;
00171     gchar *env_file;
00172     GKeyFile    *keyfile = g_key_file_new();
00173     GError      *error;
00174     gchar **env_vars;
00175     gsize param_count;
00176     gint i;
00177     gboolean got_keyfile;
00178     gchar *env_parm, *bin_parm;
00179 
00180     /* Export default parameters to the environment */
00181     env_parm = gnc_path_get_prefix();
00182     if (!g_setenv("GNC_HOME", env_parm, FALSE))
00183         g_warning ("Couldn't set/override environment variable GNC_HOME.");
00184     bin_parm = g_build_filename(env_parm, "bin", NULL);
00185     if (!g_setenv("GNC_BIN", bin_parm, FALSE))
00186         g_warning ("Couldn't set/override environment variable GNC_BIN.");
00187     g_free (env_parm);
00188     g_free (bin_parm);
00189     env_parm = gnc_path_get_pkglibdir();
00190     if (!g_setenv("GNC_LIB", env_parm, FALSE))
00191         g_warning ("Couldn't set/override environment variable GNC_LIB.");
00192     g_free (env_parm);
00193     env_parm = gnc_path_get_pkgdatadir();
00194     if (!g_setenv("GNC_DATA", env_parm, FALSE))
00195         g_warning ("Couldn't set/override environment variable GNC_DATA.");
00196     g_free (env_parm);
00197     env_parm = gnc_path_get_pkgsysconfdir();
00198     if (!g_setenv("GNC_CONF", env_parm, FALSE))
00199         g_warning ("Couldn't set/override environment variable GNC_CONF.");
00200     g_free (env_parm);
00201     env_parm = gnc_path_get_libdir();
00202     if (!g_setenv("SYS_LIB", env_parm, FALSE))
00203         g_warning ("Couldn't set/override environment variable SYS_LIB.");
00204     g_free (env_parm);
00205 
00206     config_path = gnc_path_get_pkgsysconfdir();
00207 #ifdef G_OS_WIN32
00208     {
00209         /* unhide files without extension */
00210         gchar *pathext = g_build_path(";", ".", g_getenv("PATHEXT"),
00211                                       (gchar*) NULL);
00212         g_setenv("PATHEXT", pathext, TRUE);
00213         g_free(pathext);
00214     }
00215 #endif
00216 
00217     env_file = g_build_filename (config_path, "environment", NULL);
00218     got_keyfile = g_key_file_load_from_file (keyfile, env_file, G_KEY_FILE_NONE, &error);
00219     g_free (config_path);
00220     g_free (env_file);
00221     if ( !got_keyfile )
00222     {
00223         g_key_file_free(keyfile);
00224         return;
00225     }
00226 
00227     /* Read the environment overrides and apply them */
00228     env_vars = g_key_file_get_keys(keyfile, "Variables", &param_count, &error);
00229     for ( i = 0; i < param_count; i++ )
00230     {
00231         gchar **val_list;
00232         gsize val_count;
00233         gint j;
00234         gchar *new_val = NULL, *tmp_val;
00235 
00236         /* For each variable, read its new value, optionally expand it and set/unset it */
00237         val_list = g_key_file_get_string_list (keyfile, "Variables",
00238                                                env_vars[i], &val_count,
00239                                                &error );
00240         if ( val_count == 0 )
00241             g_unsetenv (env_vars[i]);
00242         else
00243         {
00244             /* Set an initial return value, so we can always use g_build_path below) */
00245             tmp_val = g_strdup ("x");
00246             for ( j = 0; j < val_count; j++ )
00247             {
00248                 gchar *expanded = environment_expand (val_list[j]);
00249                 new_val = g_build_path (G_SEARCHPATH_SEPARATOR_S, tmp_val, expanded, NULL);
00250                 g_free (tmp_val);
00251                 g_free(expanded);
00252                 tmp_val = new_val;
00253             }
00254             g_strfreev (val_list);
00255 
00256             /* Remove the "x" from our result */
00257             if (g_strcmp0 (tmp_val, "x"))
00258                 new_val = g_strdup (tmp_val + sizeof (G_SEARCHPATH_SEPARATOR_S));
00259             g_free (tmp_val);
00260 
00261             if (!g_setenv (env_vars[i], new_val, TRUE))
00262                 g_warning ("Couldn't properly override environment variable \"%s\". "
00263                            "This may lead to unexpected results", env_vars[i]);
00264             g_free(new_val);
00265         }
00266     }
00267 
00268     g_strfreev(env_vars);
00269     g_key_file_free(keyfile);
00270 }
00271 
00272 #ifdef MAC_INTEGRATION
00273 static void
00274 set_mac_locale()
00275 {
00276     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00277     NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
00278     NSArray *languages = [defs objectForKey: @"AppleLanguages"];
00279     const gchar *langs = NULL;
00280     NSLocale *locale = [NSLocale currentLocale];
00281     NSString *locale_str = [[[locale objectForKey: NSLocaleLanguageCode]
00282                              stringByAppendingString: @"_"]
00283                             stringByAppendingString:
00284                             [locale objectForKey: NSLocaleCountryCode]];
00285 /* If we didn't get a valid current locale, the string will be just "_" */
00286     if ([locale_str isEqualToString: @"_"])
00287         setlocale(LC_ALL, "en_US");
00288     else
00289         setlocale(LC_ALL, [locale_str UTF8String]);
00290 /* If the currency doesn't match the base locale, we need to find a locale that does match, because setlocale won't know what to do with just a currency identifier. */
00291     if (![[locale objectForKey: NSLocaleCurrencyCode] isEqualToString:
00292           [[[NSLocale alloc] initWithLocaleIdentifier: locale_str] objectForKey: NSLocaleCurrencyCode]]) {
00293         NSArray *all_locales = [NSLocale availableLocaleIdentifiers];
00294         NSEnumerator *locale_iter = [all_locales objectEnumerator];
00295         NSString *this_locale;
00296         NSString *currency = [locale objectForKey: NSLocaleCurrencyCode];
00297         NSString *money_locale = nil;
00298         while ((this_locale = (NSString*)[locale_iter nextObject]))
00299             if ([[[[NSLocale alloc] initWithLocaleIdentifier: this_locale]
00300                    objectForKey: NSLocaleCurrencyCode]
00301                  isEqualToString: currency]) {
00302                 money_locale = this_locale;
00303                 break;
00304             }
00305         if (money_locale)
00306             setlocale(LC_MONETARY, [money_locale UTF8String]);
00307     }
00308 /* Now call gnc_localeconv() to force creation of the app locale
00309  * before another call to setlocale messes it up. */
00310     gnc_localeconv ();
00311 /* Process the language list.
00312  *
00313  * Language subgroups (e.g., US English) are reported in the form
00314  * "ll-SS" (e.g. again, "en-US"), not what gettext wants. We convert
00315  * those to old-style locales, which is easy for most cases. There are
00316  * two where it isn't, though: Simplified Chinese (zh-Hans) and
00317  * traditional Chinese (zh-Hant), which are normally assigned the
00318  * locales zh_CN and zh_TW, respectively. Those are handled
00319  * specially.*/
00320     if ([languages count] > 0) {
00321         NSEnumerator *lang_iter = [languages objectEnumerator];
00322         NSString *this_lang;
00323         NSArray *elements;
00324         NSArray *new_languages = [NSArray array];
00325         while ((this_lang = [lang_iter nextObject])) {
00326             this_lang = [this_lang stringByTrimmingCharactersInSet:
00327                          [NSCharacterSet characterSetWithCharactersInString:
00328                           @"\""]];
00329             elements = [this_lang componentsSeparatedByString: @"-"];
00330             if ([elements count] > 1) {
00331                 if ([[elements objectAtIndex: 0] isEqualToString: @"zh"]) {
00332                     if ([[elements objectAtIndex: 1] isEqualToString: @"Hans"])
00333                         this_lang = [NSString stringWithString: @"zh_CN"];
00334                     else
00335                         this_lang = [NSString stringWithString: @"zh_TW"];
00336                 }
00337                 else
00338                   this_lang = [elements componentsJoinedByString: @"_"];
00339             }
00340             new_languages = [new_languages arrayByAddingObject: this_lang];
00341 /* If it's an english language, add the "C" locale after it so that
00342  * any messages can default to it */
00343             if ( [[elements objectAtIndex: 0] isEqualToString: @"en"])
00344                 new_languages = [new_languages arrayByAddingObject: @"C"];
00345 
00346         }
00347         langs = [[new_languages componentsJoinedByString:@":"] UTF8String];
00348     }
00349     if (langs && strlen(langs) > 0)
00350         g_setenv("LANGUAGE", langs, TRUE);
00351     [pool drain];
00352 }
00353 #endif /* MAC_INTEGRATION */
00354 
00355 static gboolean
00356 try_load_config_array(const gchar *fns[])
00357 {
00358     gchar *filename;
00359     int i;
00360 
00361     for (i = 0; fns[i]; i++)
00362     {
00363         filename = gnc_build_dotgnucash_path(fns[i]);
00364         if (gfec_try_load(filename))
00365         {
00366             g_free(filename);
00367             return TRUE;
00368         }
00369         g_free(filename);
00370     }
00371     return FALSE;
00372 }
00373 
00374 static void
00375 update_message(const gchar *msg)
00376 {
00377     gnc_update_splash_screen(msg, GNC_SPLASH_PERCENTAGE_UNKNOWN);
00378     g_message("%s", msg);
00379 }
00380 
00381 static void
00382 load_system_config(void)
00383 {
00384     static int is_system_config_loaded = FALSE;
00385     gchar *system_config_dir;
00386     gchar *system_config;
00387 
00388     if (is_system_config_loaded) return;
00389 
00390     update_message("loading system configuration");
00391     system_config_dir = gnc_path_get_pkgsysconfdir();
00392     system_config = g_build_filename(system_config_dir, "config", NULL);
00393     is_system_config_loaded = gfec_try_load(system_config);
00394     g_free(system_config_dir);
00395     g_free(system_config);
00396 }
00397 
00398 static void
00399 load_user_config(void)
00400 {
00401     /* Don't continue adding to this list. When 2.0 rolls around bump
00402        the 1.4 (unnumbered) files off the list. */
00403     static const gchar *user_config_files[] =
00404     {
00405         "config-2.0.user", "config-1.8.user", "config-1.6.user",
00406         "config.user", NULL
00407     };
00408     static const gchar *auto_config_files[] =
00409     {
00410         "config-2.0.auto", "config-1.8.auto", "config-1.6.auto",
00411         "config.auto", NULL
00412     };
00413     static const gchar *saved_report_files[] =
00414     {
00415         "saved-reports-2.4", "saved-reports-2.0", NULL
00416     };
00417     static const gchar *stylesheet_files[] = { "stylesheets-2.0", NULL};
00418     static int is_user_config_loaded = FALSE;
00419 
00420     if (is_user_config_loaded)
00421         return;
00422     else is_user_config_loaded = TRUE;
00423 
00424     update_message("loading user configuration");
00425     try_load_config_array(user_config_files);
00426     update_message("loading auto configuration");
00427     try_load_config_array(auto_config_files);
00428     update_message("loading saved reports");
00429     try_load_config_array(saved_report_files);
00430     update_message("loading stylesheets");
00431     try_load_config_array(stylesheet_files);
00432 }
00433 
00434 /* Parse command line options, using GOption interface */
00435 
00436 static void
00437 gnucash_command_line(int *argc, char **argv)
00438 {
00439     int debugging = 0, extra = 0;
00440     char *namespace_regexp = NULL;
00441     const gchar *gconf_path = NULL;
00442     GError *error = NULL;
00443     GOptionContext *context;
00444     GOptionEntry options[] =
00445     {
00446         {
00447             "version", 'v', 0, G_OPTION_ARG_NONE, &gnucash_show_version,
00448             _("Show GnuCash version"), NULL
00449         },
00450 
00451         {
00452             "debug", '\0', 0, G_OPTION_ARG_NONE, &debugging,
00453             _("Enable debugging mode: increasing logging to provide deep detail."), NULL
00454         },
00455 
00456         {
00457             "extra", '\0', 0, G_OPTION_ARG_NONE, &extra,
00458             _("Enable extra/development/debugging features."), NULL
00459         },
00460 
00461         {
00462             "log", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &log_flags,
00463             _("Log level overrides, of the form \"log.ger.path={debug,info,warn,crit,error}\""),
00464             NULL
00465         },
00466 
00467         {
00468             "logto", '\0', 0, G_OPTION_ARG_STRING, &log_to_filename,
00469             _("File to log into; defaults to \"/tmp/gnucash.trace\"; can be \"stderr\" or \"stdout\"."),
00470             NULL
00471         },
00472 
00473         {
00474             "nofile", '\0', 0, G_OPTION_ARG_NONE, &nofile,
00475             _("Do not load the last file opened"), NULL
00476         },
00477         {
00478             "gconf-path", '\0', 0, G_OPTION_ARG_STRING, &gconf_path,
00479             _("Set the prefix path for gconf queries"),
00480             /* Translators: Argument description for autohelp; see
00481                http://developer.gnome.org/doc/API/2.0/glib/glib-Commandline-option-parser.html */
00482             _("GCONFPATH")
00483         },
00484         {
00485             "add-price-quotes", '\0', 0, G_OPTION_ARG_STRING, &add_quotes_file,
00486             _("Add price quotes to given GnuCash datafile"),
00487             /* Translators: Argument description for autohelp; see
00488                http://developer.gnome.org/doc/API/2.0/glib/glib-Commandline-option-parser.html */
00489             _("FILE")
00490         },
00491         {
00492             "namespace", '\0', 0, G_OPTION_ARG_STRING, &namespace_regexp,
00493             _("Regular expression determining which namespace commodities will be retrieved"),
00494             /* Translators: Argument description for autohelp; see
00495                http://developer.gnome.org/doc/API/2.0/glib/glib-Commandline-option-parser.html */
00496             _("REGEXP")
00497         },
00498         { NULL }
00499     };
00500 
00501     context = g_option_context_new (" [datafile]");
00502     g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
00503     g_option_context_add_group (context, gtk_get_option_group (FALSE));
00504     if (!g_option_context_parse (context, argc, &argv, &error))
00505     {
00506         g_warning("Error parsing command line arguments: [%s]; try `gnucash --help` for available options.", error->message);
00507         exit(1);
00508     }
00509     g_option_context_free (context);
00510     if (error)
00511         g_error_free(error);
00512 
00513     if (*argc > 0)
00514         file_to_load = argv[1];
00515 
00516     if (gnucash_show_version)
00517     {
00518         if (is_development_version)
00519         {
00520             /* Translators: %s is the version number */
00521             g_print(_("GnuCash %s development version"), VERSION);
00522         }
00523         else
00524         {
00525             /* Translators: %s is the version number */
00526             g_print(_("GnuCash %s"), VERSION);
00527         }
00528         g_print("\n");
00529         /* Translators: 1st %s is the build date; 2nd %s is the SVN
00530            revision number */
00531         g_print(_("Built %s from r%s"), GNUCASH_BUILD_DATE, GNUCASH_SVN_REV);
00532         g_print("\n");
00533         exit(0);
00534     }
00535 
00536     gnc_set_extra(extra);
00537 
00538     if (!gconf_path)
00539     {
00540         const char *path = g_getenv("GNC_GCONF_PATH");
00541         if (path)
00542             gconf_path = path;
00543         else
00544             gconf_path = GCONF_PATH;
00545     }
00546 
00547     gnc_set_gconf_path(g_strdup(gconf_path));
00548     gnc_set_debugging(debugging);
00549 
00550     if (namespace_regexp)
00551         gnc_main_set_namespace_regexp(namespace_regexp);
00552 }
00553 
00554 static void
00555 load_gnucash_modules()
00556 {
00557     int i, len;
00558     struct
00559     {
00560         gchar * name;
00561         int version;
00562         gboolean optional;
00563     } modules[] =
00564     {
00565         { "gnucash/app-utils", 0, FALSE },
00566         { "gnucash/engine", 0, FALSE },
00567         { "gnucash/register/ledger-core", 0, FALSE },
00568         { "gnucash/register/register-core", 0, FALSE },
00569         { "gnucash/register/register-gnome", 0, FALSE },
00570         { "gnucash/import-export/qif-import", 0, FALSE },
00571         { "gnucash/import-export/ofx", 0, TRUE },
00572         { "gnucash/import-export/csv-import", 0, TRUE },
00573         { "gnucash/import-export/csv-export", 0, TRUE },
00574         { "gnucash/import-export/log-replay", 0, TRUE },
00575         { "gnucash/import-export/aqbanking", 0, TRUE },
00576         { "gnucash/report/report-system", 0, FALSE },
00577         { "gnucash/report/stylesheets", 0, FALSE },
00578         { "gnucash/report/standard-reports", 0, FALSE },
00579         { "gnucash/report/utility-reports", 0, FALSE },
00580         { "gnucash/report/locale-specific/us", 0, FALSE },
00581         { "gnucash/report/report-gnome", 0, FALSE },
00582         { "gnucash/business-gnome", 0, TRUE },
00583         { "gnucash/gtkmm", 0, TRUE },
00584         { "gnucash/python", 0, TRUE },
00585     };
00586 
00587     /* module initializations go here */
00588     len = sizeof(modules) / sizeof(*modules);
00589     for (i = 0; i < len; i++)
00590     {
00591         DEBUG("Loading module %s started", modules[i].name);
00592         gnc_update_splash_screen(modules[i].name, GNC_SPLASH_PERCENTAGE_UNKNOWN);
00593         if (modules[i].optional)
00594             gnc_module_load_optional(modules[i].name, modules[i].version);
00595         else
00596             gnc_module_load(modules[i].name, modules[i].version);
00597         DEBUG("Loading module %s finished", modules[i].name);
00598     }
00599     if (!gnc_engine_is_initialized())
00600     {
00601         /* On Windows this check used to fail anyway, see
00602          * https://lists.gnucash.org/pipermail/gnucash-devel/2006-September/018529.html
00603          * but more recently it seems to work as expected
00604          * again. 2006-12-20, cstim. */
00605         g_warning("GnuCash engine failed to initialize.  Exiting.\n");
00606         exit(1);
00607     }
00608 }
00609 
00610 static void
00611 inner_main_add_price_quotes(void *closure, int argc, char **argv)
00612 {
00613     SCM mod, add_quotes, scm_book, scm_result = SCM_BOOL_F;
00614     QofSession *session = NULL;
00615 
00616     scm_c_eval_string("(debug-set! stack 200000)");
00617 
00618     mod = scm_c_resolve_module("gnucash price-quotes");
00619     scm_set_current_module(mod);
00620 
00621     /* Don't load the modules since the stylesheet module crashes if the
00622        GUI is not initialized */
00623 #ifdef PRICE_QUOTES_NEED_MODULES
00624     load_gnucash_modules();
00625 #endif
00626 
00627     qof_event_suspend();
00628     scm_c_eval_string("(gnc:price-quotes-install-sources)");
00629 
00630     if (!gnc_quote_source_fq_installed())
00631     {
00632         g_print("%s", _("No quotes retrieved. Finance::Quote isn't "
00633                         "installed properly.\n"));
00634         goto fail;
00635     }
00636 
00637     add_quotes = scm_c_eval_string("gnc:book-add-quotes");
00638     session = gnc_get_current_session();
00639     if (!session) goto fail;
00640 
00641     qof_session_begin(session, add_quotes_file, FALSE, FALSE, FALSE);
00642     if (qof_session_get_error(session) != ERR_BACKEND_NO_ERR) goto fail;
00643 
00644     qof_session_load(session, NULL);
00645     if (qof_session_get_error(session) != ERR_BACKEND_NO_ERR) goto fail;
00646 
00647     scm_book = gnc_book_to_scm(qof_session_get_book(session));
00648     scm_result = scm_call_2(add_quotes, SCM_BOOL_F, scm_book);
00649 
00650     qof_session_save(session, NULL);
00651     if (qof_session_get_error(session) != ERR_BACKEND_NO_ERR) goto fail;
00652 
00653     qof_session_destroy(session);
00654     if (!scm_is_true(scm_result))
00655     {
00656         g_warning("Failed to add quotes to %s.", add_quotes_file);
00657         goto fail;
00658     }
00659 
00660     qof_event_resume();
00661     gnc_shutdown(0);
00662     return;
00663 fail:
00664     if (session && qof_session_get_error(session) != ERR_BACKEND_NO_ERR)
00665         g_warning("Session Error: %s", qof_session_get_error_message(session));
00666     qof_event_resume();
00667     gnc_shutdown(1);
00668 }
00669 
00670 static char *
00671 get_file_to_load()
00672 {
00673     if (file_to_load)
00674         return g_strdup(file_to_load);
00675     else
00676         return gnc_history_get_last();
00677 }
00678 
00679 static void
00680 inner_main (void *closure, int argc, char **argv)
00681 {
00682     SCM main_mod;
00683     char* fn;
00684     GError *error = NULL;
00685 
00686     scm_c_eval_string("(debug-set! stack 200000)");
00687 
00688     main_mod = scm_c_resolve_module("gnucash main");
00689     scm_set_current_module(main_mod);
00690 
00691     load_gnucash_modules();
00692 
00693     /* Load the config before starting up the gui. This insures that
00694      * custom reports have been read into memory before the Reports
00695      * menu is created. */
00696     load_system_config();
00697     load_user_config();
00698 
00699     /* Setting-up the report menu must come after the module
00700        loading but before the gui initialization. */
00701     scm_c_use_module("gnucash report report-gnome");
00702     scm_c_eval_string("(gnc:report-menu-setup)");
00703 
00704     /* TODO: After some more guile-extraction, this should happen even
00705        before booting guile.  */
00706     gnc_main_gui_init();
00707 
00708     gnc_hook_add_dangler(HOOK_UI_SHUTDOWN, (GFunc)gnc_file_quit, NULL);
00709 
00710     scm_c_eval_string("(gnc:main)");
00711 
00712     /* Install Price Quote Sources */
00713     gnc_update_splash_screen(_("Checking Finance::Quote..."), GNC_SPLASH_PERCENTAGE_UNKNOWN);
00714     scm_c_use_module("gnucash price-quotes");
00715     scm_c_eval_string("(gnc:price-quotes-install-sources)");
00716 
00717     gnc_hook_run(HOOK_STARTUP, NULL);
00718 
00719     if (!nofile && (fn = get_file_to_load()))
00720     {
00721         gnc_update_splash_screen(_("Loading data..."), GNC_SPLASH_PERCENTAGE_UNKNOWN);
00722         gnc_file_open_file(fn, /*open_readonly*/ FALSE);
00723         g_free(fn);
00724     }
00725     else if (gnc_gconf_get_bool("dialogs/new_user", "first_startup", &error)
00726              && !error)
00727     {
00728         gnc_destroy_splash_screen();
00729         gnc_ui_new_user_dialog();
00730     }
00731 
00732     gnc_destroy_splash_screen();
00733     gnc_main_window_show_all_windows();
00734 
00735     gnc_hook_run(HOOK_UI_POST_STARTUP, NULL);
00736     gnc_ui_start_event_loop();
00737     gnc_hook_remove_dangler(HOOK_UI_SHUTDOWN, (GFunc)gnc_file_quit);
00738 
00739     gnc_shutdown(0);
00740     return;
00741 }
00742 
00743 static void
00744 gnc_log_init()
00745 {
00746     if (log_to_filename != NULL)
00747     {
00748         qof_log_init_filename_special(log_to_filename);
00749     }
00750     else
00751     {
00752         /* initialize logging to our file. */
00753         gchar *tracefilename;
00754         tracefilename = g_build_filename(g_get_tmp_dir(), "gnucash.trace",
00755                                          (gchar *)NULL);
00756         qof_log_init_filename(tracefilename);
00757         g_free(tracefilename);
00758     }
00759 
00760     // set a reasonable default.
00761     qof_log_set_default(QOF_LOG_WARNING);
00762 
00763     gnc_log_default();
00764 
00765     if (gnc_is_debugging())
00766     {
00767         qof_log_set_level("", QOF_LOG_INFO);
00768         qof_log_set_level("qof", QOF_LOG_INFO);
00769         qof_log_set_level("gnc", QOF_LOG_INFO);
00770     }
00771 
00772     {
00773         gchar *log_config_filename;
00774         log_config_filename = gnc_build_dotgnucash_path("log.conf");
00775         if (g_file_test(log_config_filename, G_FILE_TEST_EXISTS))
00776             qof_log_parse_log_config(log_config_filename);
00777         g_free(log_config_filename);
00778     }
00779 
00780     if (log_flags != NULL)
00781     {
00782         int i = 0;
00783         for (; log_flags[i] != NULL; i++)
00784         {
00785             QofLogLevel level;
00786             gchar **parts = NULL;
00787 
00788             gchar *log_opt = log_flags[i];
00789             parts = g_strsplit(log_opt, "=", 2);
00790             if (parts == NULL || parts[0] == NULL || parts[1] == NULL)
00791             {
00792                 g_warning("string [%s] not parseable", log_opt);
00793                 continue;
00794             }
00795 
00796             level = qof_log_level_from_string(parts[1]);
00797             qof_log_set_level(parts[0], level);
00798             g_strfreev(parts);
00799         }
00800     }
00801 }
00802 
00803 int
00804 main(int argc, char ** argv)
00805 {
00806 #if !defined(G_THREADS_ENABLED) || defined(G_THREADS_IMPL_NONE)
00807 #    error "No GLib thread implementation available!"
00808 #endif
00809     g_thread_init(NULL);
00810 
00811 #ifdef ENABLE_BINRELOC
00812     {
00813         GError *binreloc_error = NULL;
00814         if (!gnc_gbr_init(&binreloc_error))
00815         {
00816             g_print("main: Error on gnc_gbr_init: %s\n", binreloc_error->message);
00817             g_error_free(binreloc_error);
00818         }
00819     }
00820 #endif
00821 
00822     /* This should be called before gettext is initialized
00823      * The user may have configured a different language via
00824      * the environment file.
00825      */
00826 #ifdef MAC_INTEGRATION
00827     set_mac_locale();
00828 #else
00829     environment_override();
00830 #endif
00831 #ifdef HAVE_GETTEXT
00832     {
00833         gchar *localedir = gnc_path_get_localedir();
00834         bindtextdomain(GETTEXT_PACKAGE, localedir);
00835         textdomain(GETTEXT_PACKAGE);
00836         bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
00837         g_free(localedir);
00838     }
00839 #endif
00840 
00841     qof_log_init();
00842     qof_log_set_default(QOF_LOG_INFO);
00843 
00844     /* Note: setlocale will also be called later by gtk_init (which gets
00845      * invoked by gnome_program_init), but that's too late. The locale
00846      * must be properly set before parsing the command line arguments
00847      * or filenames may be returned in a charset other than UTF-8 and
00848      * not work with other glib calls.
00849      */
00850     setlocale(LC_ALL, "");
00851     gnucash_command_line(&argc, argv);
00852     gnc_print_unstable_message();
00853 
00854     gnc_module_system_init();
00855     gnc_log_init();
00856 
00857 
00858     if (add_quotes_file)
00859     {
00860         gchar *prefix = gnc_path_get_prefix ();
00861         gchar *pkgsysconfdir = gnc_path_get_pkgsysconfdir ();
00862         gchar *pkgdatadir = gnc_path_get_pkgdatadir ();
00863         gchar *pkglibdir = gnc_path_get_pkglibdir ();
00864         /* This option needs to run without a display, so we can't
00865            initialize any GUI libraries.  */
00866         gnome_program_init(
00867             PACKAGE, VERSION, LIBGNOME_MODULE,
00868             argc, argv,
00869             GNOME_PARAM_APP_PREFIX, prefix,
00870             GNOME_PARAM_APP_SYSCONFDIR, pkgsysconfdir,
00871             GNOME_PARAM_APP_DATADIR, pkgdatadir,
00872             GNOME_PARAM_APP_LIBDIR, pkglibdir,
00873             GNOME_PARAM_NONE);
00874         g_free (prefix);
00875         g_free (pkgsysconfdir);
00876         g_free (pkgdatadir);
00877         g_free (pkglibdir);
00878         scm_boot_guile(argc, argv, inner_main_add_price_quotes, 0);
00879         exit(0);  /* never reached */
00880     }
00881 
00882     gnc_gnome_init (argc, argv, VERSION);
00883     gnc_gui_init();
00884     scm_boot_guile(argc, argv, inner_main, 0);
00885     exit(0); /* never reached */
00886 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines