gnucash/libgnucash/backend/xml/gnc-freqspec-xml-v2.cpp
John Ralls bbb4113a5a Bug 798156 - glib 2.68.0 breaks gnucash
Move all of the #include <glib> to before the extern "C" blocks
so that the include guards will protect against headers inside
the extern "C" block also including glib.h.
2021-04-20 11:03:23 -07:00

523 lines
14 KiB
C++

/********************************************************************
* gnc-freqspec-xml-v2.c -- xml routines for FreqSpecs *
* Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
* Copyright (C) 2001 Ben Stanley <bds02@uow.edu.au> *
* *
* 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 *
* *
*******************************************************************/
#include <glib.h>
extern "C"
{
#include <config.h>
#include <string.h>
#include "qof.h"
#include "SchedXaction.h"
#include "FreqSpec.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 "sixtp-dom-parsers.h"
const gchar* freqspec_version_string = "1.0.0";
struct freqTypeTuple
{
const char* str;
FreqType ft;
};
struct freqTypeTuple freqTypeStrs[] =
{
{ "none", INVALID },
{ "once", ONCE },
{ "daily", DAILY },
{ "weekly", WEEKLY },
{ "monthly", MONTHLY },
{ "month_relative", MONTH_RELATIVE },
{ "composite", COMPOSITE },
{ NULL, static_cast<FreqType> (-1) },
};
struct uiFreqTypeTuple
{
const char* str;
UIFreqType uift;
};
struct uiFreqTypeTuple uiFreqTypeStrs[] =
{
{ "none", UIFREQ_NONE },
{ "once", UIFREQ_ONCE },
{ "daily", UIFREQ_DAILY },
{ "daily_mf", UIFREQ_DAILY_MF },
{ "weekly", UIFREQ_WEEKLY },
{ "bi_weekly", UIFREQ_BI_WEEKLY },
{ "semi_monthly", UIFREQ_SEMI_MONTHLY },
{ "monthly", UIFREQ_MONTHLY },
{ "quarterly", UIFREQ_QUARTERLY },
{ "tri_anually", UIFREQ_TRI_ANUALLY },
{ "semi_yearly", UIFREQ_SEMI_YEARLY },
{ "yearly", UIFREQ_YEARLY },
{ NULL, static_cast<UIFreqType> (-1) }
};
/**
* Struct passed around as user-data when parsing the FreqSpec.
**/
typedef struct
{
QofBook* book; /* Book we're loading into. */
Recurrence* recurrence;
GList* recurrence_list;
/* fields used in the union of unions... :) */
GDate once_day; /* once */
gint64 interval; /* all [except once] */
gint64 offset; /* all [except once] */
gint64 day; /* monthly or month-relative */
gint64 occurrence; /* month-relative */
gint64 weekend_adj; /* monthly/yearly */
GList* list; /* composite */
UIFreqType uift;
} fsParseData;
static void
fspd_init (fsParseData* fspd)
{
fspd->list = NULL;
fspd->book = NULL;
fspd->recurrence = g_new0 (Recurrence, 1);
fspd->recurrence_list = NULL;
fspd->uift = UIFREQ_NONE;
fspd->interval
= fspd->offset
= fspd->day
= fspd->occurrence
= 0;
fspd->weekend_adj = WEEKEND_ADJ_NONE;
g_date_clear (&fspd->once_day, 1);
}
static
gboolean
gnc_fs_handler (xmlNodePtr node, gpointer d);
static
gboolean
fs_uift_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
int i;
char* nodeTxt;
nodeTxt = dom_tree_to_text (node);
g_return_val_if_fail (nodeTxt, FALSE);
for (i = 0; uiFreqTypeStrs[i].str != NULL; i++)
{
if (g_strcmp0 (nodeTxt, uiFreqTypeStrs[i].str) == 0)
{
fspd->uift = uiFreqTypeStrs[i].uift;
g_free (nodeTxt);
return TRUE;
}
}
g_free (nodeTxt);
return FALSE;
}
static
gboolean
fs_date_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
GDate* foo;
foo = dom_tree_to_gdate (node);
if (foo == NULL)
return FALSE;
fspd->once_day = *foo;
g_date_free (foo);
return TRUE;
}
static
gboolean
fs_interval_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
gboolean ret;
gint64 foo;
ret = dom_tree_to_integer (node, &foo);
if (! ret)
{
return ret;
}
fspd->interval = foo;
return TRUE;
}
static
gboolean
fs_offset_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
gboolean ret;
gint64 foo;
ret = dom_tree_to_integer (node, &foo);
if (! ret)
return ret;
fspd->offset = foo;
return TRUE;
}
static
gboolean
fs_day_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
gboolean ret;
gint64 foo;
ret = dom_tree_to_integer (node, &foo);
if (! ret)
return ret;
fspd->day = foo;
return TRUE;
}
static
gboolean
fs_weekday_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
gboolean ret;
gint64 foo;
ret = dom_tree_to_integer (node, &foo);
if (!ret)
return ret;
fspd->day = foo;
return TRUE;
}
static
gboolean
fs_occurrence_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
gboolean ret;
gint64 foo;
ret = dom_tree_to_integer (node, &foo);
if (!ret)
return ret;
fspd->occurrence = foo;
return TRUE;
}
static
gboolean
fs_weekend_adj_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
gboolean ret;
gint64 foo;
ret = dom_tree_to_integer (node, &foo);
if (!ret)
return ret;
fspd->weekend_adj = foo;
return TRUE;
}
static
gboolean
fs_subelement_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
GList* recurrences;
recurrences = dom_tree_freqSpec_to_recurrences (node, fspd->book);
if (recurrences == NULL)
return FALSE;
{
GList* r_iter;
for (r_iter = recurrences; r_iter != NULL; r_iter = r_iter->next)
{
Recurrence* r = (Recurrence*)r_iter->data;
GDate recurrence_date;
if (fspd->uift == UIFREQ_SEMI_MONTHLY)
{
// complementry hack around 'once' freqspects not being valid. :/
recurrence_date = recurrenceGetDate (r);
recurrenceSet (r, recurrenceGetMultiplier (r), PERIOD_MONTH, &recurrence_date,
recurrenceGetWeekendAdjust (r));
}
fspd->recurrence_list = g_list_append (fspd->recurrence_list, r);
}
}
return TRUE;
}
struct dom_tree_handler fs_union_dom_handlers[] =
{
{ "fs:date", fs_date_handler, 0, 0 },
{ "fs:interval", fs_interval_handler, 0, 0 },
{ "fs:offset", fs_offset_handler, 0, 0 },
{ "fs:day", fs_day_handler, 0, 0 },
{ "fs:weekday", fs_weekday_handler, 0, 0 },
{ "fs:occurrence", fs_occurrence_handler, 0, 0 },
{ "fs:weekend_adj", fs_weekend_adj_handler, 0, 0 },
{ "gnc:freqspec", fs_subelement_handler, 0, 0 },
{ NULL, NULL, 0, 0 },
};
static gboolean
fs_none_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
gboolean successful;
successful = dom_tree_generic_parse (node,
fs_union_dom_handlers,
fspd);
return successful;
}
static
gboolean
fs_once_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
gboolean successful;
successful = dom_tree_generic_parse (node,
fs_union_dom_handlers,
fspd);
if (!successful)
return FALSE;
recurrenceSet (fspd->recurrence, 0, PERIOD_ONCE, &fspd->once_day,
WEEKEND_ADJ_NONE);
return TRUE;
}
static gboolean
fs_daily_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
GDate offset_date;
gboolean successful;
successful = dom_tree_generic_parse (node, fs_union_dom_handlers, fspd);
if (!successful)
return FALSE;
g_date_clear (&offset_date, 1);
g_date_set_julian (&offset_date, fspd->offset == 0 ? 7 : fspd->offset);
recurrenceSet (fspd->recurrence, fspd->interval, PERIOD_DAY, &offset_date,
WEEKEND_ADJ_NONE);
return TRUE;
}
static
gboolean
fs_weekly_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
GDate offset_date;
gboolean successful;
successful = dom_tree_generic_parse (node,
fs_union_dom_handlers,
fspd);
if (!successful)
return FALSE;
g_date_clear (&offset_date, 1);
g_date_set_julian (&offset_date, fspd->offset == 0 ? 7 : fspd->offset);
recurrenceSet (fspd->recurrence, fspd->interval, PERIOD_WEEK, &offset_date,
WEEKEND_ADJ_NONE);
return TRUE;
}
static
gboolean
fs_monthly_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
GDate offset_date;
gboolean successful;
successful = dom_tree_generic_parse (node,
fs_union_dom_handlers,
fspd);
if (!successful)
return FALSE;
g_date_clear (&offset_date, 1);
g_date_set_julian (&offset_date, 1);
g_date_add_months (&offset_date, fspd->offset);
g_date_set_day (&offset_date, fspd->day);
if (fspd->uift == UIFREQ_ONCE)
{
// hack...
recurrenceSet (fspd->recurrence, fspd->interval, PERIOD_ONCE, &offset_date,
WEEKEND_ADJ_NONE);
}
else
{
recurrenceSet (fspd->recurrence, fspd->interval,
PERIOD_MONTH, &offset_date,
static_cast<WeekendAdjust> (fspd->weekend_adj));
}
return successful;
}
static
gboolean
fs_month_relative_handler (xmlNodePtr node, gpointer data)
{
g_critical ("this was never supported, how is it in the datafile?");
return FALSE;
}
static
gboolean
fs_guid_handler (xmlNodePtr node, gpointer data)
{
return TRUE;
}
static
gboolean
fs_composite_handler (xmlNodePtr node, gpointer data)
{
fsParseData* fspd = static_cast<decltype (fspd)> (data);
gboolean successful;
successful = dom_tree_generic_parse (node,
fs_union_dom_handlers,
fspd);
return successful;
}
static struct dom_tree_handler fs_dom_handlers[] =
{
{ "gnc:freqspec", gnc_fs_handler, 0, 0 },
{ "fs:ui_type", fs_uift_handler, 1, 0 },
{ "fs:id", fs_guid_handler, 1, 0 },
{ "fs:none", fs_none_handler, 0, 0 },
{ "fs:once", fs_once_handler, 0, 0 },
{ "fs:daily", fs_daily_handler, 0, 0 },
{ "fs:weekly", fs_weekly_handler, 0, 0 },
{ "fs:monthly", fs_monthly_handler, 0, 0 },
{ "fs:month_relative", fs_month_relative_handler, 0, 0 },
{ "fs:composite", fs_composite_handler, 0, 0 },
{ NULL, NULL, 0, 0 }
};
static
gboolean
gnc_fs_handler (xmlNodePtr node, gpointer d)
{
return dom_tree_generic_parse (node, fs_dom_handlers, d);
}
static
gboolean
gnc_freqSpec_end_handler (gpointer data_for_children,
GSList* data_from_children, GSList* sibling_data,
gpointer parent_data, gpointer global_data,
gpointer* result, const gchar* tag)
{
fsParseData fspd;
gboolean successful = FALSE;
xmlNodePtr tree = (xmlNodePtr)data_for_children;
sixtp_gdv2* globaldata = (sixtp_gdv2*)global_data;
fspd_init (&fspd);
fspd.book = globaldata->book;
/* this won't actually get invoked [FreqSpecs aren't top-level
elements]; see dom_tree_to_freqSpec(), below. */
if (parent_data)
return TRUE;
if (!tag)
return TRUE;
g_return_val_if_fail (tree, FALSE);
successful = dom_tree_generic_parse (tree, fs_dom_handlers, &fspd);
if (!successful)
{
xmlElemDump (stdout, NULL, tree);
}
xmlFreeNode (tree);
return successful;
}
sixtp*
gnc_freqSpec_sixtp_parser_create (void)
{
return sixtp_dom_parser_new (gnc_freqSpec_end_handler, NULL, NULL);
}
static void
common_parse (fsParseData* fspd, xmlNodePtr node, QofBook* book)
{
gboolean successful;
fspd->book = book;
successful = dom_tree_generic_parse (node, fs_dom_handlers, fspd);
if (!successful)
{
xmlElemDump (stdout, NULL, node);
}
}
GList*
dom_tree_freqSpec_to_recurrences (xmlNodePtr node, QofBook* book)
{
fsParseData fspd;
fspd_init (&fspd);
common_parse (&fspd, node, book);
if (fspd.recurrence_list == NULL)
{
fspd.recurrence_list = g_list_append (fspd.recurrence_list, fspd.recurrence);
}
return fspd.recurrence_list;
}