25 #include <glib/gstdio.h>
35 #include "gnc-pricedb-p.h"
38 #include "SX-book-p.h"
40 #include "TransactionP.h"
42 #include "sixtp-dom-parsers.h"
44 #include "io-gncxml-gen.h"
47 #include "sixtp-parsers.h"
48 #include "sixtp-utils.h"
54 # define fdopen _fdopen
59 # define g_fopen fopen
67 #if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 2)
68 # pragma GCC diagnostic warning "-Wstrict-aliasing"
74 static GHashTable *threads = NULL;
75 G_LOCK_DEFINE_STATIC(threads);
97 #define GNC_V2_STRING "gnc-v2"
99 const gchar *gnc_v2_xml_version_string = GNC_V2_STRING;
100 extern const gchar *gnc_v2_book_version_string;
103 static FILE *try_gz_open (
const char *filename,
const char *perms, gboolean use_gzip,
105 static gboolean is_gzipped_file(
const gchar *name);
106 static gboolean wait_for_gzip(FILE *file);
111 if (data->countCallback)
113 data->countCallback(data, type);
118 clear_up_account_commodity(
122 int (*scu_getter) (
const Account *account),
123 void (*scu_setter) (
Account *account,
int scu))
130 old_scu = scu_getter(act);
148 PWARN(
"unable to find global commodity for %s adding new",
155 if (old_scu != 0 && scu_setter)
156 scu_setter(act, old_scu);
162 clear_up_transaction_commodity(
184 PWARN(
"unable to find global commodity for %s adding new",
206 clear_up_account_commodity(table, act,
211 clear_up_account_commodity(table, act,
218 xaccAccountScrubKvp (act);
226 gnc_book_set_root_account(data->book, act);
233 root = gnc_book_get_root_account(data->book);
238 data->counter.accounts_loaded++;
247 data->counter.books_loaded++;
262 data->counter.commodities_loaded++;
276 clear_up_transaction_commodity(table, trn,
283 data->counter.transactions_loaded++;
292 sxes = gnc_book_get_schedxactions(data->book);
293 gnc_sxes_add_sx(sxes, sx);
294 data->counter.schedXactions_loaded++;
300 add_template_transaction_local(
sixtp_gdv2 *data,
312 for ( n = txd->accts; n; n = n->next )
319 gnc_book_set_template_root(book, (
Account *)n->data);
333 for ( n = txd->transactions; n; n = n->next )
336 add_transaction_local( data, (
Transaction*)n->data );
350 do_counter_cb (
const char *type, gpointer data_p, gpointer be_data_p)
355 g_return_if_fail (type && data && be_data);
356 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
358 if (be_data->ok == TRUE)
361 if (!g_strcmp0 (be_data->tag, data->type_name))
368 gnc_counter_end_handler(gpointer data_for_children,
369 GSList* data_from_children, GSList* sibling_data,
370 gpointer parent_data, gpointer global_data,
371 gpointer *result,
const gchar *tag)
376 xmlNodePtr tree = (xmlNodePtr)data_for_children;
389 g_return_val_if_fail(tree, FALSE);
395 type = (
char*)xmlGetProp(tree, BAD_CAST
"cd:type");
396 strval = dom_tree_to_text(tree);
397 if (!string_to_gint64(strval, &val))
399 PERR (
"string_to_gint64 failed with input: %s",
400 strval ? strval :
"(null)");
403 else if (g_strcmp0(type,
"transaction") == 0)
405 sixdata->counter.transactions_total = val;
407 else if (g_strcmp0(type,
"account") == 0)
409 sixdata->counter.accounts_total = val;
411 else if (g_strcmp0(type,
"book") == 0)
413 sixdata->counter.books_total = val;
415 else if (g_strcmp0(type,
"commodity") == 0)
417 sixdata->counter.commodities_total = val;
419 else if (g_strcmp0(type,
"schedxaction") == 0)
421 sixdata->counter.schedXactions_total = val;
423 else if (g_strcmp0(type,
"budget") == 0)
425 sixdata->counter.budgets_total = val;
427 else if (g_strcmp0(type,
"price") == 0)
429 sixdata->counter.prices_total = val;
440 if (be_data.ok == FALSE)
442 PERR(
"Unknown type: %s", type ? type :
"(null)");
460 gnc_counter_sixtp_parser_create(
void)
462 return sixtp_dom_parser_new(gnc_counter_end_handler, NULL, NULL);
468 DEBUG(
"Transactions: Total: %d, Loaded: %d",
469 data->transactions_total, data->transactions_loaded);
470 DEBUG(
"Accounts: Total: %d, Loaded: %d",
471 data->accounts_total, data->accounts_loaded);
472 DEBUG(
"Books: Total: %d, Loaded: %d",
473 data->books_total, data->books_loaded);
474 DEBUG(
"Commodities: Total: %d, Loaded: %d",
475 data->commodities_total, data->commodities_loaded);
476 DEBUG(
"Scheduled Transactions: Total: %d, Loaded: %d",
477 data->schedXactions_total, data->schedXactions_loaded);
478 DEBUG(
"Budgets: Total: %d, Loaded: %d",
479 data->budgets_total, data->budgets_loaded);
483 file_rw_feedback (
sixtp_gdv2 *gd,
const char *type)
486 int loaded, total, percentage;
488 g_assert(gd != NULL);
489 if (!gd->gui_display_fn)
492 counter = &gd->counter;
493 loaded = counter->transactions_loaded + counter->accounts_loaded +
494 counter->books_loaded + counter->commodities_loaded +
495 counter->schedXactions_loaded + counter->budgets_loaded +
496 counter->prices_loaded;
497 total = counter->transactions_total + counter->accounts_total +
498 counter->books_total + counter->commodities_total +
499 counter->schedXactions_total + counter->budgets_total +
500 counter->prices_total;
504 percentage = (loaded * 100) / total;
505 if (percentage > 100)
522 gd->gui_display_fn(NULL, percentage);
525 static const char *BOOK_TAG =
"gnc:book";
526 static const char *BOOK_ID_TAG =
"book:id";
527 static const char *BOOK_SLOTS_TAG =
"book:slots";
528 static const char *ACCOUNT_TAG =
"gnc:account";
529 static const char *PRICEDB_TAG =
"gnc:pricedb";
530 static const char *COMMODITY_TAG =
"gnc:commodity";
531 static const char *COUNT_DATA_TAG =
"gnc:count-data";
532 static const char *TRANSACTION_TAG =
"gnc:transaction";
533 static const char *SCHEDXACTION_TAG =
"gnc:schedxaction";
534 static const char *TEMPLATE_TRANSACTION_TAG =
"gnc:template-transactions";
535 static const char *BUDGET_TAG =
"gnc:budget";
538 add_item_cb (
const char *type, gpointer data_p, gpointer be_data_p)
543 g_return_if_fail (type && data && be_data);
544 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
549 if (!g_strcmp0 (be_data->tag, data->type_name))
552 (data->add_item)(be_data->gd, be_data->data);
559 book_callback(
const char *tag, gpointer globaldata, gpointer data)
563 if (g_strcmp0(tag, ACCOUNT_TAG) == 0)
565 add_account_local(gd, (
Account*)data);
567 else if (g_strcmp0(tag, PRICEDB_TAG) == 0)
571 else if (g_strcmp0(tag, COMMODITY_TAG) == 0)
575 else if (g_strcmp0(tag, TRANSACTION_TAG) == 0)
579 else if (g_strcmp0(tag, SCHEDXACTION_TAG) == 0)
583 else if (g_strcmp0(tag, TEMPLATE_TRANSACTION_TAG) == 0)
587 else if (g_strcmp0(tag, BUDGET_TAG) == 0)
602 if (be_data.ok == FALSE)
604 PWARN (
"unexpected tag %s", tag);
611 generic_callback(
const char *tag, gpointer globaldata, gpointer data)
615 if (g_strcmp0(tag, BOOK_TAG) == 0)
617 add_book_local(gd, (
QofBook*)data);
618 book_callback(tag, globaldata, data);
623 book_callback(tag, globaldata, data);
629 add_parser_cb (
const char *type, gpointer data_p, gpointer be_data_p)
634 g_return_if_fail (type && data && be_data);
635 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
637 if (be_data->ok == FALSE)
640 if (data->create_parser)
641 if (!sixtp_add_some_sub_parsers(
642 be_data->parser, TRUE,
643 data->type_name, (data->create_parser)(),
649 scrub_cb (
const char *type, gpointer data_p, gpointer be_data_p)
654 g_return_if_fail (type && data && be_data);
655 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
658 (data->scrub)(be_data->book);
665 countCallbackFn countcallback,
670 if (gd == NULL)
return NULL;
673 gd->counter.accounts_loaded = 0;
674 gd->counter.accounts_total = 0;
675 gd->counter.books_loaded = 0;
676 gd->counter.books_total = 0;
677 gd->counter.commodities_loaded = 0;
678 gd->counter.commodities_total = 0;
679 gd->counter.transactions_loaded = 0;
680 gd->counter.transactions_total = 0;
681 gd->counter.prices_loaded = 0;
682 gd->counter.prices_total = 0;
683 gd->counter.schedXactions_loaded = 0;
684 gd->counter.schedXactions_total = 0;
685 gd->counter.budgets_loaded = 0;
686 gd->counter.budgets_total = 0;
687 gd->exporting = exporting;
688 gd->countCallback = countcallback;
689 gd->gui_display_fn = gui_display_fn;
694 qof_session_load_from_xml_file_v2_full(
696 sixtp_push_handler push_handler, gpointer push_user_data,
697 QofBookFileType type)
709 gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage);
711 top_parser = sixtp_new();
712 main_parser = sixtp_new();
713 book_parser = sixtp_new();
715 if (type == GNC_BOOK_XML2_FILE)
716 v2type = g_strdup(GNC_V2_STRING);
718 if (!sixtp_add_some_sub_parsers(
729 if (!sixtp_add_some_sub_parsers(
731 COUNT_DATA_TAG, gnc_counter_sixtp_parser_create(),
732 BOOK_TAG, book_parser,
737 PRICEDB_TAG, gnc_pricedb_sixtp_parser_create(),
738 COMMODITY_TAG, gnc_commodity_sixtp_parser_create(),
739 ACCOUNT_TAG, gnc_account_sixtp_parser_create(),
740 TRANSACTION_TAG, gnc_transaction_sixtp_parser_create(),
741 SCHEDXACTION_TAG, gnc_schedXaction_sixtp_parser_create(),
742 TEMPLATE_TRANSACTION_TAG, gnc_template_transaction_sixtp_parser_create(),
748 if (!sixtp_add_some_sub_parsers(
750 BOOK_ID_TAG, gnc_book_id_sixtp_parser_create(),
751 BOOK_SLOTS_TAG, gnc_book_slots_sixtp_parser_create(),
752 COUNT_DATA_TAG, gnc_counter_sixtp_parser_create(),
753 PRICEDB_TAG, gnc_pricedb_sixtp_parser_create(),
754 COMMODITY_TAG, gnc_commodity_sixtp_parser_create(),
755 ACCOUNT_TAG, gnc_account_sixtp_parser_create(),
756 BUDGET_TAG, gnc_budget_sixtp_parser_create(),
757 TRANSACTION_TAG, gnc_transaction_sixtp_parser_create(),
758 SCHEDXACTION_TAG, gnc_schedXaction_sixtp_parser_create(),
759 TEMPLATE_TRANSACTION_TAG, gnc_template_transaction_sixtp_parser_create(),
766 be_data.parser = book_parser;
768 if (be_data.ok == FALSE)
773 xaccDisableDataScrubbing();
777 gpointer parse_result = NULL;
780 gpdata.cb = generic_callback;
781 gpdata.parsedata = gd;
782 gpdata.bookdata = book;
784 retval = sixtp_parse_push(top_parser, push_handler, push_user_data,
785 NULL, &gpdata, &parse_result);
795 gchar *filename = fbe->fullpath;
797 gboolean is_compressed = is_gzipped_file(filename);
798 file = try_gz_open(filename,
"r", is_compressed, FALSE);
801 PWARN(
"Unable to open file %s", filename);
806 retval = gnc_xml_parse_fd(top_parser, file,
807 generic_callback, gd, book);
816 sixtp_destroy(top_parser);
818 xaccEnableDataScrubbing();
821 debug_print_counter_data(&gd->counter);
824 sixtp_destroy (top_parser);
827 xaccEnableDataScrubbing();
833 memset(&be_data, 0,
sizeof(be_data));
838 root = gnc_book_get_root_account(book);
845 xaccAccountTreeScrubSplits (root);
866 QofBookFileType type)
868 return qof_session_load_from_xml_file_v2_full(fbe, book, NULL, NULL, type);
874 write_counts(FILE* out, ...)
878 gboolean success = TRUE;
881 type = g_strdup (va_arg(ap,
char *));
883 while (success && type)
885 int amount = va_arg(ap,
int);
889 #if GNUCASH_REALLY_BUILD_AN_XML_TREE_ON_OUTPUT
893 val = g_strdup_printf(
"%d", amount);
895 node = xmlNewNode(NULL, BAD_CAST COUNT_DATA_TAG);
901 xmlSetProp(node, BAD_CAST
"cd:type", checked_char_cast (type));
902 xmlNodeAddContent(node, checked_char_cast (val));
906 xmlElemDump(out, NULL, node);
909 if (ferror(out) || fprintf(out,
"\n") < 0)
915 if (fprintf(out,
"<%s %s=\"%s\">%d</%s>\n",
916 COUNT_DATA_TAG,
"cd:type", type, amount, COUNT_DATA_TAG) < 0)
925 type = va_arg(ap,
char *);
933 compare_namespaces(gconstpointer a, gconstpointer b)
935 const gchar *sa = (
const gchar *) a;
936 const gchar *sb = (
const gchar *) b;
937 return(g_strcmp0(sa, sb));
941 compare_commodity_ids(gconstpointer a, gconstpointer b)
951 static gboolean write_template_transaction_data (FILE *out,
QofBook *book,
sixtp_gdv2 *gd);
953 static void write_budget (
QofInstance *ent, gpointer data);
956 write_counts_cb (
const char *type, gpointer data_p, gpointer be_data_p)
961 g_return_if_fail (type && data && be_data);
962 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
965 write_counts (be_data->out, data->type_name,
966 (data->get_count) (be_data->book),
971 write_data_cb (
const char *type, gpointer data_p, gpointer be_data_p)
976 g_return_if_fail (type && data && be_data);
977 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
979 if (data->write && !ferror(be_data->out))
980 (data->write)(be_data->out, be_data->book);
988 #ifdef IMPLEMENT_BOOK_DOM_TREES_LATER
996 node = gnc_book_dom_tree_create(book);
1003 xmlElemDump(out, NULL, node);
1006 if (ferror(out) || fprintf(out,
"\n") < 0)
1014 be_data.book = book;
1016 if (fprintf( out,
"<%s version=\"%s\">\n", BOOK_TAG, gnc_v2_book_version_string) < 0)
1018 if (!write_book_parts (out, book))
1024 if (!write_counts(out,
1033 g_list_length(gnc_book_get_schedxactions(book)->sx_list),
1043 || !write_commodities(out, book, gd)
1044 || !write_pricedb(out, book, gd)
1045 || !write_accounts(out, book, gd)
1046 || !write_transactions(out, book, gd)
1047 || !write_template_transaction_data(out, book, gd)
1048 || !write_schedXactions(out, book, gd))
1053 write_budget, &be_data);
1061 if (fprintf( out,
"</%s>\n", BOOK_TAG ) < 0)
1073 gboolean success = TRUE;
1080 namespaces = g_list_sort(namespaces, compare_namespaces);
1083 for (lp = namespaces; success && lp; lp = lp->next)
1089 comms = g_list_sort(comms, compare_commodity_ids);
1091 for (lp2 = comms; lp2; lp2 = lp2->next)
1093 comnode = gnc_commodity_dom_tree_create(lp2->data);
1094 if (comnode == NULL)
1097 xmlElemDump(out, NULL, comnode);
1098 if (ferror(out) || fprintf(out,
"\n") < 0)
1104 xmlFreeNode(comnode);
1105 gd->counter.commodities_loaded++;
1109 g_list_free (comms);
1112 if (namespaces) g_list_free (namespaces);
1122 xmlOutputBufferPtr outbuf;
1135 if (fprintf( out,
"<%s version=\"%s\">\n", parent->name,
1136 xmlGetProp(parent, BAD_CAST
"version")) < 0)
1141 outbuf = xmlOutputBufferCreateFile(out, NULL);
1144 xmlFreeNode(parent);
1148 for (node = parent->children; node; node = node->next)
1151 xmlOutputBufferWrite(outbuf, 2,
" ");
1152 xmlNodeDumpOutput(outbuf, NULL, node, 1, 1, NULL);
1154 xmlOutputBufferWrite(outbuf, 1,
"\n");
1157 gd->counter.prices_loaded += 1;
1161 xmlOutputBufferClose(outbuf);
1163 if (ferror(out) || fprintf(out,
"</%s>\n", parent->name) < 0)
1165 xmlFreeNode(parent);
1169 xmlFreeNode(parent);
1179 node = gnc_transaction_dom_tree_create(t);
1181 xmlElemDump(be_data->out, NULL, node);
1184 if (ferror(be_data->out) || fprintf(be_data->out,
"\n") < 0)
1187 be_data->gd->counter.transactions_loaded++;
1202 (gpointer) &be_data);
1217 if (fprintf(out,
"<%s>\n", TEMPLATE_TRANSACTION_TAG) < 0
1218 || !write_account_tree(out, ra, gd)
1220 || fprintf(out,
"</%s>\n", TEMPLATE_TRANSACTION_TAG) < 0)
1231 GList *schedXactions;
1235 schedXactions = gnc_book_get_schedxactions(book)->sx_list;
1237 if (schedXactions == NULL)
1242 tmpSX = schedXactions->data;
1243 node = gnc_schedXaction_dom_tree_create( tmpSX );
1244 xmlElemDump( out, NULL, node );
1246 if (ferror(out) || fprintf(out,
"\n") < 0)
1248 gd->counter.schedXactions_loaded++;
1251 while ( (schedXactions = schedXactions->next) );
1264 if (ferror(be->out))
1267 node = gnc_budget_dom_tree_create(bgt);
1268 xmlElemDump( be->out, NULL, node );
1270 if (ferror(be->out) || fprintf(be->out,
"\n") < 0)
1273 be->gd->counter.budgets_loaded++;
1280 g_return_val_if_fail(name_space, FALSE);
1281 return fprintf(out,
"\n xmlns:%s=\"http://www.gnucash.org/XML/%s\"",
1282 name_space, name_space) >= 0;
1286 do_write_namespace_cb (
const char *type, gpointer data_p, gpointer file_p)
1291 g_return_if_fail (type && data && out);
1292 g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
1294 if (data->ns && !ferror(out))
1299 write_v2_header (FILE *out)
1301 if (fprintf(out,
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n") < 0
1302 || fprintf(out,
"<" GNC_V2_STRING) < 0
1325 if (ferror(out) || fprintf(out,
">\n") < 0)
1332 gnc_book_write_to_xml_filehandle_v2(
QofBook *book, FILE *out)
1336 gboolean success = TRUE;
1338 if (!out)
return FALSE;
1340 if (!write_v2_header(out)
1341 || !write_counts(out,
"book", 1, NULL))
1345 gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage);
1346 gd->counter.commodities_total =
1348 gd->counter.accounts_total = 1 +
1351 gd->counter.schedXactions_total =
1352 g_list_length(gnc_book_get_schedxactions(book)->sx_list);
1357 if (!write_book(out, book, gd)
1358 || fprintf(out,
"</" GNC_V2_STRING
">\n\n") < 0)
1375 gboolean success = TRUE;
1377 if (!out)
return FALSE;
1379 root = gnc_book_get_root_account(book);
1385 if (!write_v2_header(out)
1386 || !write_counts(out,
"commodity", ncom,
"account", nacc, NULL))
1389 gd = gnc_sixtp_gdv2_new(book, TRUE, file_rw_feedback, be->percentage);
1390 gd->counter.commodities_total = ncom;
1391 gd->counter.accounts_total = nacc;
1393 if (!write_commodities(out, book, gd)
1394 || !write_accounts(out, book, gd)
1395 || fprintf(out,
"</" GNC_V2_STRING
">\n\n") < 0)
1409 gchar buffer[BUFLEN];
1417 gchar *conv_name = g_win32_locale_filename_from_utf8(params->filename);
1422 g_warning(
"Could not convert '%s' to system codepage",
1425 goto cleanup_gz_thread_func;
1428 if (strchr(params->perms,
'b'))
1429 perms = g_strdup(params->perms);
1431 perms = g_strdup_printf(
"%cb%s", *params->perms, params->perms + 1);
1433 file = gzopen(conv_name, perms);
1438 file = gzopen(params->filename, params->perms);
1443 g_warning(
"Child threads gzopen failed");
1445 goto cleanup_gz_thread_func;
1448 if (params->compress)
1452 bytes = read(params->fd, buffer, BUFLEN);
1455 if (gzwrite(file, buffer, bytes) <= 0)
1458 const gchar *error = gzerror(file, &errnum);
1459 g_warning(
"Could not write the compressed file '%s'. The error is: '%s' (%d)",
1460 params->filename, error, errnum);
1464 else if (bytes == 0)
1470 g_warning(
"Could not read from pipe. The error is '%s' (errno %d)",
1471 g_strerror(errno) ? g_strerror(errno) :
"", errno);
1480 gzval = gzread(file, buffer, BUFLEN);
1489 (params->fd, buffer, gzval) < 0)
1491 g_warning(
"Could not write to pipe. The error is '%s' (%d)",
1492 g_strerror(errno) ? g_strerror(errno) :
"", errno);
1496 else if (gzval == 0)
1503 const gchar *error = gzerror(file, &errnum);
1504 g_warning(
"Could not read from compressed file '%s'. The error is: '%s' (%d)",
1505 params->filename, error, errnum);
1511 if ((gzval = gzclose(file)) != Z_OK)
1513 g_warning(
"Could not close the compressed file '%s' (errnum %d)",
1514 params->filename, gzval);
1518 cleanup_gz_thread_func:
1520 g_free(params->filename);
1521 g_free(params->perms);
1524 return GINT_TO_POINTER(success);
1528 try_gz_open (
const char *filename,
const char *perms, gboolean use_gzip,
1531 if (strstr(filename,
".gz.") != NULL)
1535 return g_fopen(filename, perms);
1540 GError *error = NULL;
1545 if (_pipe(filedes, 4096, _O_BINARY) < 0)
1548 if (pipe(filedes) < 0)
1551 g_warning(
"Pipe call failed. Opening uncompressed file.");
1552 return g_fopen(filename, perms);
1556 params->fd = filedes[compress ? 0 : 1];
1557 params->filename = g_strdup(filename);
1558 params->perms = g_strdup(perms);
1559 params->compress = compress;
1561 #ifndef HAVE_GLIB_2_32
1562 thread = g_thread_create((GThreadFunc) gz_thread_func, params,
1565 thread = g_thread_new(
"xml_thread", (GThreadFunc) gz_thread_func,
1570 g_warning(
"Could not create thread for (de)compression: %s",
1572 g_error_free(error);
1573 g_free(params->filename);
1574 g_free(params->perms);
1579 return g_fopen(filename, perms);
1583 file = fdopen(filedes[1],
"w");
1585 file = fdopen(filedes[0],
"r");
1589 threads = g_hash_table_new(g_direct_hash, g_direct_equal);
1591 g_hash_table_insert(threads, file, thread);
1599 wait_for_gzip(FILE *file)
1601 gboolean retval = TRUE;
1606 GThread *thread = g_hash_table_lookup(threads, file);
1609 g_hash_table_remove(threads, file);
1610 retval = GPOINTER_TO_INT(g_thread_join(thread));
1619 gnc_book_write_to_xml_file_v2(
1621 const char *filename,
1625 gboolean success = TRUE;
1627 out = try_gz_open(filename,
"w", compress, TRUE);
1631 || !gnc_book_write_to_xml_filehandle_v2(book, out)
1632 || !write_emacs_trailer(out))
1636 if (out && fclose(out))
1640 if (out && compress)
1641 if (!wait_for_gzip(out))
1653 gnc_book_write_accounts_to_xml_file_v2(
1656 const char *filename)
1659 gboolean success = TRUE;
1661 out = g_fopen(filename,
"w");
1666 || !write_emacs_trailer(out))
1670 if (out && fclose(out))
1686 is_gzipped_file(
const gchar *name)
1688 unsigned char buf[2];
1689 int fd = g_open(name, O_RDONLY, 0);
1696 if (read(fd, buf, 2) != 2)
1703 if (buf[0] == 037 && buf[1] == 0213)
1714 if (is_gzipped_file(name))
1717 char first_chunk[256];
1722 gchar *conv_name = g_win32_locale_filename_from_utf8(name);
1724 g_warning(
"Could not convert '%s' to system codepage", name);
1727 file = gzopen(conv_name,
"rb");
1732 file = gzopen(name,
"r");
1735 return GNC_BOOK_NOT_OURS;
1737 num_read = gzread(file, first_chunk,
sizeof(first_chunk) - 1);
1741 return GNC_BOOK_NOT_OURS;
1743 return gnc_is_our_first_xml_chunk(first_chunk, with_encoding);
1746 return (gnc_is_our_xml_file(name, with_encoding));
1751 replace_character_references(gchar *
string)
1753 gchar *cursor, *semicolon, *tail;
1756 for (cursor = strstr(
string,
"&#");
1758 cursor = strstr(cursor,
"&#"))
1760 semicolon = strchr(cursor,
';');
1761 if (semicolon && *semicolon)
1766 if (*(cursor + 2) ==
'x')
1768 number = strtol(cursor + 3, &tail, 16);
1772 number = strtol(cursor + 2, &tail, 10);
1774 if (errno || tail != semicolon || number < 0 || number > 255)
1776 PWARN(
"Illegal character reference");
1781 *cursor = (gchar) number;
1783 if (*(semicolon + 1))
1786 tail = g_strdup(semicolon + 1);
1787 strcpy(cursor, tail);
1799 PWARN(
"Unclosed character reference");
1810 g_free(conv->utf8_string);
1816 conv_list_free(GList *conv_list)
1818 g_list_foreach(conv_list, (GFunc) conv_free, NULL);
1819 g_list_free(conv_list);
1830 GHashTable **unique, GHashTable **ambiguous,
1834 GList *iconv_list = NULL, *conv_list = NULL, *iter;
1837 GHashTable *processed = NULL;
1838 gint n_impossible = 0;
1839 GError *error = NULL;
1840 gboolean is_compressed;
1841 gboolean clean_return = FALSE;
1843 is_compressed = is_gzipped_file(filename);
1844 file = try_gz_open(filename,
"r", is_compressed, FALSE);
1847 PWARN(
"Unable to open file %s", filename);
1848 goto cleanup_find_ambs;
1853 ascii->encoding = g_quark_from_string(
"ASCII");
1854 ascii->iconv = g_iconv_open(
"UTF-8",
"ASCII");
1855 if (ascii->iconv == (GIConv) - 1)
1857 PWARN(
"Unable to open ASCII ICONV conversion descriptor");
1858 goto cleanup_find_ambs;
1862 for (iter = encodings; iter; iter = iter->next)
1865 iconv_item->encoding = GPOINTER_TO_UINT (iter->data);
1866 if (iconv_item->encoding == ascii->encoding)
1871 enc = g_quark_to_string(iconv_item->encoding);
1872 iconv_item->iconv = g_iconv_open(
"UTF-8", enc);
1873 if (iconv_item->iconv == (GIConv) - 1)
1875 PWARN(
"Unable to open IConv conversion descriptor for '%s'", enc);
1876 goto cleanup_find_ambs;
1880 iconv_list = g_list_prepend(iconv_list, iconv_item);
1886 *unique = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
1887 (GDestroyNotify) conv_free);
1889 *ambiguous = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
1890 (GDestroyNotify) conv_list_free);
1893 processed = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
1898 gchar line[256], *word, *utf8;
1899 gchar **word_array, **word_cursor;
1902 if (!fgets(line,
sizeof(line) - 1, file))
1910 goto cleanup_find_ambs;
1915 replace_character_references(line);
1916 word_array = g_strsplit_set(line,
"> <", 0);
1919 for (word_cursor = word_array; *word_cursor; word_cursor++)
1921 word = *word_cursor;
1925 utf8 = g_convert_with_iconv(word, -1, ascii->iconv,
1926 NULL, NULL, &error);
1933 g_error_free(error);
1936 if (g_hash_table_lookup_extended(processed, word, NULL, NULL))
1944 for (iter = iconv_list; iter; iter = iter->next)
1946 iconv_item = iter->data;
1947 utf8 = g_convert_with_iconv(word, -1, iconv_item->iconv,
1948 NULL, NULL, &error);
1952 conv->encoding = iconv_item->encoding;
1953 conv->utf8_string = utf8;
1954 conv_list = g_list_prepend(conv_list, conv);
1958 g_error_free(error);
1967 *impossible = g_list_append(*impossible, g_strdup(word));
1972 else if (conv_list->next)
1976 g_hash_table_insert(*ambiguous, g_strdup(word), conv_list);
1980 conv_list_free(conv_list);
1989 g_hash_table_insert(*unique, g_strdup(word), conv);
1995 g_list_free(conv_list);
1998 g_hash_table_insert(processed, g_strdup(word), NULL);
2000 g_strfreev(word_array);
2003 clean_return = TRUE;
2009 for (iter = iconv_list; iter; iter = iter->next)
2017 g_list_free(iconv_list);
2020 g_hash_table_destroy(processed);
2027 wait_for_gzip(file);
2030 return (clean_return) ? n_impossible : -1;
2040 parse_with_subst_push_handler (xmlParserCtxtPtr xml_context,
2043 const gchar *filename;
2045 GIConv ascii = (GIConv) - 1;
2046 GString *output = NULL;
2047 GError *error = NULL;
2048 gboolean is_compressed;
2050 filename = push_data->filename;
2051 is_compressed = is_gzipped_file(filename);
2052 file = try_gz_open(filename,
"r", is_compressed, FALSE);
2055 PWARN(
"Unable to open file %s", filename);
2056 goto cleanup_push_handler;
2059 ascii = g_iconv_open(
"UTF-8",
"ASCII");
2060 if (ascii == (GIConv) - 1)
2062 PWARN(
"Unable to open ASCII ICONV conversion descriptor");
2063 goto cleanup_push_handler;
2069 gchar line[256], *word, *repl, *utf8;
2071 gchar *start, *cursor;
2073 if (!fgets(line,
sizeof(line) - 1, file))
2081 goto cleanup_push_handler;
2085 replace_character_references(line);
2086 output = g_string_new(line);
2089 cursor = output->str;
2094 while (*cursor ==
'>' || *cursor ==
' ' || *cursor ==
'<' ||
2108 while (*cursor && *cursor !=
'>' && *cursor !=
' ' && *cursor !=
'<' &&
2115 utf8 = g_convert_with_iconv(start, len, ascii, NULL, NULL, &error);
2125 g_error_free(error);
2128 word = g_strndup(start, len);
2129 repl = g_hash_table_lookup(push_data->subst, word);
2134 output = g_string_insert(g_string_erase(output, pos, len),
2136 pos += strlen(repl);
2137 cursor = output->str + pos;
2142 goto cleanup_push_handler;
2147 if (xmlParseChunk(xml_context, output->str, output->len, 0) != 0)
2149 goto cleanup_push_handler;
2154 xmlParseChunk(xml_context,
"", 0, 1);
2156 cleanup_push_handler:
2159 g_string_free(output, TRUE);
2160 if (ascii != (GIConv) - 1)
2161 g_iconv_close(ascii);
2166 wait_for_gzip(file);
2177 push_data->filename = fbe->fullpath;
2178 push_data->subst = subst;
2180 success = qof_session_load_from_xml_file_v2_full(
2181 fbe, book, (sixtp_push_handler) parse_with_subst_push_handler,
2182 push_data, GNC_BOOK_XML2_FILE);
2185 qof_instance_set_dirty (QOF_INSTANCE (book));
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
Account * gnc_account_get_parent(const Account *acc)
int xaccAccountTreeForEachTransaction(Account *acc, TransactionCallback proc, void *data)
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
gboolean qof_session_load_from_xml_file_v2(FileBackend *, QofBook *, QofBookFileType)
void xaccTransScrubCurrency(Transaction *trans)
void qof_backend_set_error(QofBackend *be, QofBackendError err)
void gnc_account_append_child(Account *new_parent, Account *child)
gint gnc_account_n_descendants(const Account *account)
gboolean gnc_book_write_accounts_to_xml_filehandle_v2(QofBackend *be, QofBook *book, FILE *fh)
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
int xaccAccountGetCommoditySCUi(const Account *acc)
void xaccAccountTreeScrubCommodities(Account *acc)
gnc_commodity * DxaccAccountGetCurrency(const Account *acc)
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
GNCAccountType xaccAccountGetType(const Account *acc)
void xaccAccountScrubCommodity(Account *account)
gboolean gnc_xml2_parse_with_subst(FileBackend *fbe, QofBook *book, GHashTable *subst)
void xaccLogDisable(void)
#define DEBUG(format, args...)
Account * gnc_book_get_template_root(const QofBook *book)
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
#define PERR(format, args...)
void qof_collection_foreach(const QofCollection *, QofInstanceForeachCB, gpointer user_data)
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
#define PWARN(format, args...)
convert single-entry accounts to clean double-entry
void qof_book_mark_session_saved(QofBook *book)
api for GnuCash version 2 XML-based file format
GList * gnc_commodity_table_get_namespaces(const gnc_commodity_table *table)
guint gnc_pricedb_get_num_prices(GNCPriceDB *db)
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
void(* QofBePercentageFunc)(const char *message, double percent)
DOCUMENT ME!
QofBookFileType gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding)
QofBackendError qof_backend_get_error(QofBackend *be)
void xaccTransCommitEdit(Transaction *trans)
void xaccTransBeginEdit(Transaction *trans)
All type declarations for the whole Gnucash engine.
void xaccAccountSetCommoditySCU(Account *acc, int scu)
CommodityList * gnc_commodity_table_get_commodities(const gnc_commodity_table *table, const char *name_space)
API for the transaction logger.
guint gnc_book_count_transactions(QofBook *book)
gint gnc_xml2_find_ambiguous(const gchar *filename, GList *encodings, GHashTable **unique, GHashTable **ambiguous, GList **impossible)
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
gboolean gnc_xml2_write_namespace_decl(FILE *out, const char *name_space)
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
QofCollection * qof_book_get_collection(const QofBook *, QofIdType)
guint gnc_commodity_table_get_size(const gnc_commodity_table *tbl)
guint qof_collection_count(const QofCollection *col)
void DxaccAccountSetCurrency(Account *acc, gnc_commodity *currency)
QofBackend * qof_book_get_backend(const QofBook *book)
Retrieve the backend used by this book.
void xaccAccountTreeScrubQuoteSources(Account *root, gnc_commodity_table *table)
API for Transactions and Splits (journal entries)
void xaccAccountCommitEdit(Account *acc)
void gnc_commodity_destroy(gnc_commodity *cm)
void run_callback(sixtp_gdv2 *data, const char *type)
const gchar * QofLogModule
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)