mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
James LewisMoss's refactoring of xml writing.
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3579 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
06b7c43a82
commit
5f5661e125
2
AUTHORS
2
AUTHORS
@ -95,7 +95,7 @@ Juan Manuel Garc
|
|||||||
Christopher Molnar <molnarc@mandrakesoft.com> build system patch
|
Christopher Molnar <molnarc@mandrakesoft.com> build system patch
|
||||||
Tim Mooney <mooney@dogbert.cc.ndsu.NoDak.edu> port to alpha-dec-osf4.0f
|
Tim Mooney <mooney@dogbert.cc.ndsu.NoDak.edu> port to alpha-dec-osf4.0f
|
||||||
G. Allen Morris III <gam3@ann.softgams.com> for QIF core dump
|
G. Allen Morris III <gam3@ann.softgams.com> for QIF core dump
|
||||||
James LewisMoss <dres@phoenixdsl.com> design doc patches
|
James LewisMoss <dres@debian.org> design doc patches
|
||||||
Steven Murdoch <sjmurdoch@linuxfan.com> gnc-prices fix for London exchange
|
Steven Murdoch <sjmurdoch@linuxfan.com> gnc-prices fix for London exchange
|
||||||
Brent Neal <brent@baton.phys.lsu.edu> TIAA-CREF support.
|
Brent Neal <brent@baton.phys.lsu.edu> TIAA-CREF support.
|
||||||
Stefan Nobis <stefan-ml@snobis.de> German translation patch
|
Stefan Nobis <stefan-ml@snobis.de> German translation patch
|
||||||
|
1
debian/rules
vendored
1
debian/rules
vendored
@ -77,7 +77,6 @@ binary-arch: build install
|
|||||||
# cp src/.libs/gnucash $(id)/usr/bin/gnucash.debug
|
# cp src/.libs/gnucash $(id)/usr/bin/gnucash.debug
|
||||||
dh_compress
|
dh_compress
|
||||||
dh_fixperms
|
dh_fixperms
|
||||||
dh_suidregister
|
|
||||||
dh_installdeb
|
dh_installdeb
|
||||||
dh_shlibdeps
|
dh_shlibdeps
|
||||||
dh_gencontrol
|
dh_gencontrol
|
||||||
|
@ -5,11 +5,14 @@
|
|||||||
#include "sixtp.h"
|
#include "sixtp.h"
|
||||||
#include "sixtp-utils.h"
|
#include "sixtp-utils.h"
|
||||||
#include "sixtp-parsers.h"
|
#include "sixtp-parsers.h"
|
||||||
|
#include "sixtp-xml-write-utils.h"
|
||||||
|
|
||||||
#include "Account.h"
|
#include "Account.h"
|
||||||
#include "AccountP.h"
|
#include "AccountP.h"
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
|
|
||||||
|
#include "sixtp-writers.h"
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* <account> (parent <ledger-data>)
|
/* <account> (parent <ledger-data>)
|
||||||
|
|
||||||
@ -552,3 +555,94 @@ gnc_account_parser_new(void)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/***********************************************************************/
|
||||||
|
/* write out the xml for each of the fields in an account */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_account_restorer(xmlNodePtr p, Account* a) {
|
||||||
|
xmlNodePtr acct_xml;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(a, FALSE);
|
||||||
|
|
||||||
|
acct_xml = xmlNewTextChild(p, NULL, "account", NULL);
|
||||||
|
g_return_val_if_fail(acct_xml, FALSE);
|
||||||
|
|
||||||
|
acct_xml = xmlNewTextChild(acct_xml, NULL, "restore", NULL);
|
||||||
|
g_return_val_if_fail(acct_xml, FALSE);
|
||||||
|
|
||||||
|
if(!xml_add_str(acct_xml, "name",
|
||||||
|
xaccAccountGetName(a), FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
if(!xml_add_guid(acct_xml, "guid",
|
||||||
|
xaccAccountGetGUID(a)))
|
||||||
|
return(FALSE);
|
||||||
|
if(!xml_add_str(acct_xml, "type",
|
||||||
|
xaccAccountTypeEnumAsString(xaccAccountGetType(a)), FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
if(!xml_add_str(acct_xml, "code",
|
||||||
|
xaccAccountGetCode(a), FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
if(!xml_add_str(acct_xml, "description",
|
||||||
|
xaccAccountGetDescription(a), FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
/* Notes field is now in kvp table. */
|
||||||
|
if(!xml_add_commodity_ref(acct_xml, "currency", xaccAccountGetCurrency(a)))
|
||||||
|
return(FALSE);
|
||||||
|
if(!xml_add_commodity_ref(acct_xml, "security", xaccAccountGetSecurity(a)))
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
if(a->kvp_data) {
|
||||||
|
if(!xml_add_kvp_frame(acct_xml, "slots", a->kvp_data, FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Account *parent = xaccAccountGetParentAccount(a);
|
||||||
|
if(parent) {
|
||||||
|
xmlNodePtr parent_xml = xmlNewTextChild(acct_xml, NULL, "parent", NULL);
|
||||||
|
g_return_val_if_fail(parent_xml, FALSE);
|
||||||
|
if(!xml_add_guid(parent_xml, "guid", xaccAccountGetGUID(parent)))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
AccountGroup *g = xaccAccountGetChildren(a);
|
||||||
|
if(g) {
|
||||||
|
GList *list = xaccGroupGetAccountList (g);
|
||||||
|
GList *node;
|
||||||
|
|
||||||
|
for (node = list; node; node = node->next) {
|
||||||
|
Account *current_acc = node->data;
|
||||||
|
|
||||||
|
if(!xml_add_account_restorer(p, current_acc))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
/* loop over all accounts in the group */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_account_restorers(xmlNodePtr p, AccountGroup *g) {
|
||||||
|
GList *list;
|
||||||
|
GList *node;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(g, FALSE);
|
||||||
|
|
||||||
|
list = xaccGroupGetAccountList (g);
|
||||||
|
|
||||||
|
for (node = list; node; node = node->next) {
|
||||||
|
Account *current_acc = node->data;
|
||||||
|
xml_add_account_restorer(p, current_acc);
|
||||||
|
}
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
@ -220,11 +220,7 @@ xaccAccountEqual(Account *aa, Account *ab, gboolean check_guids) {
|
|||||||
if(!aa) return FALSE;
|
if(!aa) return FALSE;
|
||||||
if(!ab) return FALSE;
|
if(!ab) return FALSE;
|
||||||
|
|
||||||
if(aa->type != ab->type) {
|
if(aa->type != ab->type) return FALSE;
|
||||||
PERR ("Account types don't match (%d != %d)\n",
|
|
||||||
aa->type, ab->type);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(safe_strcmp(aa->accountName, ab->accountName) != 0) return FALSE;
|
if(safe_strcmp(aa->accountName, ab->accountName) != 0) return FALSE;
|
||||||
if(safe_strcmp(aa->accountCode, ab->accountCode) != 0) return FALSE;
|
if(safe_strcmp(aa->accountCode, ab->accountCode) != 0) return FALSE;
|
||||||
@ -233,11 +229,7 @@ xaccAccountEqual(Account *aa, Account *ab, gboolean check_guids) {
|
|||||||
if(!gnc_commodity_equiv(aa->security, ab->security)) return FALSE;
|
if(!gnc_commodity_equiv(aa->security, ab->security)) return FALSE;
|
||||||
|
|
||||||
if(check_guids) {
|
if(check_guids) {
|
||||||
if(!guid_equal(&aa->guid, &ab->guid)) {
|
if(!guid_equal(&aa->guid, &ab->guid)) return FALSE;
|
||||||
PERR ("Account guids don't match for %s ?= %s\n",
|
|
||||||
aa->accountName, ab->accountName);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(kvp_frame_compare(aa->kvp_data, ab->kvp_data) != 0) return FALSE;
|
if(kvp_frame_compare(aa->kvp_data, ab->kvp_data) != 0) return FALSE;
|
||||||
|
@ -6,9 +6,12 @@
|
|||||||
#include "sixtp.h"
|
#include "sixtp.h"
|
||||||
#include "sixtp-utils.h"
|
#include "sixtp-utils.h"
|
||||||
#include "sixtp-parsers.h"
|
#include "sixtp-parsers.h"
|
||||||
|
#include "sixtp-writers.h"
|
||||||
|
#include "sixtp-xml-write-utils.h"
|
||||||
|
|
||||||
#include "gnc-commodity.h"
|
#include "gnc-commodity.h"
|
||||||
#include "gnc-engine.h"
|
#include "gnc-engine.h"
|
||||||
|
#include "gnc-engine-util.h"
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* Commodity restorer.
|
/* Commodity restorer.
|
||||||
@ -358,3 +361,143 @@ generic_gnc_commodity_lookup_parser_new(void)
|
|||||||
|
|
||||||
return(top_level);
|
return(top_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/***********************************************************************/
|
||||||
|
/* WRITING */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_commodity_ref(xmlNodePtr p, const char *tag, const gnc_commodity *c) {
|
||||||
|
xmlNodePtr c_xml = NULL;
|
||||||
|
gboolean ok = FALSE;
|
||||||
|
|
||||||
|
if(p && tag) {
|
||||||
|
if(!c) {
|
||||||
|
ok = TRUE;
|
||||||
|
} else {
|
||||||
|
c_xml= xmlNewTextChild(p, NULL, tag, NULL);
|
||||||
|
if(c_xml) {
|
||||||
|
const gchar *namestr = gnc_commodity_get_namespace(c);
|
||||||
|
if(namestr) {
|
||||||
|
xmlNodePtr namespace_xml = xmlNewTextChild(c_xml, NULL, "space", namestr);
|
||||||
|
if(namespace_xml) {
|
||||||
|
const gchar *idstr = gnc_commodity_get_mnemonic(c);
|
||||||
|
xmlNodePtr id_xml = xmlNewTextChild(c_xml, NULL, "id", idstr);
|
||||||
|
if(id_xml) ok = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ok && c_xml) xmlFreeNode(c_xml);
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_commodity_restorer(xmlNodePtr p, gnc_commodity *c) {
|
||||||
|
xmlNodePtr comm_xml;
|
||||||
|
xmlNodePtr rst_xml;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(c, FALSE);
|
||||||
|
|
||||||
|
comm_xml = xmlNewTextChild(p, NULL, "commodity", NULL);
|
||||||
|
g_return_val_if_fail(comm_xml, FALSE);
|
||||||
|
|
||||||
|
rst_xml = xmlNewTextChild(comm_xml, NULL, "restore", NULL);
|
||||||
|
if(!rst_xml) {
|
||||||
|
xmlFreeNode(comm_xml);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!xml_add_str(rst_xml, "space", gnc_commodity_get_namespace(c), FALSE)) {
|
||||||
|
xmlFreeNode(comm_xml);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
if(!xml_add_str(rst_xml, "id", gnc_commodity_get_mnemonic(c), FALSE)) {
|
||||||
|
xmlFreeNode(comm_xml);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
if(!xml_add_str(rst_xml, "name", gnc_commodity_get_fullname(c), FALSE)) {
|
||||||
|
xmlFreeNode(comm_xml);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
if(!xml_add_str(rst_xml, "xcode", gnc_commodity_get_exchange_code(c), FALSE)) {
|
||||||
|
xmlFreeNode(comm_xml);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
if(!xml_add_gint64(rst_xml, "fraction", gnc_commodity_get_fraction(c))) {
|
||||||
|
xmlFreeNode(comm_xml);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_namespaces(gconstpointer a, gconstpointer b) {
|
||||||
|
const gchar *sa = (const gchar *) a;
|
||||||
|
const gchar *sb = (const gchar *) b;
|
||||||
|
return(safe_strcmp(sa, sb));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_commodity_ids(gconstpointer a, gconstpointer b) {
|
||||||
|
const gnc_commodity *ca = (const gnc_commodity *) a;
|
||||||
|
const gnc_commodity *cb = (const gnc_commodity *) b;
|
||||||
|
return(safe_strcmp(gnc_commodity_get_mnemonic(ca),
|
||||||
|
gnc_commodity_get_mnemonic(cb)));
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_commodity_restorers(xmlNodePtr p) {
|
||||||
|
gnc_commodity_table *commodities;
|
||||||
|
GList *namespaces;
|
||||||
|
GList *lp;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
|
||||||
|
commodities = gnc_engine_commodities();
|
||||||
|
g_return_val_if_fail(commodities, FALSE);
|
||||||
|
|
||||||
|
namespaces = g_list_sort(gnc_commodity_table_get_namespaces(commodities),
|
||||||
|
compare_namespaces);
|
||||||
|
|
||||||
|
|
||||||
|
for(lp = namespaces; lp; lp = lp->next) {
|
||||||
|
gchar *space;
|
||||||
|
|
||||||
|
if(!lp->data) {
|
||||||
|
g_list_free (namespaces);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
space = (gchar *) lp->data;
|
||||||
|
if(strcmp(GNC_COMMODITY_NS_ISO, space) != 0) {
|
||||||
|
GList *comms = gnc_commodity_table_get_commodities(commodities, space);
|
||||||
|
GList *lp2;
|
||||||
|
|
||||||
|
comms = g_list_sort(comms, compare_commodity_ids);
|
||||||
|
|
||||||
|
for(lp2 = comms; lp2; lp2 = lp2->next) {
|
||||||
|
gnc_commodity *com = (gnc_commodity *) lp2->data;
|
||||||
|
|
||||||
|
if(!xml_add_commodity_restorer(p, com)) {
|
||||||
|
g_list_free (comms);
|
||||||
|
g_list_free (namespaces);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (comms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (namespaces);
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@ libgncengine_la_SOURCES = \
|
|||||||
sixtp-kvp-parser.c \
|
sixtp-kvp-parser.c \
|
||||||
sixtp-stack.c \
|
sixtp-stack.c \
|
||||||
sixtp-utils.c \
|
sixtp-utils.c \
|
||||||
|
sixtp-xml-write-utils.c \
|
||||||
sixtp.c \
|
sixtp.c \
|
||||||
Account-xml-parser-v1.c \
|
Account-xml-parser-v1.c \
|
||||||
Commodity-xml-parser-v1.c \
|
Commodity-xml-parser-v1.c \
|
||||||
@ -78,7 +79,9 @@ noinst_HEADERS = \
|
|||||||
gnc-event-p.h \
|
gnc-event-p.h \
|
||||||
gnc-numeric.h \
|
gnc-numeric.h \
|
||||||
sixtp-parsers.h \
|
sixtp-parsers.h \
|
||||||
|
sixtp-writers.h \
|
||||||
sixtp-stack.h \
|
sixtp-stack.h \
|
||||||
|
sixtp-xml-write-utils.h \
|
||||||
sixtp.h
|
sixtp.h
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
@ -5,14 +5,13 @@
|
|||||||
#include "sixtp.h"
|
#include "sixtp.h"
|
||||||
#include "sixtp-utils.h"
|
#include "sixtp-utils.h"
|
||||||
#include "sixtp-parsers.h"
|
#include "sixtp-parsers.h"
|
||||||
|
#include "sixtp-xml-write-utils.h"
|
||||||
|
#include "gnc-engine-util.h"
|
||||||
|
|
||||||
#include "Query.h"
|
#include "Query.h"
|
||||||
|
|
||||||
/****************************************************************************/
|
static short module = MOD_IO;
|
||||||
/* ================================================================= */
|
|
||||||
/* ================================================================= */
|
|
||||||
/* ================================================================= */
|
|
||||||
/* ================================================================= */
|
|
||||||
/* <query-server> (parent <gnc-data>)
|
/* <query-server> (parent <gnc-data>)
|
||||||
|
|
||||||
On failure or on normal cleanup, the query will be killed,
|
On failure or on normal cleanup, the query will be killed,
|
||||||
@ -532,3 +531,161 @@ query_server_parser_new (void)
|
|||||||
|
|
||||||
return(top_level);
|
return(top_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/***********************************************************************/
|
||||||
|
/* WRITING */
|
||||||
|
/* push query terms into xml */
|
||||||
|
/* XXX hack alert not all predicates currently implemented */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_qterm_restorer(xmlNodePtr qxml, QueryTerm *qt)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
xmlNodePtr p = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail(qxml, FALSE);
|
||||||
|
g_return_val_if_fail(qt, FALSE);
|
||||||
|
|
||||||
|
/* we set the predicates names based on the info they record */
|
||||||
|
switch (qt->data.base.term_type) {
|
||||||
|
case PR_ACCOUNT:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "account-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_ACTION:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "action-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_AMOUNT:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "amount-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_BALANCE:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "balance-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_CLEARED:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "cleared-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_DATE:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "date-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_DESC:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "description-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_MEMO:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "memo-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_NUM:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "num-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_PRICE:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "price-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_SHRS:
|
||||||
|
p = xmlNewTextChild(qxml, NULL, "shares-pred", NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PR_MISC:
|
||||||
|
PERR ("Misc terms are not transmittable");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if (!p) return (FALSE);
|
||||||
|
|
||||||
|
rc = xml_add_gint32(p, "sense", qt->data.base.sense);
|
||||||
|
if (!rc) return(FALSE);
|
||||||
|
|
||||||
|
|
||||||
|
/* however, many of the types share a generic structure. */
|
||||||
|
switch (qt->data.type) {
|
||||||
|
case PD_ACCOUNT:
|
||||||
|
PERR ("account query unimplemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PD_AMOUNT:
|
||||||
|
PERR ("amount query unimplemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PD_BALANCE:
|
||||||
|
PERR ("balance query unimplemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PD_CLEARED:
|
||||||
|
PERR ("cleared query unimplemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PD_DATE:
|
||||||
|
xml_add_gint32(p, "use-start", qt->data.date.use_start);
|
||||||
|
xml_add_gint32(p, "use-end", qt->data.date.use_end);
|
||||||
|
if (qt->data.date.use_start) {
|
||||||
|
xml_add_editable_timespec(p, "start-date",
|
||||||
|
&(qt->data.date.start), FALSE);
|
||||||
|
}
|
||||||
|
if (qt->data.date.use_end) {
|
||||||
|
xml_add_editable_timespec(p, "end-date",
|
||||||
|
&(qt->data.date.end), FALSE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PD_STRING:
|
||||||
|
xml_add_gint32(p, "case-sens", qt->data.str.case_sens);
|
||||||
|
xml_add_gint32(p, "use-regexp", qt->data.str.use_regexp);
|
||||||
|
xml_add_str(p, "matchstring", qt->data.str.matchstring, TRUE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PD_MISC:
|
||||||
|
PERR ("Must not happen");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
/* loop over all terms in the query */
|
||||||
|
/* XXX hack alert -- need to also send max-terms, sort-order,
|
||||||
|
* and other mis query elements */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_query_restorers(xmlNodePtr p, Query *q)
|
||||||
|
{
|
||||||
|
xmlNodePtr qxml, restore_xml, and_xml;
|
||||||
|
GList *aterms, *oterms;
|
||||||
|
GList *anode, *onode;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(q, FALSE);
|
||||||
|
|
||||||
|
oterms = xaccQueryGetTerms (q);
|
||||||
|
|
||||||
|
/* write the nested <query> <restore> */
|
||||||
|
qxml = xmlNewTextChild(p, NULL, "query", NULL);
|
||||||
|
g_return_val_if_fail(qxml, FALSE);
|
||||||
|
|
||||||
|
restore_xml = xmlNewTextChild(qxml, NULL, "restore", NULL);
|
||||||
|
g_return_val_if_fail(restore_xml, FALSE);
|
||||||
|
|
||||||
|
for (onode = oterms; onode; onode = onode->next) {
|
||||||
|
aterms = onode->data;
|
||||||
|
and_xml = xmlNewTextChild(restore_xml, NULL, "and-terms", NULL);
|
||||||
|
g_return_val_if_fail(and_xml, FALSE);
|
||||||
|
|
||||||
|
for (anode = aterms; anode; anode = anode->next) {
|
||||||
|
QueryTerm *qt = anode->data;
|
||||||
|
xml_add_qterm_restorer(and_xml, qt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "sixtp.h"
|
#include "sixtp.h"
|
||||||
#include "sixtp-utils.h"
|
#include "sixtp-utils.h"
|
||||||
#include "sixtp-parsers.h"
|
#include "sixtp-parsers.h"
|
||||||
|
#include "sixtp-xml-write-utils.h"
|
||||||
|
|
||||||
#include "Transaction.h"
|
#include "Transaction.h"
|
||||||
#include "TransactionP.h"
|
#include "TransactionP.h"
|
||||||
@ -834,3 +835,136 @@ gnc_transaction_parser_new(void)
|
|||||||
|
|
||||||
return(top_level);
|
return(top_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/***********************************************************************/
|
||||||
|
/* WRITING */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_transaction_split(xmlNodePtr p, Split* s) {
|
||||||
|
xmlNodePtr split_xml;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(s, FALSE);
|
||||||
|
|
||||||
|
split_xml = xmlNewTextChild(p, NULL, "split", NULL);
|
||||||
|
g_return_val_if_fail(split_xml, FALSE);
|
||||||
|
|
||||||
|
if(!xml_add_guid(split_xml, "guid", xaccSplitGetGUID(s)))
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
if(!xml_add_str(split_xml, "memo", xaccSplitGetMemo(s), FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
if(!xml_add_str(split_xml, "action", xaccSplitGetAction(s), FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
/* reconcile-state */
|
||||||
|
{
|
||||||
|
char state = xaccSplitGetReconcile(s);
|
||||||
|
if(!xml_add_character(split_xml, "reconcile-state", state))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* reconcile-date */
|
||||||
|
Timespec ts;
|
||||||
|
xaccSplitGetDateReconciledTS(s, &ts);
|
||||||
|
if(!xml_add_editable_timespec(split_xml, "reconcile-date", &ts, FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* share-amount */
|
||||||
|
if(!xml_add_gnc_numeric(split_xml, "value", xaccSplitGetValue(s)))
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
/* share-price */
|
||||||
|
if(!xml_add_gnc_numeric(split_xml, "quantity", xaccSplitGetShareAmount(s)))
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
/* account */
|
||||||
|
{
|
||||||
|
Account *acct = xaccSplitGetAccount(s);
|
||||||
|
if(acct) {
|
||||||
|
if(!xml_add_guid(split_xml, "account", xaccAccountGetGUID(acct)))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s->kvp_data) {
|
||||||
|
if(!xml_add_kvp_frame(split_xml, "slots", s->kvp_data, FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_txn_restore(xmlNodePtr p, Transaction* t) {
|
||||||
|
|
||||||
|
xmlNodePtr txn_xml;
|
||||||
|
xmlNodePtr restore_xml;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(t, FALSE);
|
||||||
|
|
||||||
|
txn_xml = xmlNewTextChild(p, NULL, "transaction", NULL);
|
||||||
|
g_return_val_if_fail(txn_xml, FALSE);
|
||||||
|
|
||||||
|
restore_xml = xmlNewTextChild(txn_xml, NULL, "restore", NULL);
|
||||||
|
g_return_val_if_fail(restore_xml, FALSE);
|
||||||
|
|
||||||
|
if(!xml_add_guid(restore_xml, "guid", xaccTransGetGUID(t)))
|
||||||
|
return(FALSE);
|
||||||
|
if(!xml_add_str(restore_xml, "num", xaccTransGetNum(t), FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
{
|
||||||
|
Timespec ts;
|
||||||
|
xaccTransGetDatePostedTS(t, &ts);
|
||||||
|
if(!xml_add_editable_timespec(restore_xml, "date-posted", &ts, FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Timespec ts;
|
||||||
|
xaccTransGetDateEnteredTS(t, &ts);
|
||||||
|
if(!xml_add_editable_timespec(restore_xml, "date-entered", &ts, FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
if(!xml_add_str(restore_xml, "description", xaccTransGetDescription(t), FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
|
||||||
|
if(t->kvp_data) {
|
||||||
|
if(!xml_add_kvp_frame(restore_xml, "slots", t->kvp_data, FALSE))
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
guint32 n = 0;
|
||||||
|
Split *s = xaccTransGetSplit(t, n);
|
||||||
|
|
||||||
|
while(s) {
|
||||||
|
if(!xml_add_transaction_split(restore_xml, s)) return(FALSE);
|
||||||
|
n++;
|
||||||
|
s = xaccTransGetSplit(t, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_txn_restore_adapter(Transaction *t, gpointer data) {
|
||||||
|
xmlNodePtr xml_node = (xmlNodePtr) data;
|
||||||
|
return(xml_add_txn_restore(xml_node, t));
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_txn_and_split_restorers(xmlNodePtr p, AccountGroup *g) {
|
||||||
|
return(xaccGroupForEachTransaction(g,
|
||||||
|
xml_add_txn_restore_adapter,
|
||||||
|
(gpointer) p));
|
||||||
|
}
|
||||||
|
@ -88,6 +88,7 @@
|
|||||||
#include "gnc-engine.h"
|
#include "gnc-engine.h"
|
||||||
#include "gnc-engine-util.h"
|
#include "gnc-engine-util.h"
|
||||||
|
|
||||||
|
#include "sixtp-writers.h"
|
||||||
#include "io-gncxml.h"
|
#include "io-gncxml.h"
|
||||||
|
|
||||||
#include "AccountP.h" /* just for kvp_data */
|
#include "AccountP.h" /* just for kvp_data */
|
||||||
@ -107,962 +108,6 @@ static const gchar *gncxml_emacs_trailer =
|
|||||||
"<!-- mode: xml -->\n"
|
"<!-- mode: xml -->\n"
|
||||||
"<!-- End: -->\n";
|
"<!-- End: -->\n";
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_str(xmlNodePtr p, const char *tag, const char *str,
|
|
||||||
gboolean include_if_empty) {
|
|
||||||
xmlNodePtr child;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
if(!str && !include_if_empty) return(TRUE);
|
|
||||||
if((strlen(str) == 0) && !include_if_empty) return(TRUE);
|
|
||||||
|
|
||||||
child = xmlNewTextChild(p, NULL, tag, str);
|
|
||||||
g_return_val_if_fail(child, FALSE);
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_character(xmlNodePtr p, const char *tag, const char c) {
|
|
||||||
char str[2];
|
|
||||||
str[0] = c;
|
|
||||||
str[1] = '\0';
|
|
||||||
return(xml_add_str(p, tag, str, FALSE));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_gint64(xmlNodePtr p, const char *tag, const gint64 value) {
|
|
||||||
xmlNodePtr val_xml;
|
|
||||||
char num_string[22];
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
|
|
||||||
g_snprintf(num_string, sizeof (num_string), "%lld", value);
|
|
||||||
|
|
||||||
val_xml = xmlNewTextChild(p, NULL, tag, num_string);
|
|
||||||
g_return_val_if_fail(val_xml, FALSE);
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_gint32(xmlNodePtr p, const char *tag, const gint32 value) {
|
|
||||||
xmlNodePtr val_xml;
|
|
||||||
char num_string[22];
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
|
|
||||||
g_snprintf(num_string, sizeof (num_string), "%d", value);
|
|
||||||
|
|
||||||
val_xml = xmlNewTextChild(p, NULL, tag, num_string);
|
|
||||||
g_return_val_if_fail(val_xml, FALSE);
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
/*
|
|
||||||
RLB writes:
|
|
||||||
We have to use guile because AFAICT, libc, and C in general isn't
|
|
||||||
smart enough to actually parse it's own output, especially not
|
|
||||||
portably (big surprise).
|
|
||||||
|
|
||||||
Linas writes:
|
|
||||||
I don't understand the claim; I'm just going to use
|
|
||||||
atof or strtod to accomplish this.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_double(xmlNodePtr p, const char *tag, const double value)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_GUILE_FOR_DOUBLE_CONVERSION
|
|
||||||
{
|
|
||||||
/* FIXME: NOT THREAD SAFE - USES STATIC DATA */
|
|
||||||
static SCM number_to_string;
|
|
||||||
static gboolean ready = FALSE;
|
|
||||||
const char *numstr;
|
|
||||||
|
|
||||||
if(!ready) {
|
|
||||||
number_to_string = gh_eval_str("number->string");
|
|
||||||
scm_protect_object(number_to_string);
|
|
||||||
ready = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
numstr = gh_scm2newstr(gh_call1(number_to_string, gh_double2scm(value)),
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if(!numstr) {
|
|
||||||
return(FALSE);
|
|
||||||
} else {
|
|
||||||
xmlNodePtr child = xmlNewTextChild(p, NULL, tag, numstr);
|
|
||||||
free((void *) numstr);
|
|
||||||
g_return_val_if_fail(child, FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* don't USE_GUILE_FOR_DOUBLE_CONVERSION */
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
char prtbuf[80];
|
|
||||||
xmlNodePtr child;
|
|
||||||
|
|
||||||
/* we're just going to use plain-old libc for the double conversion.
|
|
||||||
* There was some question as to whether libc is accurate enough
|
|
||||||
* in its printf function for doubles, but I don't understand
|
|
||||||
* how it couldn't be ...
|
|
||||||
*/
|
|
||||||
len = snprintf (prtbuf, 80, "%24.18g", value);
|
|
||||||
if (80 <=len) return (FALSE);
|
|
||||||
|
|
||||||
child = xmlNewTextChild(p, NULL, tag, prtbuf);
|
|
||||||
g_return_val_if_fail(child, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* USE_GUILE_FOR_DOUBLE_CONVERSION */
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_gnc_numeric(xmlNodePtr p, const char *tag, const gnc_numeric n) {
|
|
||||||
char *numstr;
|
|
||||||
xmlNodePtr child;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
|
|
||||||
/* fprintf(stderr, "WRITE GNUM S: %lld/%lld -> ", n.num, n.denom); */
|
|
||||||
|
|
||||||
numstr = gnc_numeric_to_string(n);
|
|
||||||
g_return_val_if_fail(numstr, FALSE);
|
|
||||||
|
|
||||||
/* fprintf(stderr, "%s\n", numstr); */
|
|
||||||
|
|
||||||
child = xmlNewTextChild(p, NULL, tag, numstr);
|
|
||||||
g_free(numstr); numstr = FALSE;
|
|
||||||
g_return_val_if_fail(child, FALSE);
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_guid(xmlNodePtr p, const char *tag, const GUID *guid) {
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
g_return_val_if_fail(guid, FALSE);
|
|
||||||
|
|
||||||
{
|
|
||||||
const char *guidstr;
|
|
||||||
xmlNodePtr child;
|
|
||||||
|
|
||||||
if(!guid) {
|
|
||||||
guidstr = NULL;
|
|
||||||
} else {
|
|
||||||
guidstr = guid_to_string(guid);
|
|
||||||
g_return_val_if_fail(guidstr, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
child = xmlNewTextChild(p, NULL, tag, guidstr);
|
|
||||||
g_return_val_if_fail(child, FALSE);
|
|
||||||
if(guidstr) free((void *) guidstr);
|
|
||||||
}
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_editable_timespec(xmlNodePtr p,
|
|
||||||
const char *tag,
|
|
||||||
const Timespec *ts,
|
|
||||||
gboolean include_if_zero) {
|
|
||||||
xmlNodePtr timespec_xml;
|
|
||||||
xmlNodePtr secs_xml;
|
|
||||||
size_t num_written;
|
|
||||||
struct tm parsed_time;
|
|
||||||
time_t tmp_timet;
|
|
||||||
char secs_str[512]; /* This should be way bigger than we need.
|
|
||||||
Still, it's bogus, we ought to have
|
|
||||||
astrftime... */
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
g_return_val_if_fail(ts, FALSE);
|
|
||||||
if(!include_if_zero && (ts->tv_sec == 0) && (ts->tv_nsec == 0)) return TRUE;
|
|
||||||
|
|
||||||
tmp_timet = ts->tv_sec;
|
|
||||||
if(!localtime_r(&tmp_timet, &parsed_time)) return(FALSE);
|
|
||||||
|
|
||||||
num_written = strftime(secs_str, sizeof(secs_str),
|
|
||||||
"%Y-%m-%d %H:%M:%S %z",
|
|
||||||
&parsed_time);
|
|
||||||
if(num_written == 0) return(FALSE);
|
|
||||||
|
|
||||||
timespec_xml= xmlNewTextChild(p, NULL, tag, NULL);
|
|
||||||
g_return_val_if_fail(timespec_xml, FALSE);
|
|
||||||
|
|
||||||
secs_xml = xmlNewTextChild(timespec_xml, NULL, "s", secs_str);
|
|
||||||
g_return_val_if_fail(secs_xml, FALSE);
|
|
||||||
|
|
||||||
if(ts->tv_nsec) {
|
|
||||||
xmlNodePtr nsec_xml;
|
|
||||||
char num_string[22];
|
|
||||||
|
|
||||||
g_snprintf(num_string, sizeof (num_string), "%ld", ts->tv_nsec);
|
|
||||||
|
|
||||||
nsec_xml = xmlNewTextChild(timespec_xml, NULL, "ns", num_string);
|
|
||||||
g_return_val_if_fail(nsec_xml, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_commodity_ref(xmlNodePtr p, const char *tag, const gnc_commodity *c) {
|
|
||||||
xmlNodePtr c_xml = NULL;
|
|
||||||
gboolean ok = FALSE;
|
|
||||||
|
|
||||||
if(p && tag) {
|
|
||||||
if(!c) {
|
|
||||||
ok = TRUE;
|
|
||||||
} else {
|
|
||||||
c_xml= xmlNewTextChild(p, NULL, tag, NULL);
|
|
||||||
if(c_xml) {
|
|
||||||
const gchar *namestr = gnc_commodity_get_namespace(c);
|
|
||||||
if(namestr) {
|
|
||||||
xmlNodePtr namespace_xml = xmlNewTextChild(c_xml, NULL, "space", namestr);
|
|
||||||
if(namespace_xml) {
|
|
||||||
const gchar *idstr = gnc_commodity_get_mnemonic(c);
|
|
||||||
xmlNodePtr id_xml = xmlNewTextChild(c_xml, NULL, "id", idstr);
|
|
||||||
if(id_xml) ok = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ok && c_xml) xmlFreeNode(c_xml);
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_commodity_restorer(xmlNodePtr p, gnc_commodity *c) {
|
|
||||||
xmlNodePtr comm_xml;
|
|
||||||
xmlNodePtr rst_xml;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(c, FALSE);
|
|
||||||
|
|
||||||
comm_xml = xmlNewTextChild(p, NULL, "commodity", NULL);
|
|
||||||
g_return_val_if_fail(comm_xml, FALSE);
|
|
||||||
|
|
||||||
rst_xml = xmlNewTextChild(comm_xml, NULL, "restore", NULL);
|
|
||||||
if(!rst_xml) {
|
|
||||||
xmlFreeNode(comm_xml);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!xml_add_str(rst_xml, "space", gnc_commodity_get_namespace(c), FALSE)) {
|
|
||||||
xmlFreeNode(comm_xml);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
if(!xml_add_str(rst_xml, "id", gnc_commodity_get_mnemonic(c), FALSE)) {
|
|
||||||
xmlFreeNode(comm_xml);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
if(!xml_add_str(rst_xml, "name", gnc_commodity_get_fullname(c), FALSE)) {
|
|
||||||
xmlFreeNode(comm_xml);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
if(!xml_add_str(rst_xml, "xcode", gnc_commodity_get_exchange_code(c), FALSE)) {
|
|
||||||
xmlFreeNode(comm_xml);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
if(!xml_add_gint64(rst_xml, "fraction", gnc_commodity_get_fraction(c))) {
|
|
||||||
xmlFreeNode(comm_xml);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gint
|
|
||||||
compare_namespaces(gconstpointer a, gconstpointer b) {
|
|
||||||
const gchar *sa = (const gchar *) a;
|
|
||||||
const gchar *sb = (const gchar *) b;
|
|
||||||
return(safe_strcmp(sa, sb));
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
compare_commodity_ids(gconstpointer a, gconstpointer b) {
|
|
||||||
const gnc_commodity *ca = (const gnc_commodity *) a;
|
|
||||||
const gnc_commodity *cb = (const gnc_commodity *) b;
|
|
||||||
return(safe_strcmp(gnc_commodity_get_mnemonic(ca),
|
|
||||||
gnc_commodity_get_mnemonic(cb)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_commodity_restorers(xmlNodePtr p) {
|
|
||||||
gnc_commodity_table *commodities;
|
|
||||||
GList *namespaces;
|
|
||||||
GList *lp;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
|
|
||||||
commodities = gnc_engine_commodities();
|
|
||||||
g_return_val_if_fail(commodities, FALSE);
|
|
||||||
|
|
||||||
namespaces = g_list_sort(gnc_commodity_table_get_namespaces(commodities),
|
|
||||||
compare_namespaces);
|
|
||||||
|
|
||||||
|
|
||||||
for(lp = namespaces; lp; lp = lp->next) {
|
|
||||||
gchar *space;
|
|
||||||
|
|
||||||
if(!lp->data) {
|
|
||||||
g_list_free (namespaces);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
space = (gchar *) lp->data;
|
|
||||||
if(strcmp(GNC_COMMODITY_NS_ISO, space) != 0) {
|
|
||||||
GList *comms = gnc_commodity_table_get_commodities(commodities, space);
|
|
||||||
GList *lp2;
|
|
||||||
|
|
||||||
comms = g_list_sort(comms, compare_commodity_ids);
|
|
||||||
|
|
||||||
for(lp2 = comms; lp2; lp2 = lp2->next) {
|
|
||||||
gnc_commodity *com = (gnc_commodity *) lp2->data;
|
|
||||||
|
|
||||||
if(!xml_add_commodity_restorer(p, com)) {
|
|
||||||
g_list_free (comms);
|
|
||||||
g_list_free (namespaces);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free (comms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free (namespaces);
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_binary(xmlNodePtr p,
|
|
||||||
const char *tag,
|
|
||||||
const gchar *format,
|
|
||||||
const void *data,
|
|
||||||
guint32 size)
|
|
||||||
{
|
|
||||||
|
|
||||||
xmlNodePtr value_xml;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
g_return_val_if_fail(format, FALSE);
|
|
||||||
g_return_val_if_fail(data, FALSE);
|
|
||||||
|
|
||||||
value_xml = xmlNewTextChild(p, NULL, tag, NULL);
|
|
||||||
g_return_val_if_fail(value_xml, FALSE);
|
|
||||||
|
|
||||||
if(size == 0) return(TRUE);
|
|
||||||
|
|
||||||
if(0 == strcmp(format, "hex")) {
|
|
||||||
/* Write out the chars as hex, buffering them in max 64 character
|
|
||||||
lines. I was going to use xmlNewTextChild, and xmlTextConcat,
|
|
||||||
but that doesn't seem to work, and looking at the source,
|
|
||||||
xmlNewTextChild doesn't set the node type to a type that
|
|
||||||
xmlTextConcat will recognize and allow. */
|
|
||||||
|
|
||||||
const guint max_line_len = 64;
|
|
||||||
xmlNodePtr data_xml = NULL;
|
|
||||||
GString *output;
|
|
||||||
guint32 i;
|
|
||||||
|
|
||||||
output = g_string_sized_new(max_line_len + 2);
|
|
||||||
|
|
||||||
for(i = 0; i < size; i++) {
|
|
||||||
g_string_sprintfa(output, "%x", (int) (((char *) data)[i]));
|
|
||||||
if(((i + 1) % max_line_len) == 0) {
|
|
||||||
data_xml = xmlNewTextChild(value_xml, NULL, "hex", output->str);
|
|
||||||
if(!data_xml) {
|
|
||||||
return(FALSE);
|
|
||||||
g_string_free(output, TRUE);
|
|
||||||
}
|
|
||||||
g_string_truncate(output, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strlen(output->str) > 0) {
|
|
||||||
data_xml = xmlNewTextChild(value_xml, NULL, "hex", output->str);
|
|
||||||
if(!data_xml) {
|
|
||||||
g_string_free(output, TRUE);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_string_free(output, TRUE);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
PERR("unknown output format %s.\n", format);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean xml_add_kvp_value(xmlNodePtr p, kvp_value *val);
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_kvp_glist(xmlNodePtr p, const char *tag, GList *lst) {
|
|
||||||
xmlNodePtr list_xml;
|
|
||||||
GList *cursor;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
g_return_val_if_fail(lst, FALSE);
|
|
||||||
|
|
||||||
list_xml = xmlNewTextChild(p, NULL, tag, NULL);
|
|
||||||
g_return_val_if_fail(list_xml, FALSE);
|
|
||||||
|
|
||||||
for(cursor = lst; cursor; cursor = cursor->next) {
|
|
||||||
kvp_value * val = (kvp_value *) cursor->data;
|
|
||||||
if(!xml_add_kvp_value(list_xml, val)) {
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_kvp_frame(xmlNodePtr p, const char *tag,
|
|
||||||
const kvp_frame *kvpf,
|
|
||||||
gboolean add_if_empty);
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_kvp_value(xmlNodePtr p, kvp_value *val) {
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(val, FALSE);
|
|
||||||
|
|
||||||
switch(kvp_value_get_type(val)) {
|
|
||||||
case KVP_TYPE_GINT64:
|
|
||||||
return(xml_add_gint64(p, "gint64", kvp_value_get_gint64(val)));
|
|
||||||
break;
|
|
||||||
case KVP_TYPE_DOUBLE:
|
|
||||||
return(xml_add_double(p, "double", kvp_value_get_double(val)));
|
|
||||||
break;
|
|
||||||
case KVP_TYPE_NUMERIC:
|
|
||||||
return(xml_add_gnc_numeric(p, "numeric", kvp_value_get_numeric(val)));
|
|
||||||
break;
|
|
||||||
case KVP_TYPE_STRING:
|
|
||||||
return(xml_add_str(p, "string", kvp_value_get_string(val), TRUE));
|
|
||||||
break;
|
|
||||||
case KVP_TYPE_GUID:
|
|
||||||
return(xml_add_guid(p, "guid", kvp_value_get_guid(val)));
|
|
||||||
break;
|
|
||||||
case KVP_TYPE_BINARY:
|
|
||||||
{
|
|
||||||
guint64 size;
|
|
||||||
void *binary_data = kvp_value_get_binary(val, &size);
|
|
||||||
g_return_val_if_fail(binary_data, FALSE);
|
|
||||||
return(xml_add_binary(p, "binary", "hex", binary_data, size));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KVP_TYPE_GLIST:
|
|
||||||
return(xml_add_kvp_glist(p, "glist", kvp_value_get_glist(val)));
|
|
||||||
break;
|
|
||||||
case KVP_TYPE_FRAME:
|
|
||||||
return(xml_add_kvp_frame(p, "frame", kvp_value_get_frame(val), TRUE));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return(FALSE);
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_kvp_slot(xmlNodePtr p, const char *key, kvp_value *val) {
|
|
||||||
xmlNodePtr slot_xml;
|
|
||||||
xmlNodePtr key_xml;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(key, FALSE);
|
|
||||||
g_return_val_if_fail(val, FALSE);
|
|
||||||
|
|
||||||
slot_xml = xmlNewTextChild(p, NULL, "s", NULL);
|
|
||||||
g_return_val_if_fail(slot_xml, FALSE);
|
|
||||||
|
|
||||||
key_xml = xmlNewTextChild(slot_xml, NULL, "k", key);
|
|
||||||
g_return_val_if_fail(key_xml, FALSE);
|
|
||||||
|
|
||||||
return(xml_add_kvp_value(slot_xml, val));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
xmlNodePtr node;
|
|
||||||
gint64 keycount;
|
|
||||||
} kvp_value_foreach_info;
|
|
||||||
|
|
||||||
static void
|
|
||||||
xml_add_kvp_value_foreach_adapter(const char *key,
|
|
||||||
kvp_value *value,
|
|
||||||
gpointer data) {
|
|
||||||
kvp_value_foreach_info *info = (kvp_value_foreach_info *) data;
|
|
||||||
xml_add_kvp_slot(info->node, key, value);
|
|
||||||
info->keycount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_kvp_frame(xmlNodePtr p,
|
|
||||||
const char *tag,
|
|
||||||
const kvp_frame *kvpf,
|
|
||||||
gboolean add_if_empty) {
|
|
||||||
|
|
||||||
xmlNodePtr kvp_xml;
|
|
||||||
kvp_value_foreach_info info;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(tag, FALSE);
|
|
||||||
g_return_val_if_fail(kvpf, FALSE);
|
|
||||||
|
|
||||||
kvp_xml = xmlNewNode(NULL, tag);
|
|
||||||
g_return_val_if_fail(kvp_xml, FALSE);
|
|
||||||
|
|
||||||
info.node = kvp_xml;
|
|
||||||
info.keycount = 0;
|
|
||||||
kvp_frame_for_each_slot((kvp_frame *) kvpf,
|
|
||||||
xml_add_kvp_value_foreach_adapter,
|
|
||||||
&info);
|
|
||||||
if(add_if_empty || info.keycount) {
|
|
||||||
xmlAddChild(p, kvp_xml);
|
|
||||||
} else {
|
|
||||||
xmlFreeNode(kvp_xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_transaction_split(xmlNodePtr p, Split* s) {
|
|
||||||
xmlNodePtr split_xml;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(s, FALSE);
|
|
||||||
|
|
||||||
split_xml = xmlNewTextChild(p, NULL, "split", NULL);
|
|
||||||
g_return_val_if_fail(split_xml, FALSE);
|
|
||||||
|
|
||||||
if(!xml_add_guid(split_xml, "guid", xaccSplitGetGUID(s)))
|
|
||||||
return(FALSE);
|
|
||||||
|
|
||||||
if(!xml_add_str(split_xml, "memo", xaccSplitGetMemo(s), FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
|
|
||||||
if(!xml_add_str(split_xml, "action", xaccSplitGetAction(s), FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
|
|
||||||
/* reconcile-state */
|
|
||||||
{
|
|
||||||
char state = xaccSplitGetReconcile(s);
|
|
||||||
if(!xml_add_character(split_xml, "reconcile-state", state))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
/* reconcile-date */
|
|
||||||
Timespec ts;
|
|
||||||
xaccSplitGetDateReconciledTS(s, &ts);
|
|
||||||
if(!xml_add_editable_timespec(split_xml, "reconcile-date", &ts, FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* share-amount */
|
|
||||||
if(!xml_add_gnc_numeric(split_xml, "value", xaccSplitGetValue(s)))
|
|
||||||
return(FALSE);
|
|
||||||
|
|
||||||
/* share-price */
|
|
||||||
if(!xml_add_gnc_numeric(split_xml, "quantity", xaccSplitGetShareAmount(s)))
|
|
||||||
return(FALSE);
|
|
||||||
|
|
||||||
/* account */
|
|
||||||
{
|
|
||||||
Account *acct = xaccSplitGetAccount(s);
|
|
||||||
if(acct) {
|
|
||||||
if(!xml_add_guid(split_xml, "account", xaccAccountGetGUID(acct)))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s->kvp_data) {
|
|
||||||
if(!xml_add_kvp_frame(split_xml, "slots", s->kvp_data, FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_txn_restore(xmlNodePtr p, Transaction* t) {
|
|
||||||
|
|
||||||
xmlNodePtr txn_xml;
|
|
||||||
xmlNodePtr restore_xml;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(t, FALSE);
|
|
||||||
|
|
||||||
txn_xml = xmlNewTextChild(p, NULL, "transaction", NULL);
|
|
||||||
g_return_val_if_fail(txn_xml, FALSE);
|
|
||||||
|
|
||||||
restore_xml = xmlNewTextChild(txn_xml, NULL, "restore", NULL);
|
|
||||||
g_return_val_if_fail(restore_xml, FALSE);
|
|
||||||
|
|
||||||
if(!xml_add_guid(restore_xml, "guid", xaccTransGetGUID(t)))
|
|
||||||
return(FALSE);
|
|
||||||
if(!xml_add_str(restore_xml, "num", xaccTransGetNum(t), FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
{
|
|
||||||
Timespec ts;
|
|
||||||
xaccTransGetDatePostedTS(t, &ts);
|
|
||||||
if(!xml_add_editable_timespec(restore_xml, "date-posted", &ts, FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Timespec ts;
|
|
||||||
xaccTransGetDateEnteredTS(t, &ts);
|
|
||||||
if(!xml_add_editable_timespec(restore_xml, "date-entered", &ts, FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
if(!xml_add_str(restore_xml, "description", xaccTransGetDescription(t), FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
|
|
||||||
if(t->kvp_data) {
|
|
||||||
if(!xml_add_kvp_frame(restore_xml, "slots", t->kvp_data, FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
guint32 n = 0;
|
|
||||||
Split *s = xaccTransGetSplit(t, n);
|
|
||||||
|
|
||||||
while(s) {
|
|
||||||
if(!xml_add_transaction_split(restore_xml, s)) return(FALSE);
|
|
||||||
n++;
|
|
||||||
s = xaccTransGetSplit(t, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_txn_restore_adapter(Transaction *t, gpointer data) {
|
|
||||||
xmlNodePtr xml_node = (xmlNodePtr) data;
|
|
||||||
return(xml_add_txn_restore(xml_node, t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_txn_and_split_restorers(xmlNodePtr p, AccountGroup *g) {
|
|
||||||
return(xaccGroupForEachTransaction(g,
|
|
||||||
xml_add_txn_restore_adapter,
|
|
||||||
(gpointer) p));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
/* write out the xml for each of the fields in an account */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_account_restorer(xmlNodePtr p, Account* a) {
|
|
||||||
xmlNodePtr acct_xml;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(a, FALSE);
|
|
||||||
|
|
||||||
acct_xml = xmlNewTextChild(p, NULL, "account", NULL);
|
|
||||||
g_return_val_if_fail(acct_xml, FALSE);
|
|
||||||
|
|
||||||
acct_xml = xmlNewTextChild(acct_xml, NULL, "restore", NULL);
|
|
||||||
g_return_val_if_fail(acct_xml, FALSE);
|
|
||||||
|
|
||||||
if(!xml_add_str(acct_xml, "name",
|
|
||||||
xaccAccountGetName(a), FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
if(!xml_add_guid(acct_xml, "guid",
|
|
||||||
xaccAccountGetGUID(a)))
|
|
||||||
return(FALSE);
|
|
||||||
if(!xml_add_str(acct_xml, "type",
|
|
||||||
xaccAccountTypeEnumAsString(xaccAccountGetType(a)), FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
if(!xml_add_str(acct_xml, "code",
|
|
||||||
xaccAccountGetCode(a), FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
if(!xml_add_str(acct_xml, "description",
|
|
||||||
xaccAccountGetDescription(a), FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
/* Notes field is now in kvp table. */
|
|
||||||
if(!xml_add_commodity_ref(acct_xml, "currency", xaccAccountGetCurrency(a)))
|
|
||||||
return(FALSE);
|
|
||||||
if(!xml_add_commodity_ref(acct_xml, "security", xaccAccountGetSecurity(a)))
|
|
||||||
return(FALSE);
|
|
||||||
|
|
||||||
if(a->kvp_data) {
|
|
||||||
if(!xml_add_kvp_frame(acct_xml, "slots", a->kvp_data, FALSE))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Account *parent = xaccAccountGetParentAccount(a);
|
|
||||||
if(parent) {
|
|
||||||
xmlNodePtr parent_xml = xmlNewTextChild(acct_xml, NULL, "parent", NULL);
|
|
||||||
g_return_val_if_fail(parent_xml, FALSE);
|
|
||||||
if(!xml_add_guid(parent_xml, "guid", xaccAccountGetGUID(parent)))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
AccountGroup *g = xaccAccountGetChildren(a);
|
|
||||||
if(g) {
|
|
||||||
GList *list = xaccGroupGetAccountList (g);
|
|
||||||
GList *node;
|
|
||||||
|
|
||||||
for (node = list; node; node = node->next) {
|
|
||||||
Account *current_acc = node->data;
|
|
||||||
|
|
||||||
if(!xml_add_account_restorer(p, current_acc))
|
|
||||||
return(FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
/* loop over all accounts in the group */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_account_restorers(xmlNodePtr p, AccountGroup *g) {
|
|
||||||
GList *list;
|
|
||||||
GList *node;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(g, FALSE);
|
|
||||||
|
|
||||||
list = xaccGroupGetAccountList (g);
|
|
||||||
|
|
||||||
for (node = list; node; node = node->next) {
|
|
||||||
Account *current_acc = node->data;
|
|
||||||
xml_add_account_restorer(p, current_acc);
|
|
||||||
}
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
/* push query terms into xml */
|
|
||||||
/* XXX hack alert not all predicates currently implemented */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_qterm_restorer(xmlNodePtr qxml, QueryTerm *qt)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
xmlNodePtr p = NULL;
|
|
||||||
|
|
||||||
g_return_val_if_fail(qxml, FALSE);
|
|
||||||
g_return_val_if_fail(qt, FALSE);
|
|
||||||
|
|
||||||
/* we set the predicates names based on the info they record */
|
|
||||||
switch (qt->data.base.term_type) {
|
|
||||||
case PR_ACCOUNT:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "account-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_ACTION:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "action-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_AMOUNT:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "amount-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_BALANCE:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "balance-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_CLEARED:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "cleared-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_DATE:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "date-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_DESC:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "description-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_MEMO:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "memo-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_NUM:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "num-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_PRICE:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "price-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_SHRS:
|
|
||||||
p = xmlNewTextChild(qxml, NULL, "shares-pred", NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PR_MISC:
|
|
||||||
PERR ("Misc terms are not transmittable");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
if (!p) return (FALSE);
|
|
||||||
|
|
||||||
rc = xml_add_gint32(p, "sense", qt->data.base.sense);
|
|
||||||
if (!rc) return(FALSE);
|
|
||||||
|
|
||||||
|
|
||||||
/* however, many of the types share a generic structure. */
|
|
||||||
switch (qt->data.type) {
|
|
||||||
case PD_ACCOUNT:
|
|
||||||
PERR ("account query unimplemented");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PD_AMOUNT:
|
|
||||||
PERR ("amount query unimplemented");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PD_BALANCE:
|
|
||||||
PERR ("balance query unimplemented");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PD_CLEARED:
|
|
||||||
PERR ("cleared query unimplemented");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PD_DATE:
|
|
||||||
xml_add_gint32(p, "use-start", qt->data.date.use_start);
|
|
||||||
xml_add_gint32(p, "use-end", qt->data.date.use_end);
|
|
||||||
if (qt->data.date.use_start) {
|
|
||||||
xml_add_editable_timespec(p, "start-date",
|
|
||||||
&(qt->data.date.start), FALSE);
|
|
||||||
}
|
|
||||||
if (qt->data.date.use_end) {
|
|
||||||
xml_add_editable_timespec(p, "end-date",
|
|
||||||
&(qt->data.date.end), FALSE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PD_STRING:
|
|
||||||
xml_add_gint32(p, "case-sens", qt->data.str.case_sens);
|
|
||||||
xml_add_gint32(p, "use-regexp", qt->data.str.use_regexp);
|
|
||||||
xml_add_str(p, "matchstring", qt->data.str.matchstring, TRUE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PD_MISC:
|
|
||||||
PERR ("Must not happen");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
/* loop over all terms in the query */
|
|
||||||
/* XXX hack alert -- need to also send max-terms, sort-order,
|
|
||||||
* and other mis query elements */
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
xml_add_query_restorers(xmlNodePtr p, Query *q)
|
|
||||||
{
|
|
||||||
xmlNodePtr qxml, restore_xml, and_xml;
|
|
||||||
GList *aterms, *oterms;
|
|
||||||
GList *anode, *onode;
|
|
||||||
|
|
||||||
g_return_val_if_fail(p, FALSE);
|
|
||||||
g_return_val_if_fail(q, FALSE);
|
|
||||||
|
|
||||||
oterms = xaccQueryGetTerms (q);
|
|
||||||
|
|
||||||
/* write the nested <query> <restore> */
|
|
||||||
qxml = xmlNewTextChild(p, NULL, "query", NULL);
|
|
||||||
g_return_val_if_fail(qxml, FALSE);
|
|
||||||
|
|
||||||
restore_xml = xmlNewTextChild(qxml, NULL, "restore", NULL);
|
|
||||||
g_return_val_if_fail(restore_xml, FALSE);
|
|
||||||
|
|
||||||
for (onode = oterms; onode; onode = onode->next) {
|
|
||||||
aterms = onode->data;
|
|
||||||
and_xml = xmlNewTextChild(restore_xml, NULL, "and-terms", NULL);
|
|
||||||
g_return_val_if_fail(and_xml, FALSE);
|
|
||||||
|
|
||||||
for (anode = aterms; anode; anode = anode->next) {
|
|
||||||
QueryTerm *qt = anode->data;
|
|
||||||
xml_add_qterm_restorer(and_xml, qt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================== */
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gncxml_append_emacs_trailer(const gchar *filename)
|
gncxml_append_emacs_trailer(const gchar *filename)
|
||||||
{
|
{
|
||||||
|
52
src/engine/sixtp-writers.h
Normal file
52
src/engine/sixtp-writers.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#ifndef _SIXTP_WRITERS_H_
|
||||||
|
#define _SIXTP_WRITERS_H_
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_XML_VERSION_HEADER
|
||||||
|
#include <libxml/xmlversion.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LIBXML_VERSION) && LIBXML_VERSION >= 20000
|
||||||
|
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/xmlmemory.h>
|
||||||
|
#include <libxml/parserInternals.h>
|
||||||
|
#ifndef xmlChildrenNode
|
||||||
|
#define xmlChildrenNode children
|
||||||
|
#define xmlRootNode children
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <gnome-xml/tree.h>
|
||||||
|
#include <gnome-xml/parser.h>
|
||||||
|
#include <gnome-xml/xmlmemory.h>
|
||||||
|
#include <gnome-xml/parserInternals.h>
|
||||||
|
#ifndef xmlChildrenNode
|
||||||
|
#define xmlChildrenNode childs
|
||||||
|
#define xmlRootNode root
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "Query.h"
|
||||||
|
|
||||||
|
gboolean xml_add_account_restorers(xmlNodePtr p, AccountGroup *g);
|
||||||
|
|
||||||
|
gboolean xml_add_commodity_restorers(xmlNodePtr p);
|
||||||
|
|
||||||
|
gboolean xml_add_commodity_ref(xmlNodePtr p, const char *tag,
|
||||||
|
const gnc_commodity *c);
|
||||||
|
|
||||||
|
gboolean xml_add_query_restorers(xmlNodePtr p, Query *q);
|
||||||
|
|
||||||
|
gboolean xml_add_txn_and_split_restorers(xmlNodePtr p, AccountGroup *g);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _SIXTP_WRITERS_H_ */
|
483
src/engine/sixtp-xml-write-utils.c
Normal file
483
src/engine/sixtp-xml-write-utils.c
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_XML_VERSION_HEADER
|
||||||
|
#include <libxml/xmlversion.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LIBXML_VERSION) && LIBXML_VERSION >= 20000
|
||||||
|
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/xmlmemory.h>
|
||||||
|
#include <libxml/parserInternals.h>
|
||||||
|
#ifndef xmlChildrenNode
|
||||||
|
#define xmlChildrenNode children
|
||||||
|
#define xmlRootNode children
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <gnome-xml/tree.h>
|
||||||
|
#include <gnome-xml/parser.h>
|
||||||
|
#include <gnome-xml/xmlmemory.h>
|
||||||
|
#include <gnome-xml/parserInternals.h>
|
||||||
|
#ifndef xmlChildrenNode
|
||||||
|
#define xmlChildrenNode childs
|
||||||
|
#define xmlRootNode root
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "sixtp-xml-write-utils.h"
|
||||||
|
|
||||||
|
#include "gnc-numeric.h"
|
||||||
|
#include "gnc-engine-util.h"
|
||||||
|
|
||||||
|
static short module = MOD_IO;
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_str(xmlNodePtr p, const char *tag, const char *str,
|
||||||
|
gboolean include_if_empty) {
|
||||||
|
xmlNodePtr child;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
if(!str && !include_if_empty) return(TRUE);
|
||||||
|
if((strlen(str) == 0) && !include_if_empty) return(TRUE);
|
||||||
|
|
||||||
|
child = xmlNewTextChild(p, NULL, tag, str);
|
||||||
|
g_return_val_if_fail(child, FALSE);
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_character(xmlNodePtr p, const char *tag, const char c) {
|
||||||
|
char str[2];
|
||||||
|
str[0] = c;
|
||||||
|
str[1] = '\0';
|
||||||
|
return(xml_add_str(p, tag, str, FALSE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_gint64(xmlNodePtr p, const char *tag, const gint64 value) {
|
||||||
|
xmlNodePtr val_xml;
|
||||||
|
char num_string[22];
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
|
||||||
|
g_snprintf(num_string, sizeof (num_string), "%lld", value);
|
||||||
|
|
||||||
|
val_xml = xmlNewTextChild(p, NULL, tag, num_string);
|
||||||
|
g_return_val_if_fail(val_xml, FALSE);
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_gint32(xmlNodePtr p, const char *tag, const gint32 value) {
|
||||||
|
xmlNodePtr val_xml;
|
||||||
|
char num_string[22];
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
|
||||||
|
g_snprintf(num_string, sizeof (num_string), "%d", value);
|
||||||
|
|
||||||
|
val_xml = xmlNewTextChild(p, NULL, tag, num_string);
|
||||||
|
g_return_val_if_fail(val_xml, FALSE);
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
/*
|
||||||
|
RLB writes:
|
||||||
|
We have to use guile because AFAICT, libc, and C in general isn't
|
||||||
|
smart enough to actually parse it's own output, especially not
|
||||||
|
portably (big surprise).
|
||||||
|
|
||||||
|
Linas writes:
|
||||||
|
I don't understand the claim; I'm just going to use
|
||||||
|
atof or strtod to accomplish this.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_double(xmlNodePtr p, const char *tag, const double value)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_GUILE_FOR_DOUBLE_CONVERSION
|
||||||
|
{
|
||||||
|
/* FIXME: NOT THREAD SAFE - USES STATIC DATA */
|
||||||
|
static SCM number_to_string;
|
||||||
|
static gboolean ready = FALSE;
|
||||||
|
const char *numstr;
|
||||||
|
|
||||||
|
if(!ready) {
|
||||||
|
number_to_string = gh_eval_str("number->string");
|
||||||
|
scm_protect_object(number_to_string);
|
||||||
|
ready = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
numstr = gh_scm2newstr(gh_call1(number_to_string, gh_double2scm(value)),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if(!numstr) {
|
||||||
|
return(FALSE);
|
||||||
|
} else {
|
||||||
|
xmlNodePtr child = xmlNewTextChild(p, NULL, tag, numstr);
|
||||||
|
free((void *) numstr);
|
||||||
|
g_return_val_if_fail(child, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* don't USE_GUILE_FOR_DOUBLE_CONVERSION */
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
char prtbuf[80];
|
||||||
|
xmlNodePtr child;
|
||||||
|
|
||||||
|
/* we're just going to use plain-old libc for the double conversion.
|
||||||
|
* There was some question as to whether libc is accurate enough
|
||||||
|
* in its printf function for doubles, but I don't understand
|
||||||
|
* how it couldn't be ...
|
||||||
|
*/
|
||||||
|
len = snprintf (prtbuf, 80, "%24.18g", value);
|
||||||
|
if (80 <=len) return (FALSE);
|
||||||
|
|
||||||
|
child = xmlNewTextChild(p, NULL, tag, prtbuf);
|
||||||
|
g_return_val_if_fail(child, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_GUILE_FOR_DOUBLE_CONVERSION */
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_gnc_numeric(xmlNodePtr p, const char *tag, const gnc_numeric n) {
|
||||||
|
char *numstr;
|
||||||
|
xmlNodePtr child;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
|
||||||
|
/* fprintf(stderr, "WRITE GNUM S: %lld/%lld -> ", n.num, n.denom); */
|
||||||
|
|
||||||
|
numstr = gnc_numeric_to_string(n);
|
||||||
|
g_return_val_if_fail(numstr, FALSE);
|
||||||
|
|
||||||
|
/* fprintf(stderr, "%s\n", numstr); */
|
||||||
|
|
||||||
|
child = xmlNewTextChild(p, NULL, tag, numstr);
|
||||||
|
g_free(numstr); numstr = FALSE;
|
||||||
|
g_return_val_if_fail(child, FALSE);
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_guid(xmlNodePtr p, const char *tag, const GUID *guid) {
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
g_return_val_if_fail(guid, FALSE);
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *guidstr;
|
||||||
|
xmlNodePtr child;
|
||||||
|
|
||||||
|
if(!guid) {
|
||||||
|
guidstr = NULL;
|
||||||
|
} else {
|
||||||
|
guidstr = guid_to_string(guid);
|
||||||
|
g_return_val_if_fail(guidstr, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
child = xmlNewTextChild(p, NULL, tag, guidstr);
|
||||||
|
g_return_val_if_fail(child, FALSE);
|
||||||
|
if(guidstr) free((void *) guidstr);
|
||||||
|
}
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_editable_timespec(xmlNodePtr p,
|
||||||
|
const char *tag,
|
||||||
|
const Timespec *ts,
|
||||||
|
gboolean include_if_zero) {
|
||||||
|
xmlNodePtr timespec_xml;
|
||||||
|
xmlNodePtr secs_xml;
|
||||||
|
size_t num_written;
|
||||||
|
struct tm parsed_time;
|
||||||
|
time_t tmp_timet;
|
||||||
|
char secs_str[512]; /* This should be way bigger than we need.
|
||||||
|
Still, it's bogus, we ought to have
|
||||||
|
astrftime... */
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
g_return_val_if_fail(ts, FALSE);
|
||||||
|
if(!include_if_zero && (ts->tv_sec == 0) && (ts->tv_nsec == 0)) return TRUE;
|
||||||
|
|
||||||
|
tmp_timet = ts->tv_sec;
|
||||||
|
if(!localtime_r(&tmp_timet, &parsed_time)) return(FALSE);
|
||||||
|
|
||||||
|
num_written = strftime(secs_str, sizeof(secs_str),
|
||||||
|
"%Y-%m-%d %H:%M:%S %z",
|
||||||
|
&parsed_time);
|
||||||
|
if(num_written == 0) return(FALSE);
|
||||||
|
|
||||||
|
timespec_xml= xmlNewTextChild(p, NULL, tag, NULL);
|
||||||
|
g_return_val_if_fail(timespec_xml, FALSE);
|
||||||
|
|
||||||
|
secs_xml = xmlNewTextChild(timespec_xml, NULL, "s", secs_str);
|
||||||
|
g_return_val_if_fail(secs_xml, FALSE);
|
||||||
|
|
||||||
|
if(ts->tv_nsec) {
|
||||||
|
xmlNodePtr nsec_xml;
|
||||||
|
char num_string[22];
|
||||||
|
|
||||||
|
g_snprintf(num_string, sizeof (num_string), "%ld", ts->tv_nsec);
|
||||||
|
|
||||||
|
nsec_xml = xmlNewTextChild(timespec_xml, NULL, "ns", num_string);
|
||||||
|
g_return_val_if_fail(nsec_xml, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_binary(xmlNodePtr p,
|
||||||
|
const char *tag,
|
||||||
|
const gchar *format,
|
||||||
|
const void *data,
|
||||||
|
guint32 size)
|
||||||
|
{
|
||||||
|
|
||||||
|
xmlNodePtr value_xml;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
g_return_val_if_fail(format, FALSE);
|
||||||
|
g_return_val_if_fail(data, FALSE);
|
||||||
|
|
||||||
|
value_xml = xmlNewTextChild(p, NULL, tag, NULL);
|
||||||
|
g_return_val_if_fail(value_xml, FALSE);
|
||||||
|
|
||||||
|
if(size == 0) return(TRUE);
|
||||||
|
|
||||||
|
if(0 == strcmp(format, "hex")) {
|
||||||
|
/* Write out the chars as hex, buffering them in max 64 character
|
||||||
|
lines. I was going to use xmlNewTextChild, and xmlTextConcat,
|
||||||
|
but that doesn't seem to work, and looking at the source,
|
||||||
|
xmlNewTextChild doesn't set the node type to a type that
|
||||||
|
xmlTextConcat will recognize and allow. */
|
||||||
|
|
||||||
|
const guint max_line_len = 64;
|
||||||
|
xmlNodePtr data_xml = NULL;
|
||||||
|
GString *output;
|
||||||
|
guint32 i;
|
||||||
|
|
||||||
|
output = g_string_sized_new(max_line_len + 2);
|
||||||
|
|
||||||
|
for(i = 0; i < size; i++) {
|
||||||
|
g_string_sprintfa(output, "%x", (int) (((char *) data)[i]));
|
||||||
|
if(((i + 1) % max_line_len) == 0) {
|
||||||
|
data_xml = xmlNewTextChild(value_xml, NULL, "hex", output->str);
|
||||||
|
if(!data_xml) {
|
||||||
|
return(FALSE);
|
||||||
|
g_string_free(output, TRUE);
|
||||||
|
}
|
||||||
|
g_string_truncate(output, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen(output->str) > 0) {
|
||||||
|
data_xml = xmlNewTextChild(value_xml, NULL, "hex", output->str);
|
||||||
|
if(!data_xml) {
|
||||||
|
g_string_free(output, TRUE);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_string_free(output, TRUE);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PERR("unknown output format %s.\n", format);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
static gboolean xml_add_kvp_value(xmlNodePtr p, kvp_value *val);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_kvp_glist(xmlNodePtr p, const char *tag, GList *lst) {
|
||||||
|
xmlNodePtr list_xml;
|
||||||
|
GList *cursor;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
g_return_val_if_fail(lst, FALSE);
|
||||||
|
|
||||||
|
list_xml = xmlNewTextChild(p, NULL, tag, NULL);
|
||||||
|
g_return_val_if_fail(list_xml, FALSE);
|
||||||
|
|
||||||
|
for(cursor = lst; cursor; cursor = cursor->next) {
|
||||||
|
kvp_value * val = (kvp_value *) cursor->data;
|
||||||
|
if(!xml_add_kvp_value(list_xml, val)) {
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_kvp_frame(xmlNodePtr p, const char *tag,
|
||||||
|
const kvp_frame *kvpf,
|
||||||
|
gboolean add_if_empty);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_kvp_value(xmlNodePtr p, kvp_value *val) {
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(val, FALSE);
|
||||||
|
|
||||||
|
switch(kvp_value_get_type(val)) {
|
||||||
|
case KVP_TYPE_GINT64:
|
||||||
|
return(xml_add_gint64(p, "gint64", kvp_value_get_gint64(val)));
|
||||||
|
break;
|
||||||
|
case KVP_TYPE_DOUBLE:
|
||||||
|
return(xml_add_double(p, "double", kvp_value_get_double(val)));
|
||||||
|
break;
|
||||||
|
case KVP_TYPE_NUMERIC:
|
||||||
|
return(xml_add_gnc_numeric(p, "numeric", kvp_value_get_numeric(val)));
|
||||||
|
break;
|
||||||
|
case KVP_TYPE_STRING:
|
||||||
|
return(xml_add_str(p, "string", kvp_value_get_string(val), TRUE));
|
||||||
|
break;
|
||||||
|
case KVP_TYPE_GUID:
|
||||||
|
return(xml_add_guid(p, "guid", kvp_value_get_guid(val)));
|
||||||
|
break;
|
||||||
|
case KVP_TYPE_BINARY:
|
||||||
|
{
|
||||||
|
guint64 size;
|
||||||
|
void *binary_data = kvp_value_get_binary(val, &size);
|
||||||
|
g_return_val_if_fail(binary_data, FALSE);
|
||||||
|
return(xml_add_binary(p, "binary", "hex", binary_data, size));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KVP_TYPE_GLIST:
|
||||||
|
return(xml_add_kvp_glist(p, "glist", kvp_value_get_glist(val)));
|
||||||
|
break;
|
||||||
|
case KVP_TYPE_FRAME:
|
||||||
|
return(xml_add_kvp_frame(p, "frame", kvp_value_get_frame(val), TRUE));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return(FALSE);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
xml_add_kvp_slot(xmlNodePtr p, const char *key, kvp_value *val) {
|
||||||
|
xmlNodePtr slot_xml;
|
||||||
|
xmlNodePtr key_xml;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(key, FALSE);
|
||||||
|
g_return_val_if_fail(val, FALSE);
|
||||||
|
|
||||||
|
slot_xml = xmlNewTextChild(p, NULL, "s", NULL);
|
||||||
|
g_return_val_if_fail(slot_xml, FALSE);
|
||||||
|
|
||||||
|
key_xml = xmlNewTextChild(slot_xml, NULL, "k", key);
|
||||||
|
g_return_val_if_fail(key_xml, FALSE);
|
||||||
|
|
||||||
|
return(xml_add_kvp_value(slot_xml, val));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
xmlNodePtr node;
|
||||||
|
gint64 keycount;
|
||||||
|
} kvp_value_foreach_info;
|
||||||
|
|
||||||
|
static void
|
||||||
|
xml_add_kvp_value_foreach_adapter(const char *key,
|
||||||
|
kvp_value *value,
|
||||||
|
gpointer data) {
|
||||||
|
kvp_value_foreach_info *info = (kvp_value_foreach_info *) data;
|
||||||
|
xml_add_kvp_slot(info->node, key, value);
|
||||||
|
info->keycount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================== */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
xml_add_kvp_frame(xmlNodePtr p,
|
||||||
|
const char *tag,
|
||||||
|
const kvp_frame *kvpf,
|
||||||
|
gboolean add_if_empty) {
|
||||||
|
|
||||||
|
xmlNodePtr kvp_xml;
|
||||||
|
kvp_value_foreach_info info;
|
||||||
|
|
||||||
|
g_return_val_if_fail(p, FALSE);
|
||||||
|
g_return_val_if_fail(tag, FALSE);
|
||||||
|
g_return_val_if_fail(kvpf, FALSE);
|
||||||
|
|
||||||
|
kvp_xml = xmlNewNode(NULL, tag);
|
||||||
|
g_return_val_if_fail(kvp_xml, FALSE);
|
||||||
|
|
||||||
|
info.node = kvp_xml;
|
||||||
|
info.keycount = 0;
|
||||||
|
kvp_frame_for_each_slot((kvp_frame *) kvpf,
|
||||||
|
xml_add_kvp_value_foreach_adapter,
|
||||||
|
&info);
|
||||||
|
if(add_if_empty || info.keycount) {
|
||||||
|
xmlAddChild(p, kvp_xml);
|
||||||
|
} else {
|
||||||
|
xmlFreeNode(kvp_xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
67
src/engine/sixtp-xml-write-utils.h
Normal file
67
src/engine/sixtp-xml-write-utils.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
#ifndef _SIXTP_XML_WRITE_UTILS_H_
|
||||||
|
#define _SIXTP_XML_WRITE_UTILS_H_
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_XML_VERSION_HEADER
|
||||||
|
#include <libxml/xmlversion.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LIBXML_VERSION) && LIBXML_VERSION >= 20000
|
||||||
|
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/xmlmemory.h>
|
||||||
|
#include <libxml/parserInternals.h>
|
||||||
|
#ifndef xmlChildrenNode
|
||||||
|
#define xmlChildrenNode children
|
||||||
|
#define xmlRootNode children
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <gnome-xml/tree.h>
|
||||||
|
#include <gnome-xml/parser.h>
|
||||||
|
#include <gnome-xml/xmlmemory.h>
|
||||||
|
#include <gnome-xml/parserInternals.h>
|
||||||
|
#ifndef xmlChildrenNode
|
||||||
|
#define xmlChildrenNode childs
|
||||||
|
#define xmlRootNode root
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gnc-numeric.h"
|
||||||
|
#include "GNCId.h"
|
||||||
|
#include "date.h"
|
||||||
|
#include "kvp_frame.h"
|
||||||
|
|
||||||
|
gboolean xml_add_str(xmlNodePtr p, const char *tag, const char *str,
|
||||||
|
gboolean include_if_empty);
|
||||||
|
|
||||||
|
gboolean xml_add_character(xmlNodePtr p, const char *tag, const char c);
|
||||||
|
|
||||||
|
gboolean xml_add_gint64(xmlNodePtr p, const char *tag, const gint64 value);
|
||||||
|
|
||||||
|
gboolean xml_add_gint32(xmlNodePtr p, const char *tag, const gint32 value);
|
||||||
|
|
||||||
|
gboolean xml_add_double(xmlNodePtr p, const char *tag, const double value);
|
||||||
|
|
||||||
|
gboolean xml_add_gnc_numeric(xmlNodePtr p, const char *tag,
|
||||||
|
const gnc_numeric n);
|
||||||
|
|
||||||
|
gboolean xml_add_guid(xmlNodePtr p, const char *tag, const GUID *guid);
|
||||||
|
|
||||||
|
gboolean xml_add_editable_timespec(xmlNodePtr p, const char *tag,
|
||||||
|
const Timespec *ts,
|
||||||
|
gboolean include_if_zero);
|
||||||
|
|
||||||
|
gboolean xml_add_kvp_frame(xmlNodePtr p, const char *tag,
|
||||||
|
const kvp_frame *kvpf, gboolean add_if_empty);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _SIXTP_XML_WRITE_UTILS_H_ */
|
@ -476,7 +476,8 @@ sixtp_sax_end_handler(void *user_data, const xmlChar *name) {
|
|||||||
current_frame = (sixtp_stack_frame *) pdata->stack->data;
|
current_frame = (sixtp_stack_frame *) pdata->stack->data;
|
||||||
parent_frame = (sixtp_stack_frame *) pdata->stack->next->data;
|
parent_frame = (sixtp_stack_frame *) pdata->stack->next->data;
|
||||||
|
|
||||||
/* time to make sure we got the right closing tag */
|
/* time to make sure we got the right closing tag. Is this really
|
||||||
|
necessary? */
|
||||||
if(safe_strcmp(current_frame->tag, name) != 0) {
|
if(safe_strcmp(current_frame->tag, name) != 0) {
|
||||||
pdata->parsing_ok = FALSE;
|
pdata->parsing_ok = FALSE;
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user