diff --git a/src/app-utils/file-utils.c b/src/app-utils/file-utils.c index 43463ab37c..399222e1e7 100644 --- a/src/app-utils/file-utils.c +++ b/src/app-utils/file-utils.c @@ -23,6 +23,9 @@ #include #include +#ifndef HAVE_GLIB_2_8 +#include +#endif #include #include #include @@ -167,6 +170,63 @@ gnc_getline (gchar **line, FILE *file) } +/* Update one state file file to fit the new constraints introduced by + * glib 2.12.5. Supposedly its always been illegal to use spaces in + * key names, but it was never a problem with earlier releases of + * glib. Glib 2.12.5 added hard enforcement of this rule, completely + * ignoring any key/value pair where the key name contained an + * "illegal" character. Glib 2.12.7 relented and changed the hard + * failure to a warning, but the point has been made. Spaces in key + * names must go. + */ +static gboolean +gnc_update_state_file_keys(const gchar *filename) +{ + const gchar *eol; + gchar *contents, **lines, *line, **kv, **parts, *part, *newkey; + GError *error = NULL; + int i, j; + + if (!g_file_get_contents(filename, &contents, NULL, &error)) { + DEBUG("Error reading state file: %s", error->message); + g_error_free(error); + return FALSE; + } + + lines = g_strsplit(contents, "\n", -1); + g_free(contents); + + /* Strip spaces from non-comment lines, and rewrite the new text + * over top of the old text. The new line is guaranteed to be at + * most the same number of characters as the old. */ + for (i = 0, line = lines[i++]; line; line = lines[i++]) { + if ((*line == '\0') || (*line == '#') || (*line == '[')) { + continue; + } else { + kv = g_strsplit(line, "=", 2); + parts = g_strsplit(kv[0], " ", -1); + for (j = 0, part = parts[j++]; part; part = parts[j++]) + part[0] = g_ascii_toupper(part[0]); + newkey = g_strjoinv("", parts); + g_sprintf(line, "%s=%s", newkey, kv[1]); + g_free(newkey); + g_strfreev(parts); + g_strfreev(kv); + } + } + + contents = g_strjoinv("\n", lines); + if (!g_file_set_contents(filename, contents, -1, &error)) { + DEBUG("Error writing state file: %s", error->message); + g_error_free(error); + g_free(contents); + return FALSE; + } + + g_free(contents); + return TRUE; +} + /* Find the state file that corresponds to this URL and guid. The * URL is used to compute the base name of the file (which will be in * ~/.gnucash/books) and the guid is used to differentiate when the @@ -179,6 +239,7 @@ gnc_find_state_file (const gchar *url, gchar *basename, *original = NULL, *filename, *tmp, *file_guid; GKeyFile *key_file = NULL; GError *error = NULL; + gboolean do_increment; gint i; ENTER("url %s, guid %s", url, guid); @@ -199,9 +260,24 @@ gnc_find_state_file (const gchar *url, else filename = g_strdup_printf("%s_%d", original, i); DEBUG("Trying %s", filename); - key_file = gnc_key_file_load_from_file(filename, FALSE, FALSE); + key_file = gnc_key_file_load_from_file(filename, FALSE, FALSE, &error); DEBUG("Result %p", key_file); + if (error && + (error->domain == G_KEY_FILE_ERROR) && + (error->code == G_KEY_FILE_ERROR_PARSE)) { + /* Handle the case where glib was updated first, and is refusing + * to read old state files. */ + if (gnc_update_state_file_keys(filename)) { + DEBUG("Trying %s again", filename); + key_file = gnc_key_file_load_from_file(filename, FALSE, FALSE, NULL); + DEBUG("Result %p", key_file); + } + } + if (error) { + g_error_free(error); + error = NULL; + } if (!key_file) { DEBUG("No key file by that name"); break; @@ -209,19 +285,35 @@ gnc_find_state_file (const gchar *url, file_guid = g_key_file_get_string(key_file, STATE_FILE_TOP, STATE_FILE_BOOK_GUID, - &error); - DEBUG("File GUID is %s", file_guid); - if (strcmp(guid, file_guid) == 0) { + NULL); + DEBUG("%s is %s", STATE_FILE_BOOK_GUID, + file_guid ? file_guid : ""); + if (safe_strcmp(guid, file_guid) == 0) { DEBUG("Matched !!!"); g_free(file_guid); break; } + /* Handle the case where gnucash was updated first, and is trying + * to find new key names in an old state files. */ + file_guid = g_key_file_get_string(key_file, + STATE_FILE_TOP, STATE_FILE_BOOK_GUID_OLD, + NULL); + DEBUG("%s is %s", STATE_FILE_BOOK_GUID, + file_guid ? file_guid : ""); + if (safe_strcmp(guid, file_guid) == 0) { + DEBUG("Matched !!!"); + do_increment = !gnc_update_state_file_keys(filename); + } else { + do_increment = TRUE; + } + DEBUG("Clean up this pass"); g_free(file_guid); g_key_file_free(key_file); g_free(filename); - i++; + if (do_increment) + i++; } DEBUG("Clean up"); diff --git a/src/app-utils/file-utils.h b/src/app-utils/file-utils.h index 3a35c4c4ab..71f3f680b6 100644 --- a/src/app-utils/file-utils.h +++ b/src/app-utils/file-utils.h @@ -61,7 +61,8 @@ gint64 gnc_getline (gchar **line, FILE *file); /* Definitions shared by file-utils.c and gnc-main-window.c */ #define STATE_FILE_TOP "Top" -#define STATE_FILE_BOOK_GUID "Book Guid" +#define STATE_FILE_BOOK_GUID "BookGuid" +#define STATE_FILE_BOOK_GUID_OLD "Book Guid" /** Find the state file that corresponds to this URL and guid. The * URL is used to compute the base name of the file (which will be in diff --git a/src/app-utils/gnc-exp-parser.c b/src/app-utils/gnc-exp-parser.c index 8849dbb79f..5197e337eb 100644 --- a/src/app-utils/gnc-exp-parser.c +++ b/src/app-utils/gnc-exp-parser.c @@ -86,7 +86,7 @@ gnc_exp_parser_real_init ( gboolean addPredefined ) if ( addPredefined ) { filename = gnc_exp_parser_filname(); - key_file = gnc_key_file_load_from_file(filename, TRUE, FALSE); + key_file = gnc_key_file_load_from_file(filename, TRUE, FALSE, NULL); if (key_file) { keys = g_key_file_get_keys(key_file, GROUP_NAME, NULL, NULL); for (key = keys; key && *key; key++) { diff --git a/src/business/business-gnome/dialog-invoice.c b/src/business/business-gnome/dialog-invoice.c index 3023482dbd..d4f33e9a6a 100644 --- a/src/business/business-gnome/dialog-invoice.c +++ b/src/business/business-gnome/dialog-invoice.c @@ -1676,10 +1676,10 @@ gnc_invoice_new_page (GNCBook *bookp, InvoiceDialogType type, return iw; } -#define KEY_INVOICE_TYPE "Invoice Type" -#define KEY_INVOICE_GUID "Invoice GUID" -#define KEY_OWNER_TYPE "Owner Type" -#define KEY_OWNER_GUID "Owner GUID" +#define KEY_INVOICE_TYPE "InvoiceType" +#define KEY_INVOICE_GUID "InvoiceGUID" +#define KEY_OWNER_TYPE "OwnerType" +#define KEY_OWNER_GUID "OwnerGUID" GncPluginPage * gnc_invoice_recreate_page (GKeyFile *key_file, diff --git a/src/core-utils/gnc-gkeyfile-utils.c b/src/core-utils/gnc-gkeyfile-utils.c index defc2987bd..94a85711d3 100644 --- a/src/core-utils/gnc-gkeyfile-utils.c +++ b/src/core-utils/gnc-gkeyfile-utils.c @@ -48,7 +48,8 @@ GKeyFile * gnc_key_file_load_from_file (const gchar *filename, gboolean ignore_error, - gboolean return_empty_struct) + gboolean return_empty_struct, + GError **caller_error) { GKeyFile *key_file; GError *error = NULL; @@ -73,7 +74,7 @@ gnc_key_file_load_from_file (const gchar *filename, if (!ignore_error) g_warning("Unable to read file %s: %s\n", filename, error->message); - g_error_free(error); + g_propagate_error(caller_error, error); return key_file; } diff --git a/src/core-utils/gnc-gkeyfile-utils.h b/src/core-utils/gnc-gkeyfile-utils.h index ab567efcde..f8b4986fad 100644 --- a/src/core-utils/gnc-gkeyfile-utils.h +++ b/src/core-utils/gnc-gkeyfile-utils.h @@ -54,7 +54,8 @@ */ GKeyFile *gnc_key_file_load_from_file (const gchar *file, gboolean ignore_error, - gboolean return_empty_struct); + gboolean return_empty_struct, + GError **caller_error); /** Write a key/value file from memory to disk. If there is no data diff --git a/src/gnome-utils/gnc-main-window.c b/src/gnome-utils/gnc-main-window.c index 5ee3e3e008..ba3baa893f 100644 --- a/src/gnome-utils/gnc-main-window.c +++ b/src/gnome-utils/gnc-main-window.c @@ -394,19 +394,19 @@ static const gchar *multiple_page_actions[] = { /************************************************************ * * ************************************************************/ -#define WINDOW_COUNT "Window Count" +#define WINDOW_COUNT "WindowCount" #define WINDOW_STRING "Window %d" -#define WINDOW_GEOMETRY "Window Geometry" -#define WINDOW_POSITION "Window Position" -#define WINDOW_MAXIMIZED "Window Maximized" -#define TOOLBAR_VISIBLE "Toolbar Visible" -#define STATUSBAR_VISIBLE "Statusbar Visible" -#define SUMMARYBAR_VISIBLE "Summarybar Visible" -#define WINDOW_FIRSTPAGE "First Page" -#define WINDOW_PAGECOUNT "Page Count" -#define WINDOW_PAGEORDER "Page Order" -#define PAGE_TYPE "Page Type" -#define PAGE_NAME "Page Name" +#define WINDOW_GEOMETRY "WindowGeometry" +#define WINDOW_POSITION "WindowPosition" +#define WINDOW_MAXIMIZED "WindowMaximized" +#define TOOLBAR_VISIBLE "ToolbarVisible" +#define STATUSBAR_VISIBLE "StatusbarVisible" +#define SUMMARYBAR_VISIBLE "SummarybarVisible" +#define WINDOW_FIRSTPAGE "FirstPage" +#define WINDOW_PAGECOUNT "PageCount" +#define WINDOW_PAGEORDER "PageOrder" +#define PAGE_TYPE "PageType" +#define PAGE_NAME "PageName" #define PAGE_STRING "Page %d" typedef struct { diff --git a/src/gnome-utils/gnc-plugin-file-history.c b/src/gnome-utils/gnc-plugin-file-history.c index 4c00126d0a..eb2046ca52 100644 --- a/src/gnome-utils/gnc-plugin-file-history.c +++ b/src/gnome-utils/gnc-plugin-file-history.c @@ -435,7 +435,7 @@ gnc_plugin_history_list_from_gnucash1 (void) /* Copy the old values from the gnucash 1.x/gnome1 settings file to * the gnucash 2.x/gconf settings area. */ mdi_file = g_build_filename(home, ".gnome", "GnuCash", (gchar *)NULL); - keyfile = gnc_key_file_load_from_file (mdi_file, FALSE, FALSE); + keyfile = gnc_key_file_load_from_file (mdi_file, FALSE, FALSE, NULL); if (keyfile) { keys = g_key_file_get_keys(keyfile, GNOME1_HISTORY, NULL, NULL); if (keys) { diff --git a/src/gnome-utils/gnc-tree-view-account.c b/src/gnome-utils/gnc-tree-view-account.c index fa1f456191..ea31142d6e 100644 --- a/src/gnome-utils/gnc-tree-view-account.c +++ b/src/gnome-utils/gnc-tree-view-account.c @@ -1884,12 +1884,12 @@ account_filter_dialog_create(AccountFilterDialog *fd, GncPluginPage *page) LEAVE(" "); } -#define ACCT_COUNT "Number of Open Accounts" -#define ACCT_OPEN "Open Account %d" -#define ACCT_SELECTED "Selected Account" -#define SHOW_HIDDEN "Show Hidden" -#define SHOW_ZERO "Show Zero Total" -#define ACCT_TYPES "Account Types" +#define ACCT_COUNT "NumberOfOpenAccounts" +#define ACCT_OPEN "OpenAccount%d" +#define ACCT_SELECTED "SelectedAccount" +#define SHOW_HIDDEN "ShowHidden" +#define SHOW_ZERO "ShowZeroTotal" +#define ACCT_TYPES "AccountTypes" typedef struct foo { GKeyFile *key_file; diff --git a/src/gnome/gnc-plugin-page-register.c b/src/gnome/gnc-plugin-page-register.c index e2df41281c..894efa47bb 100644 --- a/src/gnome/gnc-plugin-page-register.c +++ b/src/gnome/gnc-plugin-page-register.c @@ -826,10 +826,10 @@ static const gchar *style_names[] = { NULL }; -#define KEY_REGISTER_TYPE "Register Type" -#define KEY_ACCOUNT_NAME "Account Name" -#define KEY_REGISTER_STYLE "Register Style" -#define KEY_DOUBLE_LINE "Double Line Mode" +#define KEY_REGISTER_TYPE "RegisterType" +#define KEY_ACCOUNT_NAME "AccountName" +#define KEY_REGISTER_STYLE "RegisterStyle" +#define KEY_DOUBLE_LINE "DoubleLineMode" #define LABEL_ACCOUNT "Account" #define LABEL_SUBACCOUNT "SubAccount" diff --git a/src/report/report-gnome/gnc-plugin-page-report.c b/src/report/report-gnome/gnc-plugin-page-report.c index 9be89358e5..9921ab5909 100644 --- a/src/report/report-gnome/gnc-plugin-page-report.c +++ b/src/report/report-gnome/gnc-plugin-page-report.c @@ -648,8 +648,8 @@ gnc_plugin_page_report_destroy_widget(GncPluginPage *plugin_page) /** The key name used it the state file for storing the report * options. */ -#define SCHEME_OPTIONS "Scheme Options" -#define SCHEME_OPTIONS_N "Scheme Options %d" +#define SCHEME_OPTIONS "SchemeOptions" +#define SCHEME_OPTIONS_N "SchemeOptions%d" /** Save enough information about this report page that it can be