gnucash/libgnucash/backend/xml/gnc-freqspec-xml-v2.cpp
Geert Janssens 1238b9d8cd Prevent gcc from searching config.h in the current directory
This will avoid a ninja-build from picking up a config.h generated by the autotools build
(in the root build directory). Picking up the wrong config.h may lead to all kinds of
subtle issues if the autotools run was done with different options than the cmake run.
2017-10-26 14:05:17 +02: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 *
* *
*******************************************************************/
extern "C"
{
#include <config.h>
#include <glib.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;
}