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