GnuCash 2.4.99
gnc-freqspec-xml-v2.c
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines