|
GnuCash 2.4.99
|
00001 /******************************************************************** 00002 * gnc-freqspec-xml-v2.c -- xml routines for FreqSpecs * 00003 * Copyright (C) 2001 Joshua Sled <jsled@asynchronous.org> * 00004 * Copyright (C) 2001 Ben Stanley <bds02@uow.edu.au> * 00005 * * 00006 * This program is free software; you can redistribute it and/or * 00007 * modify it under the terms of the GNU General Public License as * 00008 * published by the Free Software Foundation; either version 2 of * 00009 * the License, or (at your option) any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License* 00017 * along with this program; if not, contact: * 00018 * * 00019 * Free Software Foundation Voice: +1-617-542-5942 * 00020 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00021 * Boston, MA 02110-1301, USA gnu@gnu.org * 00022 * * 00023 *******************************************************************/ 00024 00025 00026 #include "config.h" 00027 00028 #include <glib.h> 00029 #include <string.h> 00030 00031 #include "gnc-xml-helper.h" 00032 #include "qof.h" 00033 00034 #include "sixtp.h" 00035 #include "sixtp-utils.h" 00036 #include "sixtp-parsers.h" 00037 #include "sixtp-utils.h" 00038 #include "sixtp-dom-parsers.h" 00039 #include "sixtp-dom-generators.h" 00040 00041 #include "gnc-xml.h" 00042 00043 #include "io-gncxml-v2.h" 00044 00045 #include "sixtp-dom-parsers.h" 00046 #include "SchedXaction.h" 00047 #include "FreqSpec.h" 00048 00049 const gchar *freqspec_version_string = "1.0.0"; 00050 00051 struct freqTypeTuple 00052 { 00053 char *str; 00054 FreqType ft; 00055 }; 00056 00057 struct freqTypeTuple freqTypeStrs[] = 00058 { 00059 { "none", INVALID }, 00060 { "once", ONCE }, 00061 { "daily", DAILY }, 00062 { "weekly", WEEKLY }, 00063 { "monthly", MONTHLY }, 00064 { "month_relative", MONTH_RELATIVE }, 00065 { "composite", COMPOSITE }, 00066 { NULL, -1 }, 00067 }; 00068 00069 struct uiFreqTypeTuple 00070 { 00071 char *str; 00072 UIFreqType uift; 00073 }; 00074 00075 struct uiFreqTypeTuple uiFreqTypeStrs[] = 00076 { 00077 { "none", UIFREQ_NONE }, 00078 { "once", UIFREQ_ONCE }, 00079 { "daily", UIFREQ_DAILY }, 00080 { "daily_mf", UIFREQ_DAILY_MF }, 00081 { "weekly", UIFREQ_WEEKLY }, 00082 { "bi_weekly", UIFREQ_BI_WEEKLY }, 00083 { "semi_monthly", UIFREQ_SEMI_MONTHLY }, 00084 { "monthly", UIFREQ_MONTHLY }, 00085 { "quarterly", UIFREQ_QUARTERLY }, 00086 { "tri_anually", UIFREQ_TRI_ANUALLY }, 00087 { "semi_yearly", UIFREQ_SEMI_YEARLY }, 00088 { "yearly", UIFREQ_YEARLY }, 00089 { NULL, -1 } 00090 }; 00091 00095 typedef struct 00096 { 00097 QofBook *book; /* Book we're loading into. */ 00098 00099 Recurrence *recurrence; 00100 GList *recurrence_list; 00101 00102 /* fields used in the union of unions... :) */ 00103 GDate once_day; /* once */ 00104 gint64 interval; /* all [except once] */ 00105 gint64 offset; /* all [except once] */ 00106 gint64 day; /* monthly or month-relative */ 00107 gint64 occurrence; /* month-relative */ 00108 gint64 weekend_adj; /* monthly/yearly */ 00109 GList *list; /* composite */ 00110 UIFreqType uift; 00111 } fsParseData; 00112 00113 static void 00114 fspd_init( fsParseData *fspd ) 00115 { 00116 fspd->list = NULL; 00117 fspd->book = NULL; 00118 fspd->recurrence = g_new0(Recurrence, 1); 00119 fspd->recurrence_list = NULL; 00120 fspd->uift = UIFREQ_NONE; 00121 fspd->interval 00122 = fspd->offset 00123 = fspd->day 00124 = fspd->occurrence 00125 = 0; 00126 fspd->weekend_adj = WEEKEND_ADJ_NONE; 00127 g_date_clear( &fspd->once_day, 1 ); 00128 } 00129 00130 static 00131 gboolean 00132 gnc_fs_handler( xmlNodePtr node, gpointer d ); 00133 00134 static 00135 gboolean 00136 fs_uift_handler( xmlNodePtr node, gpointer data) 00137 { 00138 fsParseData *fspd = data; 00139 int i; 00140 char *nodeTxt; 00141 char *tmp; 00142 00143 nodeTxt = dom_tree_to_text( node ); 00144 00145 g_return_val_if_fail( nodeTxt, FALSE ); 00146 for ( i = 0; (tmp = uiFreqTypeStrs[i].str) != NULL; i++ ) 00147 { 00148 if ( safe_strcmp( nodeTxt, tmp ) == 0 ) 00149 { 00150 fspd->uift = uiFreqTypeStrs[i].uift; 00151 g_free( nodeTxt ); 00152 return TRUE; 00153 } 00154 } 00155 g_free( nodeTxt ); 00156 return FALSE; 00157 } 00158 00159 static 00160 gboolean 00161 fs_date_handler( xmlNodePtr node, gpointer data ) 00162 { 00163 fsParseData *fspd = data; 00164 GDate *foo; 00165 foo = dom_tree_to_gdate( node ); 00166 if ( foo == NULL ) 00167 return FALSE; 00168 fspd->once_day = *foo; 00169 g_date_free( foo ); 00170 return TRUE; 00171 } 00172 00173 static 00174 gboolean 00175 fs_interval_handler( xmlNodePtr node, gpointer data ) 00176 { 00177 fsParseData *fspd = data; 00178 gboolean ret; 00179 gint64 foo; 00180 00181 ret = dom_tree_to_integer( node, &foo ); 00182 if ( ! ret ) 00183 { 00184 return ret; 00185 } 00186 fspd->interval = foo; 00187 return TRUE; 00188 } 00189 00190 static 00191 gboolean 00192 fs_offset_handler( xmlNodePtr node, gpointer data ) 00193 { 00194 fsParseData *fspd = data; 00195 gboolean ret; 00196 gint64 foo; 00197 00198 ret = dom_tree_to_integer( node, &foo ); 00199 if ( ! ret ) 00200 return ret; 00201 fspd->offset = foo; 00202 return TRUE; 00203 } 00204 00205 static 00206 gboolean 00207 fs_day_handler( xmlNodePtr node, gpointer data ) 00208 { 00209 fsParseData *fspd = data; 00210 gboolean ret; 00211 gint64 foo; 00212 00213 ret = dom_tree_to_integer( node, &foo ); 00214 if ( ! ret ) 00215 return ret; 00216 fspd->day = foo; 00217 return TRUE; 00218 } 00219 00220 static 00221 gboolean 00222 fs_weekday_handler( xmlNodePtr node, gpointer data) 00223 { 00224 fsParseData *fspd = data; 00225 gboolean ret; 00226 gint64 foo; 00227 ret = dom_tree_to_integer( node, &foo ); 00228 if ( !ret ) 00229 return ret; 00230 fspd->day = foo; 00231 return TRUE; 00232 } 00233 00234 static 00235 gboolean 00236 fs_occurrence_handler( xmlNodePtr node, gpointer data ) 00237 { 00238 fsParseData *fspd = data; 00239 gboolean ret; 00240 gint64 foo; 00241 ret = dom_tree_to_integer( node, &foo ); 00242 if ( !ret ) 00243 return ret; 00244 fspd->occurrence = foo; 00245 return TRUE; 00246 } 00247 00248 static 00249 gboolean 00250 fs_weekend_adj_handler( xmlNodePtr node, gpointer data ) 00251 { 00252 fsParseData *fspd = data; 00253 gboolean ret; 00254 gint64 foo; 00255 ret = dom_tree_to_integer( node, &foo ); 00256 if ( !ret ) 00257 return ret; 00258 fspd->weekend_adj = foo; 00259 return TRUE; 00260 } 00261 00262 static 00263 gboolean 00264 fs_subelement_handler( xmlNodePtr node, gpointer data ) 00265 { 00266 fsParseData *fspd = data; 00267 GList *recurrences; 00268 00269 recurrences = dom_tree_freqSpec_to_recurrences(node, fspd->book); 00270 if (recurrences == NULL) 00271 return FALSE; 00272 00273 { 00274 GList *r_iter; 00275 for (r_iter = recurrences; r_iter != NULL; r_iter = r_iter->next) 00276 { 00277 Recurrence *r = (Recurrence*)r_iter->data; 00278 GDate recurrence_date; 00279 if (fspd->uift == UIFREQ_SEMI_MONTHLY) 00280 { 00281 // complementry hack around 'once' freqspects not being valid. :/ 00282 recurrence_date = recurrenceGetDate(r); 00283 recurrenceSet(r, recurrenceGetMultiplier(r), PERIOD_MONTH, &recurrence_date, recurrenceGetWeekendAdjust(r)); 00284 } 00285 fspd->recurrence_list = g_list_append(fspd->recurrence_list, r); 00286 } 00287 } 00288 return TRUE; 00289 } 00290 00291 struct dom_tree_handler fs_union_dom_handlers[] = 00292 { 00293 { "fs:date", fs_date_handler, 0, 0 }, 00294 { "fs:interval", fs_interval_handler, 0, 0 }, 00295 { "fs:offset", fs_offset_handler, 0, 0 }, 00296 { "fs:day", fs_day_handler, 0, 0 }, 00297 { "fs:weekday", fs_weekday_handler, 0, 0 }, 00298 { "fs:occurrence", fs_occurrence_handler, 0, 0 }, 00299 { "fs:weekend_adj", fs_weekend_adj_handler, 0, 0 }, 00300 { "gnc:freqspec", fs_subelement_handler, 0, 0 }, 00301 { NULL, NULL, 0, 0 }, 00302 }; 00303 00304 static gboolean 00305 fs_none_handler( xmlNodePtr node, gpointer data ) 00306 { 00307 fsParseData *fspd = data; 00308 gboolean successful; 00309 successful = dom_tree_generic_parse( node, 00310 fs_union_dom_handlers, 00311 fspd ); 00312 return successful; 00313 } 00314 00315 static 00316 gboolean 00317 fs_once_handler( xmlNodePtr node, gpointer data ) 00318 { 00319 fsParseData *fspd = data; 00320 gboolean successful; 00321 00322 successful = dom_tree_generic_parse( node, 00323 fs_union_dom_handlers, 00324 fspd ); 00325 if ( !successful ) 00326 return FALSE; 00327 recurrenceSet(fspd->recurrence, 0, PERIOD_ONCE, &fspd->once_day, WEEKEND_ADJ_NONE); 00328 00329 return TRUE; 00330 } 00331 00332 static gboolean 00333 fs_daily_handler(xmlNodePtr node, gpointer data) 00334 { 00335 fsParseData *fspd = data; 00336 GDate offset_date; 00337 gboolean successful; 00338 successful = dom_tree_generic_parse(node, fs_union_dom_handlers, fspd ); 00339 if (!successful) 00340 return FALSE; 00341 00342 g_date_clear(&offset_date, 1); 00343 g_date_set_julian(&offset_date, fspd->offset == 0 ? 7 : fspd->offset); 00344 recurrenceSet(fspd->recurrence, fspd->interval, PERIOD_DAY, &offset_date, WEEKEND_ADJ_NONE); 00345 00346 return TRUE; 00347 } 00348 00349 static 00350 gboolean 00351 fs_weekly_handler( xmlNodePtr node, gpointer data ) 00352 { 00353 fsParseData *fspd = data; 00354 GDate offset_date; 00355 gboolean successful; 00356 successful = dom_tree_generic_parse( node, 00357 fs_union_dom_handlers, 00358 fspd ); 00359 if ( !successful ) 00360 return FALSE; 00361 00362 g_date_clear(&offset_date, 1); 00363 g_date_set_julian(&offset_date, fspd->offset == 0 ? 7 : fspd->offset); 00364 recurrenceSet(fspd->recurrence, fspd->interval, PERIOD_WEEK, &offset_date, WEEKEND_ADJ_NONE); 00365 00366 return TRUE; 00367 } 00368 00369 static 00370 gboolean 00371 fs_monthly_handler( xmlNodePtr node, gpointer data) 00372 { 00373 fsParseData *fspd = data; 00374 GDate offset_date; 00375 gboolean successful; 00376 successful = dom_tree_generic_parse( node, 00377 fs_union_dom_handlers, 00378 fspd ); 00379 if ( !successful ) 00380 return FALSE; 00381 00382 00383 g_date_clear(&offset_date, 1); 00384 g_date_set_julian(&offset_date, 1); 00385 g_date_add_months(&offset_date, fspd->offset); 00386 g_date_set_day(&offset_date, fspd->day); 00387 if (fspd->uift == UIFREQ_ONCE) 00388 { 00389 // hack... 00390 recurrenceSet(fspd->recurrence, fspd->interval, PERIOD_ONCE, &offset_date, WEEKEND_ADJ_NONE); 00391 } 00392 else 00393 { 00394 recurrenceSet(fspd->recurrence, fspd->interval, PERIOD_MONTH, &offset_date, fspd->weekend_adj); 00395 } 00396 00397 return successful; 00398 } 00399 00400 static 00401 gboolean 00402 fs_month_relative_handler( xmlNodePtr node, gpointer data) 00403 { 00404 g_critical("this was never supported, how is it in the datafile?"); 00405 return FALSE; 00406 } 00407 00408 static 00409 gboolean 00410 fs_guid_handler( xmlNodePtr node, gpointer data) 00411 { 00412 fsParseData *fspd = data; 00413 GncGUID *guid; 00414 guid = dom_tree_to_guid( node ); 00415 return TRUE; 00416 } 00417 00418 static 00419 gboolean 00420 fs_composite_handler( xmlNodePtr node, gpointer data) 00421 { 00422 fsParseData *fspd = data; 00423 gboolean successful; 00424 successful = dom_tree_generic_parse( node, 00425 fs_union_dom_handlers, 00426 fspd ); 00427 return successful; 00428 } 00429 00430 static struct dom_tree_handler fs_dom_handlers[] = 00431 { 00432 { "gnc:freqspec", gnc_fs_handler, 0, 0 }, 00433 { "fs:ui_type", fs_uift_handler, 1, 0 }, 00434 { "fs:id", fs_guid_handler, 1, 0 }, 00435 { "fs:none", fs_none_handler, 0, 0 }, 00436 { "fs:once", fs_once_handler, 0, 0 }, 00437 { "fs:daily", fs_daily_handler, 0, 0 }, 00438 { "fs:weekly", fs_weekly_handler, 0, 0 }, 00439 { "fs:monthly", fs_monthly_handler, 0, 0 }, 00440 { "fs:month_relative", fs_month_relative_handler, 0, 0 }, 00441 { "fs:composite", fs_composite_handler, 0, 0 }, 00442 { NULL, NULL, 0, 0 } 00443 }; 00444 00445 static 00446 gboolean 00447 gnc_fs_handler( xmlNodePtr node, gpointer d ) 00448 { 00449 return dom_tree_generic_parse( node, fs_dom_handlers, d ); 00450 } 00451 00452 static 00453 gboolean 00454 gnc_freqSpec_end_handler(gpointer data_for_children, 00455 GSList* data_from_children, GSList* sibling_data, 00456 gpointer parent_data, gpointer global_data, 00457 gpointer *result, const gchar *tag) 00458 { 00459 fsParseData fspd; 00460 gboolean successful = FALSE; 00461 xmlNodePtr tree = (xmlNodePtr)data_for_children; 00462 sixtp_gdv2 *globaldata = (sixtp_gdv2*)global_data; 00463 00464 fspd_init( &fspd ); 00465 fspd.book = globaldata->book; 00466 00467 /* this won't actually get invoked [FreqSpecs aren't top-level 00468 elements]; see dom_tree_to_freqSpec(), below. */ 00469 if ( parent_data ) 00470 return TRUE; 00471 00472 if ( !tag ) 00473 return TRUE; 00474 00475 g_return_val_if_fail( tree, FALSE ); 00476 00477 successful = dom_tree_generic_parse( tree, fs_dom_handlers, &fspd ); 00478 if (!successful) 00479 { 00480 xmlElemDump( stdout, NULL, tree ); 00481 } 00482 00483 xmlFreeNode(tree); 00484 00485 return successful; 00486 } 00487 00488 sixtp* 00489 gnc_freqSpec_sixtp_parser_create(void) 00490 { 00491 return sixtp_dom_parser_new( gnc_freqSpec_end_handler, NULL, NULL ); 00492 } 00493 00494 static void 00495 common_parse(fsParseData *fspd, xmlNodePtr node, QofBook *book) 00496 { 00497 gboolean successful; 00498 00499 fspd->book = book; 00500 successful = dom_tree_generic_parse( node, fs_dom_handlers, fspd ); 00501 if (!successful) 00502 { 00503 xmlElemDump(stdout, NULL, node); 00504 } 00505 } 00506 00507 GList* 00508 dom_tree_freqSpec_to_recurrences(xmlNodePtr node, QofBook *book) 00509 { 00510 fsParseData fspd; 00511 fspd_init( &fspd ); 00512 common_parse(&fspd, node, book); 00513 if (fspd.recurrence_list == NULL) 00514 { 00515 fspd.recurrence_list = g_list_append(fspd.recurrence_list, fspd.recurrence); 00516 } 00517 return fspd.recurrence_list; 00518 }
1.7.4