gnucash/libgnucash/backend/xml/gnc-schedxaction-xml-v2.cpp
Christopher Lam de09259f13 Bug 797500 - valgrind errors - new/delete vs malloc/free
Mismatched new/g_free()
Change to new/guid_free() which calls delete
2019-11-17 09:55:51 +08:00

942 lines
28 KiB
C++

/********************************************************************
* gnc-schedxactions-xml-v2.c -- xml routines for transactions *
* Copyright (C) 2001,2007 Joshua Sled <jsled@asynchronous.org> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
* *
*******************************************************************/
extern "C"
{
#include <config.h>
#include <glib.h>
#include <string.h>
#include "SX-book.h"
}
#include "gnc-xml-helper.h"
#include "sixtp.h"
#include "sixtp-utils.h"
#include "sixtp-parsers.h"
#include "sixtp-utils.h"
#include "sixtp-dom-parsers.h"
#include "sixtp-dom-generators.h"
#include "gnc-xml.h"
#include "io-gncxml-v2.h"
#include "io-gncxml-gen.h"
#include "sixtp-dom-parsers.h"
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "gnc.backend.file.sx"
#define SX_ID "sx:id"
#define SX_NAME "sx:name"
#define SX_ENABLED "sx:enabled"
#define SX_AUTOCREATE "sx:autoCreate"
#define SX_AUTOCREATE_NOTIFY "sx:autoCreateNotify"
#define SX_ADVANCE_CREATE_DAYS "sx:advanceCreateDays"
#define SX_ADVANCE_REMIND_DAYS "sx:advanceRemindDays"
#define SX_INSTANCE_COUNT "sx:instanceCount"
#define SX_START "sx:start"
#define SX_LAST "sx:last"
#define SX_NUM_OCCUR "sx:num-occur"
#define SX_REM_OCCUR "sx:rem-occur"
#define SX_END "sx:end"
#define SX_TEMPL_ACCT "sx:templ-acct"
#define SX_FREQSPEC "sx:freqspec"
#define SX_SCHEDULE "sx:schedule"
#define SX_SLOTS "sx:slots"
#define SX_DEFER_INSTANCE "sx:deferredInstance"
/*
* FIXME: These should be defined in a header somewhere
*/
#define GNC_ACCOUNT_TAG "gnc:account"
#define GNC_TRANSACTION_TAG "gnc:transaction"
#define GNC_SCHEDXACTION_TAG "gnc:schedxaction"
const gchar* schedxaction_version_string = "1.0.0";
const gchar* schedxaction_version2_string = "2.0.0";
xmlNodePtr
gnc_schedXaction_dom_tree_create (SchedXaction* sx)
{
xmlNodePtr ret;
const GDate* date;
gint instCount;
const GncGUID* templ_acc_guid;
gboolean allow_2_2_incompat = TRUE;
gchar* name = g_strdup (xaccSchedXactionGetName (sx));
templ_acc_guid = xaccAccountGetGUID (sx->template_acct);
/* FIXME: this should be the same as the def in io-gncxml-v2.c */
ret = xmlNewNode (NULL, BAD_CAST GNC_SCHEDXACTION_TAG);
if (allow_2_2_incompat)
xmlSetProp (ret, BAD_CAST "version", BAD_CAST schedxaction_version2_string);
else
xmlSetProp (ret, BAD_CAST "version", BAD_CAST schedxaction_version_string);
xmlAddChild (ret,
guid_to_dom_tree (SX_ID,
xaccSchedXactionGetGUID (sx)));
xmlNewTextChild (ret, NULL, BAD_CAST SX_NAME, checked_char_cast (name));
g_free (name);
if (allow_2_2_incompat)
{
xmlNewTextChild (ret, NULL, BAD_CAST SX_ENABLED,
BAD_CAST (sx->enabled ? "y" : "n"));
}
xmlNewTextChild (ret, NULL, BAD_CAST SX_AUTOCREATE,
BAD_CAST (sx->autoCreateOption ? "y" : "n"));
xmlNewTextChild (ret, NULL, BAD_CAST SX_AUTOCREATE_NOTIFY,
BAD_CAST (sx->autoCreateNotify ? "y" : "n"));
xmlAddChild (ret, int_to_dom_tree (SX_ADVANCE_CREATE_DAYS,
sx->advanceCreateDays));
xmlAddChild (ret, int_to_dom_tree (SX_ADVANCE_REMIND_DAYS,
sx->advanceRemindDays));
instCount = gnc_sx_get_instance_count (sx, NULL);
xmlAddChild (ret, int_to_dom_tree (SX_INSTANCE_COUNT,
instCount));
xmlAddChild (ret,
gdate_to_dom_tree (SX_START,
xaccSchedXactionGetStartDate (sx)));
date = xaccSchedXactionGetLastOccurDate (sx);
if (g_date_valid (date))
{
xmlAddChild (ret, gdate_to_dom_tree (SX_LAST, date));
}
if (xaccSchedXactionHasOccurDef (sx))
{
xmlAddChild (ret, int_to_dom_tree (SX_NUM_OCCUR,
xaccSchedXactionGetNumOccur (sx)));
xmlAddChild (ret, int_to_dom_tree (SX_REM_OCCUR,
xaccSchedXactionGetRemOccur (sx)));
}
else if (xaccSchedXactionHasEndDate (sx))
{
xmlAddChild (ret,
gdate_to_dom_tree (SX_END,
xaccSchedXactionGetEndDate (sx)));
}
/* output template account GncGUID */
xmlAddChild (ret,
guid_to_dom_tree (SX_TEMPL_ACCT,
templ_acc_guid));
if (allow_2_2_incompat)
{
xmlNodePtr schedule_node = xmlNewNode (NULL,
BAD_CAST "sx:schedule");
GList* schedule = gnc_sx_get_schedule (sx);
for (; schedule != NULL; schedule = schedule->next)
{
xmlAddChild (schedule_node, recurrence_to_dom_tree ("gnc:recurrence",
(Recurrence*)schedule->data));
}
xmlAddChild (ret, schedule_node);
}
/* Output deferred-instance list. */
{
xmlNodePtr instNode;
SXTmpStateData* tsd;
GList* l;
for (l = gnc_sx_get_defer_instances (sx); l; l = l->next)
{
tsd = (SXTmpStateData*)l->data;
instNode = xmlNewNode (NULL, BAD_CAST SX_DEFER_INSTANCE);
if (g_date_valid (&tsd->last_date))
{
xmlAddChild (instNode, gdate_to_dom_tree (SX_LAST,
&tsd->last_date));
}
xmlAddChild (instNode, int_to_dom_tree (SX_REM_OCCUR,
tsd->num_occur_rem));
xmlAddChild (instNode, int_to_dom_tree (SX_INSTANCE_COUNT,
tsd->num_inst));
xmlAddChild (ret, instNode);
}
}
/* xmlAddChild won't do anything with a NULL, so tests are superfluous. */
xmlAddChild (ret, qof_instance_slots_to_dom_tree (SX_SLOTS,
QOF_INSTANCE (sx)));
return ret;
}
struct sx_pdata
{
SchedXaction* sx;
QofBook* book;
gboolean saw_freqspec;
gboolean saw_recurrence;
};
static
gboolean
sx_id_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
GncGUID* tmp = dom_tree_to_guid (node);
g_return_val_if_fail (tmp, FALSE);
xaccSchedXactionSetGUID (sx, tmp);
g_free (tmp);
return TRUE;
}
static
gboolean
sx_name_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
gchar* tmp = dom_tree_to_text (node);
g_debug ("sx named [%s]", tmp);
g_return_val_if_fail (tmp, FALSE);
xaccSchedXactionSetName (sx, tmp);
g_free (tmp);
return TRUE;
}
static gboolean
sx_enabled_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
gchar* tmp = dom_tree_to_text (node);
sx->enabled = (g_strcmp0 (tmp, "y") == 0 ? TRUE : FALSE);
return TRUE;
}
static gboolean
sx_autoCreate_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
gchar* tmp = dom_tree_to_text (node);
sx->autoCreateOption = (g_strcmp0 (tmp, "y") == 0 ? TRUE : FALSE);
return TRUE;
}
static gboolean
sx_notify_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
gchar* tmp = dom_tree_to_text (node);
sx->autoCreateNotify = (g_strcmp0 (tmp, "y") == 0 ? TRUE : FALSE);
return TRUE;
}
static gboolean
sx_advCreate_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
gint64 advCreate;
if (! dom_tree_to_integer (node, &advCreate))
{
return FALSE;
}
xaccSchedXactionSetAdvanceCreation (sx, advCreate);
return TRUE;
}
static gboolean
sx_advRemind_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
gint64 advRemind;
if (! dom_tree_to_integer (node, &advRemind))
{
return FALSE;
}
xaccSchedXactionSetAdvanceReminder (sx, advRemind);
return TRUE;
}
static
gboolean
sx_set_date (xmlNodePtr node, SchedXaction* sx,
void (*settor) (SchedXaction* sx, const GDate* d))
{
GDate* date;
date = dom_tree_to_gdate (node);
g_return_val_if_fail (date, FALSE);
(*settor) (sx, date);
g_date_free (date);
return TRUE;
}
static
gboolean
sx_instcount_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
gint64 instanceNum;
if (! dom_tree_to_integer (node, &instanceNum))
{
return FALSE;
}
gnc_sx_set_instance_count (sx, instanceNum);
return TRUE;
}
static
gboolean
sx_start_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
return sx_set_date (node, sx, xaccSchedXactionSetStartDate);
}
static
gboolean
sx_last_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
return sx_set_date (node, sx, xaccSchedXactionSetLastOccurDate);
}
static
gboolean
sx_end_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
return sx_set_date (node, sx, xaccSchedXactionSetEndDate);
}
static void
_fixup_recurrence_start_dates (const GDate* sx_start_date, GList* schedule)
{
GList* iter;
for (iter = schedule; iter != NULL; iter = iter->next)
{
Recurrence* r;
GDate start, next;
r = (Recurrence*)iter->data;
start = *sx_start_date;
g_date_subtract_days (&start, 1);
g_date_clear (&next, 1);
recurrenceNextInstance (r, &start, &next);
g_return_if_fail (g_date_valid (&next));
{
gchar date_str[128];
gchar* sched_str;
g_date_strftime (date_str, 127, "%x", &next);
sched_str = recurrenceToString (r);
g_debug ("setting recurrence [%s] start date to [%s]",
sched_str, date_str);
g_free (sched_str);
}
recurrenceSet (r,
recurrenceGetMultiplier (r),
recurrenceGetPeriodType (r),
&next,
recurrenceGetWeekendAdjust (r));
}
if (g_list_length (schedule) == 1
&& recurrenceGetPeriodType ((Recurrence*)g_list_nth_data (schedule,
0)) == PERIOD_ONCE)
{
char date_buf[128];
Recurrence* fixup = (Recurrence*)g_list_nth_data (schedule, 0);
g_date_strftime (date_buf, 127, "%x", sx_start_date);
recurrenceSet (fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE);
g_debug ("fixed up period=ONCE Recurrence to date [%s]", date_buf);
}
}
static gboolean
sx_freqspec_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
GList* schedule;
gchar* debug_str;
g_return_val_if_fail (node, FALSE);
schedule = dom_tree_freqSpec_to_recurrences (node, pdata->book);
gnc_sx_set_schedule (sx, schedule);
debug_str = recurrenceListToString (schedule);
g_debug ("parsed from freqspec [%s]", debug_str);
g_free (debug_str);
_fixup_recurrence_start_dates (xaccSchedXactionGetStartDate (sx), schedule);
pdata->saw_freqspec = TRUE;
return TRUE;
}
static gboolean
sx_schedule_recurrence_handler (xmlNodePtr node, gpointer parsing_data)
{
GList** schedule = (GList**)parsing_data;
gchar* sched_str;
Recurrence* r = dom_tree_to_recurrence (node);
g_return_val_if_fail (r, FALSE);
sched_str = recurrenceToString (r);
g_debug ("parsed recurrence [%s]", sched_str);
g_free (sched_str);
*schedule = g_list_append (*schedule, r);
return TRUE;
}
struct dom_tree_handler sx_recurrence_list_handlers[] =
{
{ "gnc:recurrence", sx_schedule_recurrence_handler, 0, 0 },
{ NULL, NULL, 0, 0 }
};
static gboolean
sx_recurrence_handler (xmlNodePtr node, gpointer _pdata)
{
struct sx_pdata* parsing_data = static_cast<decltype (parsing_data)> (_pdata);
GList* schedule = NULL;
gchar* debug_str;
g_return_val_if_fail (node, FALSE);
if (!dom_tree_generic_parse (node, sx_recurrence_list_handlers, &schedule))
return FALSE;
// g_return_val_if_fail(schedule, FALSE);
debug_str = recurrenceListToString (schedule);
g_debug ("setting freshly-parsed schedule: [%s]", debug_str);
g_free (debug_str);
gnc_sx_set_schedule (parsing_data->sx, schedule);
parsing_data->saw_recurrence = TRUE;
return TRUE;
}
static
gboolean
sx_defer_last_handler (xmlNodePtr node, gpointer gpTSD)
{
GDate* gd;
SXTmpStateData* tsd = (SXTmpStateData*)gpTSD;
g_return_val_if_fail (node, FALSE);
gd = dom_tree_to_gdate (node);
g_return_val_if_fail (gd, FALSE);
tsd->last_date = *gd;
g_date_free (gd);
return TRUE;
}
static
gboolean
sx_defer_rem_occur_handler (xmlNodePtr node, gpointer gpTSD)
{
gint64 remOccur;
SXTmpStateData* tsd = (SXTmpStateData*)gpTSD;
g_return_val_if_fail (node, FALSE);
if (! dom_tree_to_integer (node, &remOccur))
{
return FALSE;
}
tsd->num_occur_rem = remOccur;
return TRUE;
}
static
gboolean
sx_defer_inst_count_handler (xmlNodePtr node, gpointer gpTSD)
{
gint64 instCount;
SXTmpStateData* tsd = (SXTmpStateData*)gpTSD;
g_return_val_if_fail (node, FALSE);
if (! dom_tree_to_integer (node, &instCount))
{
return FALSE;
}
tsd->num_inst = instCount;
return TRUE;
}
struct dom_tree_handler sx_defer_dom_handlers[] =
{
/* tag name, handler, opt, ? */
{ SX_LAST, sx_defer_last_handler, 1, 0 },
{ SX_REM_OCCUR, sx_defer_rem_occur_handler, 1, 0 },
{ SX_INSTANCE_COUNT, sx_defer_inst_count_handler, 1, 0 },
{ NULL, NULL, 0, 0 }
};
static
gboolean
sx_defer_inst_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
SXTmpStateData* tsd;
g_return_val_if_fail (node, FALSE);
tsd = g_new0 (SXTmpStateData, 1);
g_assert (sx_defer_dom_handlers != NULL);
if (!dom_tree_generic_parse (node,
sx_defer_dom_handlers,
tsd))
{
xmlElemDump (stdout, NULL, node);
g_free (tsd);
tsd = NULL;
return FALSE;
}
/* We assume they were serialized in sorted order, here. */
sx->deferredList = g_list_append (sx->deferredList, tsd);
return TRUE;
}
static
gboolean
sx_numOccur_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
gint64 numOccur;
if (! dom_tree_to_integer (node, &numOccur))
{
return FALSE;
}
xaccSchedXactionSetNumOccur (sx, numOccur);
return TRUE;
}
static
gboolean
sx_templ_acct_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
GncGUID* templ_acct_guid = dom_tree_to_guid (node);
Account* account;
if (!templ_acct_guid)
{
return FALSE;
}
account = xaccAccountLookup (templ_acct_guid, pdata->book);
sx_set_template_account (sx, account);
guid_free (templ_acct_guid);
return TRUE;
}
static
gboolean
sx_remOccur_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
gint64 remOccur;
if (! dom_tree_to_integer (node, &remOccur))
{
return FALSE;
}
xaccSchedXactionSetRemOccur (sx, remOccur);
return TRUE;
}
static
gboolean
sx_slots_handler (xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata* pdata = static_cast<decltype (pdata)> (sx_pdata);
SchedXaction* sx = pdata->sx;
return dom_tree_create_instance_slots (node, QOF_INSTANCE (sx));
}
struct dom_tree_handler sx_dom_handlers[] =
{
{ SX_ID, sx_id_handler, 1, 0 },
{ SX_NAME, sx_name_handler, 1, 0 },
{ SX_ENABLED, sx_enabled_handler, 0, 0 },
{ SX_AUTOCREATE, sx_autoCreate_handler, 1, 0 },
{ SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 },
{ SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 },
{ SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 },
{ SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 },
{ SX_START, sx_start_handler, 1, 0 },
{ SX_LAST, sx_last_handler, 0, 0 },
{ SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 },
{ SX_REM_OCCUR, sx_remOccur_handler, 0, 0 },
{ SX_END, sx_end_handler, 0, 0 },
{ SX_TEMPL_ACCT, sx_templ_acct_handler, 0, 0 },
{ SX_FREQSPEC, sx_freqspec_handler, 0, 0 },
{ SX_SCHEDULE, sx_recurrence_handler, 0, 0 },
{ SX_DEFER_INSTANCE, sx_defer_inst_handler, 0, 0 },
{ SX_SLOTS, sx_slots_handler, 0, 0 },
{ NULL, NULL, 0, 0 }
};
static gboolean
gnc_schedXaction_end_handler (gpointer data_for_children,
GSList* data_from_children, GSList* sibling_data,
gpointer parent_data, gpointer global_data,
gpointer* result, const gchar* tag)
{
SchedXaction* sx;
gboolean successful = FALSE;
xmlNodePtr tree = (xmlNodePtr)data_for_children;
gxpf_data* gdata = (gxpf_data*)global_data;
struct sx_pdata sx_pdata;
if (parent_data)
{
return TRUE;
}
if (!tag)
{
return TRUE;
}
g_return_val_if_fail (tree, FALSE);
sx = xaccSchedXactionMalloc (static_cast<QofBook*> (gdata->bookdata));
memset (&sx_pdata, 0, sizeof (sx_pdata));
sx_pdata.sx = sx;
sx_pdata.book = static_cast<decltype (sx_pdata.book)> (gdata->bookdata);
g_assert (sx_dom_handlers != NULL);
successful = dom_tree_generic_parse (tree, sx_dom_handlers, &sx_pdata);
if (!successful)
{
g_critical ("failed to parse scheduled xaction");
xmlElemDump (stdout, NULL, tree);
gnc_sx_begin_edit (sx);
xaccSchedXactionDestroy (sx);
goto done;
}
if (tree->properties)
{
gchar* sx_name = xaccSchedXactionGetName (sx);
xmlAttr* attr;
for (attr = tree->properties; attr != NULL; attr = attr->next)
{
xmlChar* attr_value = attr->children->content;
g_debug ("sx attribute name[%s] value[%s]", attr->name, attr_value);
if (strcmp ((const char*)attr->name, "version") != 0)
{
g_warning ("unknown sx attribute [%s]", attr->name);
continue;
}
// if version == 1.0.0: ensure freqspec, no recurrence
// if version == 2.0.0: ensure recurrence, no freqspec.
if (strcmp ((const char*)attr_value,
schedxaction_version_string) == 0)
{
if (!sx_pdata.saw_freqspec)
g_critical ("did not see freqspec in version 1 sx [%s]", sx_name);
if (sx_pdata.saw_recurrence)
g_warning ("saw recurrence in supposedly version 1 sx [%s]", sx_name);
}
if (strcmp ((const char*)attr_value,
schedxaction_version2_string) == 0)
{
if (sx_pdata.saw_freqspec)
g_warning ("saw freqspec in version 2 sx [%s]", sx_name);
if (!sx_pdata.saw_recurrence)
g_critical ("did not find recurrence in version 2 sx [%s]", sx_name);
}
}
}
// generic_callback -> book_callback: insert the SX in the book
gdata->cb (tag, gdata->parsedata, sx);
/* FIXME: this should be removed somewhere near 1.8 release time. */
if (sx->template_acct == NULL)
{
Account* ra = NULL;
Account* acct = NULL;
sixtp_gdv2* sixdata = static_cast<decltype (sixdata)> (gdata->parsedata);
QofBook* book;
gchar guidstr[GUID_ENCODING_LENGTH + 1];
book = sixdata->book;
/* We're dealing with a pre-200107<near-end-of-month> rgmerk
change re: storing template accounts. */
/* Fix: get account with name of our GncGUID from the template
accounts. Make that our template_acct pointer. */
guid_to_string_buff (xaccSchedXactionGetGUID (sx), guidstr);
ra = gnc_book_get_template_root (book);
if (ra == NULL)
{
g_warning ("Error getting template root account from being-parsed Book.");
xmlFreeNode (tree);
return FALSE;
}
acct = gnc_account_lookup_by_name (ra, guidstr);
if (acct == NULL)
{
g_warning ("no template account with name [%s]", guidstr);
xmlFreeNode (tree);
return FALSE;
}
g_debug ("template account name [%s] for SX with GncGUID [%s]",
xaccAccountGetName (acct), guidstr);
/* FIXME: free existing template account.
* HUH????? We only execute this if there isn't
* currently an existing template account, don't we?
* <rgmerk>
*/
sx->template_acct = acct;
}
done:
xmlFreeNode (tree);
return successful;
}
sixtp*
gnc_schedXaction_sixtp_parser_create (void)
{
return sixtp_dom_parser_new (gnc_schedXaction_end_handler, NULL, NULL);
}
static
gboolean
tt_act_handler (xmlNodePtr node, gpointer data)
{
gnc_template_xaction_data* txd = static_cast<decltype (txd)> (data);
Account* acc;
gnc_commodity* com;
acc = dom_tree_to_account (node, txd->book);
if (acc == NULL)
{
return FALSE;
}
else
{
xaccAccountBeginEdit (acc);
/* Check for the lack of a commodity [signifying that the
pre-7/11/2001-CIT-change SX template Account was parsed [but
incorrectly]. */
if (xaccAccountGetCommodity (acc) == NULL)
{
#if 1
gnc_commodity_table* table;
table = gnc_commodity_table_get_table (txd->book);
com = gnc_commodity_table_lookup (table,
GNC_COMMODITY_NS_TEMPLATE, "template");
#else
/* FIXME: This should first look in the table of the
book, maybe? The right thing happens [WRT file
load/save] if we just _new all the time, but it
doesn't seem right. This whole block should go
away at some point, but the same concern still
applies for
SchedXaction.c:xaccSchedXactionInit... */
com = gnc_commodity_new (txd->book,
"template", GNC_COMMODITY_NS_TEMPLATE,
"template", "template",
1);
#endif
xaccAccountSetCommodity (acc, com);
}
txd->accts = g_list_append (txd->accts, acc);
}
return TRUE;
}
static
gboolean
tt_trn_handler (xmlNodePtr node, gpointer data)
{
gnc_template_xaction_data* txd = static_cast<decltype (txd)> (data);
Transaction* trn;
trn = dom_tree_to_transaction (node, txd->book);
if (trn == NULL)
{
return FALSE;
}
else
{
txd->transactions = g_list_append (txd->transactions, trn);
}
return TRUE;
}
struct dom_tree_handler tt_dom_handlers[] =
{
{ GNC_ACCOUNT_TAG, tt_act_handler, 0, 0 },
{ GNC_TRANSACTION_TAG, tt_trn_handler, 0, 0 },
{ NULL, NULL, 0, 0 },
};
static gboolean
gnc_template_transaction_end_handler (gpointer data_for_children,
GSList* data_from_children,
GSList* sibling_data,
gpointer parent_data,
gpointer global_data,
gpointer* result,
const gchar* tag)
{
gboolean successful = FALSE;
xmlNodePtr tree = static_cast<decltype (tree)> (data_for_children);
gxpf_data* gdata = static_cast<decltype (gdata)> (global_data);
QofBook* book = static_cast<decltype (book)> (gdata->bookdata);
GList* n;
gnc_template_xaction_data txd;
txd.book = book;
txd.accts = NULL;
txd.transactions = NULL;
/* the DOM tree will have an account tree [the template
accounts] and a list of transactions [which will be members
of the template account].
we want to parse through the dom trees for each, placing
the null-parent account in the book's template-group slot,
the others under it, and the transactions as normal. */
if (parent_data)
{
return TRUE;
}
if (!tag)
{
return TRUE;
}
g_return_val_if_fail (tree, FALSE);
successful = dom_tree_generic_parse (tree, tt_dom_handlers, &txd);
if (successful)
{
gdata->cb (tag, gdata->parsedata, &txd);
}
else
{
g_warning ("failed to parse template transaction");
xmlElemDump (stdout, NULL, tree);
}
/* cleanup */
for (n = txd.accts; n; n = n->next)
{
n->data = NULL;
}
for (n = txd.transactions; n; n = n->next)
{
n->data = NULL;
}
g_list_free (txd.accts);
g_list_free (txd.transactions);
xmlFreeNode (tree);
return successful;
}
sixtp*
gnc_template_transaction_sixtp_parser_create (void)
{
return sixtp_dom_parser_new (gnc_template_transaction_end_handler,
NULL, NULL);
}