GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-freqspec-xml-v2.cpp
1/********************************************************************
2 * gnc-freqspec-xml-v2.c -- xml routines for FreqSpecs *
3 * Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> *
4 * Copyright (C) 2001 Ben Stanley <bds02@uow.edu.au> *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22 * *
23 *******************************************************************/
24
25#include <glib.h>
26
27#include <config.h>
28#include <string.h>
29#include "qof.h"
30#include "SchedXaction.h"
31#include "FreqSpec.h"
32
33#include "gnc-xml-helper.h"
34#include "sixtp.h"
35#include "sixtp-utils.h"
36#include "sixtp-parsers.h"
37#include "sixtp-utils.h"
38#include "sixtp-dom-parsers.h"
39#include "sixtp-dom-generators.h"
40
41#include "gnc-xml.h"
42
43#include "io-gncxml-v2.h"
44
45#include "sixtp-dom-parsers.h"
46
47const gchar* freqspec_version_string = "1.0.0";
48
50{
51 const char* str;
52 FreqType ft;
53};
54
55struct freqTypeTuple freqTypeStrs[] =
56{
57 { "none", INVALID },
58 { "once", ONCE },
59 { "daily", DAILY },
60 { "weekly", WEEKLY },
61 { "monthly", MONTHLY },
62 { "month_relative", MONTH_RELATIVE },
63 { "composite", COMPOSITE },
64 { NULL, static_cast<FreqType> (-1) },
65};
66
68{
69 const char* str;
70 UIFreqType uift;
71};
72
73struct uiFreqTypeTuple uiFreqTypeStrs[] =
74{
75 { "none", UIFREQ_NONE },
76 { "once", UIFREQ_ONCE },
77 { "daily", UIFREQ_DAILY },
78 { "daily_mf", UIFREQ_DAILY_MF },
79 { "weekly", UIFREQ_WEEKLY },
80 { "bi_weekly", UIFREQ_BI_WEEKLY },
81 { "semi_monthly", UIFREQ_SEMI_MONTHLY },
82 { "monthly", UIFREQ_MONTHLY },
83 { "quarterly", UIFREQ_QUARTERLY },
84 { "tri_anually", UIFREQ_TRI_ANUALLY },
85 { "semi_yearly", UIFREQ_SEMI_YEARLY },
86 { "yearly", UIFREQ_YEARLY },
87 { NULL, static_cast<UIFreqType> (-1) }
88};
89
93typedef struct
94{
95 QofBook* book; /* Book we're loading into. */
96
97 Recurrence* recurrence;
98 GList* recurrence_list;
99
100 /* fields used in the union of unions... :) */
101 GDate once_day; /* once */
102 gint64 interval; /* all [except once] */
103 gint64 offset; /* all [except once] */
104 gint64 day; /* monthly or month-relative */
105 gint64 occurrence; /* month-relative */
106 gint64 weekend_adj; /* monthly/yearly */
107 GList* list; /* composite */
108 UIFreqType uift;
110
111static void
112fspd_init (fsParseData* fspd)
113{
114 fspd->list = NULL;
115 fspd->book = NULL;
116 fspd->recurrence = g_new0 (Recurrence, 1);
117 fspd->recurrence_list = NULL;
118 fspd->uift = UIFREQ_NONE;
119 fspd->interval
120 = fspd->offset
121 = fspd->day
122 = fspd->occurrence
123 = 0;
124 fspd->weekend_adj = WEEKEND_ADJ_NONE;
125 g_date_clear (&fspd->once_day, 1);
126}
127
128static
129gboolean
130gnc_fs_handler (xmlNodePtr node, gpointer d);
131
132static
133gboolean
134fs_uift_handler (xmlNodePtr node, gpointer data)
135{
136 fsParseData* fspd = static_cast<decltype (fspd)> (data);
137 int i;
138
139 auto nodeTxt = dom_tree_to_text (node);
140
141 g_return_val_if_fail (nodeTxt, FALSE);
142 for (i = 0; uiFreqTypeStrs[i].str != NULL; i++)
143 {
144 if (g_strcmp0 (nodeTxt->c_str(), uiFreqTypeStrs[i].str) == 0)
145 {
146 fspd->uift = uiFreqTypeStrs[i].uift;
147 return TRUE;
148 }
149 }
150 return FALSE;
151}
152
153static
154gboolean
155fs_date_handler (xmlNodePtr node, gpointer data)
156{
157 fsParseData* fspd = static_cast<decltype (fspd)> (data);
158 GDate* foo;
159 foo = dom_tree_to_gdate (node);
160 if (foo == NULL)
161 return FALSE;
162 fspd->once_day = *foo;
163 g_date_free (foo);
164 return TRUE;
165}
166
167static
168gboolean
169fs_interval_handler (xmlNodePtr node, gpointer data)
170{
171 fsParseData* fspd = static_cast<decltype (fspd)> (data);
172 gboolean ret;
173 gint64 foo;
174
175 ret = dom_tree_to_integer (node, &foo);
176 if (! ret)
177 {
178 return ret;
179 }
180 fspd->interval = foo;
181 return TRUE;
182}
183
184static
185gboolean
186fs_offset_handler (xmlNodePtr node, gpointer data)
187{
188 fsParseData* fspd = static_cast<decltype (fspd)> (data);
189 gboolean ret;
190 gint64 foo;
191
192 ret = dom_tree_to_integer (node, &foo);
193 if (! ret)
194 return ret;
195 fspd->offset = foo;
196 return TRUE;
197}
198
199static
200gboolean
201fs_day_handler (xmlNodePtr node, gpointer data)
202{
203 fsParseData* fspd = static_cast<decltype (fspd)> (data);
204 gboolean ret;
205 gint64 foo;
206
207 ret = dom_tree_to_integer (node, &foo);
208 if (! ret)
209 return ret;
210 fspd->day = foo;
211 return TRUE;
212}
213
214static
215gboolean
216fs_weekday_handler (xmlNodePtr node, gpointer data)
217{
218 fsParseData* fspd = static_cast<decltype (fspd)> (data);
219 gboolean ret;
220 gint64 foo;
221 ret = dom_tree_to_integer (node, &foo);
222 if (!ret)
223 return ret;
224 fspd->day = foo;
225 return TRUE;
226}
227
228static
229gboolean
230fs_occurrence_handler (xmlNodePtr node, gpointer data)
231{
232 fsParseData* fspd = static_cast<decltype (fspd)> (data);
233 gboolean ret;
234 gint64 foo;
235 ret = dom_tree_to_integer (node, &foo);
236 if (!ret)
237 return ret;
238 fspd->occurrence = foo;
239 return TRUE;
240}
241
242static
243gboolean
244fs_weekend_adj_handler (xmlNodePtr node, gpointer data)
245{
246 fsParseData* fspd = static_cast<decltype (fspd)> (data);
247 gboolean ret;
248 gint64 foo;
249 ret = dom_tree_to_integer (node, &foo);
250 if (!ret)
251 return ret;
252 fspd->weekend_adj = foo;
253 return TRUE;
254}
255
256static
257gboolean
258fs_subelement_handler (xmlNodePtr node, gpointer data)
259{
260 fsParseData* fspd = static_cast<decltype (fspd)> (data);
261 GList* recurrences;
262
263 recurrences = dom_tree_freqSpec_to_recurrences (node, fspd->book);
264 if (recurrences == NULL)
265 return FALSE;
266
267 {
268 GList* r_iter;
269 for (r_iter = recurrences; r_iter != NULL; r_iter = r_iter->next)
270 {
271 Recurrence* r = (Recurrence*)r_iter->data;
272 GDate recurrence_date;
273 if (fspd->uift == UIFREQ_SEMI_MONTHLY)
274 {
275 // complementry hack around 'once' freqspects not being valid. :/
276 recurrence_date = recurrenceGetDate (r);
277 recurrenceSet (r, recurrenceGetMultiplier (r), PERIOD_MONTH, &recurrence_date,
278 recurrenceGetWeekendAdjust (r));
279 }
280 fspd->recurrence_list = g_list_append (fspd->recurrence_list, r);
281 }
282 }
283 return TRUE;
284}
285
286struct dom_tree_handler fs_union_dom_handlers[] =
287{
288 { "fs:date", fs_date_handler, 0, 0 },
289 { "fs:interval", fs_interval_handler, 0, 0 },
290 { "fs:offset", fs_offset_handler, 0, 0 },
291 { "fs:day", fs_day_handler, 0, 0 },
292 { "fs:weekday", fs_weekday_handler, 0, 0 },
293 { "fs:occurrence", fs_occurrence_handler, 0, 0 },
294 { "fs:weekend_adj", fs_weekend_adj_handler, 0, 0 },
295 { "gnc:freqspec", fs_subelement_handler, 0, 0 },
296 { NULL, NULL, 0, 0 },
297};
298
299static gboolean
300fs_none_handler (xmlNodePtr node, gpointer data)
301{
302 fsParseData* fspd = static_cast<decltype (fspd)> (data);
303 gboolean successful;
304 successful = dom_tree_generic_parse (node,
305 fs_union_dom_handlers,
306 fspd);
307 return successful;
308}
309
310static
311gboolean
312fs_once_handler (xmlNodePtr node, gpointer data)
313{
314 fsParseData* fspd = static_cast<decltype (fspd)> (data);
315 gboolean successful;
316
317 successful = dom_tree_generic_parse (node,
318 fs_union_dom_handlers,
319 fspd);
320 if (!successful)
321 return FALSE;
322 recurrenceSet (fspd->recurrence, 0, PERIOD_ONCE, &fspd->once_day,
323 WEEKEND_ADJ_NONE);
324
325 return TRUE;
326}
327
328static gboolean
329fs_daily_handler (xmlNodePtr node, gpointer data)
330{
331 fsParseData* fspd = static_cast<decltype (fspd)> (data);
332 GDate offset_date;
333 gboolean successful;
334 successful = dom_tree_generic_parse (node, fs_union_dom_handlers, fspd);
335 if (!successful)
336 return FALSE;
337
338 g_date_clear (&offset_date, 1);
339 g_date_set_julian (&offset_date, fspd->offset == 0 ? 7 : fspd->offset);
340 recurrenceSet (fspd->recurrence, fspd->interval, PERIOD_DAY, &offset_date,
341 WEEKEND_ADJ_NONE);
342
343 return TRUE;
344}
345
346static
347gboolean
348fs_weekly_handler (xmlNodePtr node, gpointer data)
349{
350 fsParseData* fspd = static_cast<decltype (fspd)> (data);
351 GDate offset_date;
352 gboolean successful;
353 successful = dom_tree_generic_parse (node,
354 fs_union_dom_handlers,
355 fspd);
356 if (!successful)
357 return FALSE;
358
359 g_date_clear (&offset_date, 1);
360 g_date_set_julian (&offset_date, fspd->offset == 0 ? 7 : fspd->offset);
361 recurrenceSet (fspd->recurrence, fspd->interval, PERIOD_WEEK, &offset_date,
362 WEEKEND_ADJ_NONE);
363
364 return TRUE;
365}
366
367static
368gboolean
369fs_monthly_handler (xmlNodePtr node, gpointer data)
370{
371 fsParseData* fspd = static_cast<decltype (fspd)> (data);
372 GDate offset_date;
373 gboolean successful;
374 successful = dom_tree_generic_parse (node,
375 fs_union_dom_handlers,
376 fspd);
377 if (!successful)
378 return FALSE;
379
380
381 g_date_clear (&offset_date, 1);
382 g_date_set_julian (&offset_date, 1);
383 g_date_add_months (&offset_date, fspd->offset);
384 g_date_set_day (&offset_date, fspd->day);
385 if (fspd->uift == UIFREQ_ONCE)
386 {
387 // hack...
388 recurrenceSet (fspd->recurrence, fspd->interval, PERIOD_ONCE, &offset_date,
389 WEEKEND_ADJ_NONE);
390 }
391 else
392 {
393 recurrenceSet (fspd->recurrence, fspd->interval,
394 PERIOD_MONTH, &offset_date,
395 static_cast<WeekendAdjust> (fspd->weekend_adj));
396 }
397
398 return successful;
399}
400
401static
402gboolean
403fs_month_relative_handler (xmlNodePtr node, gpointer data)
404{
405 g_critical ("this was never supported, how is it in the datafile?");
406 return FALSE;
407}
408
409static
410gboolean
411fs_guid_handler (xmlNodePtr node, gpointer data)
412{
413 return TRUE;
414}
415
416static
417gboolean
418fs_composite_handler (xmlNodePtr node, gpointer data)
419{
420 fsParseData* fspd = static_cast<decltype (fspd)> (data);
421 gboolean successful;
422 successful = dom_tree_generic_parse (node,
423 fs_union_dom_handlers,
424 fspd);
425 return successful;
426}
427
428static struct dom_tree_handler fs_dom_handlers[] =
429{
430 { "gnc:freqspec", gnc_fs_handler, 0, 0 },
431 { "fs:ui_type", fs_uift_handler, 1, 0 },
432 { "fs:id", fs_guid_handler, 1, 0 },
433 { "fs:none", fs_none_handler, 0, 0 },
434 { "fs:once", fs_once_handler, 0, 0 },
435 { "fs:daily", fs_daily_handler, 0, 0 },
436 { "fs:weekly", fs_weekly_handler, 0, 0 },
437 { "fs:monthly", fs_monthly_handler, 0, 0 },
438 { "fs:month_relative", fs_month_relative_handler, 0, 0 },
439 { "fs:composite", fs_composite_handler, 0, 0 },
440 { NULL, NULL, 0, 0 }
441};
442
443static
444gboolean
445gnc_fs_handler (xmlNodePtr node, gpointer d)
446{
447 return dom_tree_generic_parse (node, fs_dom_handlers, d);
448}
449
450static
451gboolean
452gnc_freqSpec_end_handler (gpointer data_for_children,
453 GSList* data_from_children, GSList* sibling_data,
454 gpointer parent_data, gpointer global_data,
455 gpointer* result, const gchar* tag)
456{
457 fsParseData fspd;
458 gboolean successful = FALSE;
459 xmlNodePtr tree = (xmlNodePtr)data_for_children;
460 sixtp_gdv2* globaldata = (sixtp_gdv2*)global_data;
461
462 fspd_init (&fspd);
463 fspd.book = globaldata->book;
464
465 /* this won't actually get invoked [FreqSpecs aren't top-level
466 elements]; see dom_tree_to_freqSpec(), below. */
467 if (parent_data)
468 return TRUE;
469
470 if (!tag)
471 return TRUE;
472
473 g_return_val_if_fail (tree, FALSE);
474
475 successful = dom_tree_generic_parse (tree, fs_dom_handlers, &fspd);
476 if (!successful)
477 {
478 xmlElemDump (stdout, NULL, tree);
479 }
480
481 xmlFreeNode (tree);
482
483 return successful;
484}
485
486sixtp*
487gnc_freqSpec_sixtp_parser_create (void)
488{
489 return sixtp_dom_parser_new (gnc_freqSpec_end_handler, NULL, NULL);
490}
491
492static void
493common_parse (fsParseData* fspd, xmlNodePtr node, QofBook* book)
494{
495 gboolean successful;
496
497 fspd->book = book;
498 successful = dom_tree_generic_parse (node, fs_dom_handlers, fspd);
499 if (!successful)
500 {
501 xmlElemDump (stdout, NULL, node);
502 }
503}
504
505GList*
506dom_tree_freqSpec_to_recurrences (xmlNodePtr node, QofBook* book)
507{
508 fsParseData fspd;
509 fspd_init (&fspd);
510 common_parse (&fspd, node, book);
511 if (fspd.recurrence_list == NULL)
512 {
513 fspd.recurrence_list = g_list_append (fspd.recurrence_list, fspd.recurrence);
514 }
515 return fspd.recurrence_list;
516}
Period / Date Frequency Specification.
Scheduled Transactions public handling routines.
FreqType
Frequency specification.
Definition FreqSpec.h:43
UIFreqType
The user's conception of the frequency.
Definition FreqSpec.h:68
api for GnuCash version 2 XML-based file format
QofBook reference.
Definition qofbook-p.hpp:47
Struct passed around as user-data when parsing the FreqSpec.
Definition sixtp.h:130