|
GnuCash 2.4.99
|
00001 /********************************************************************\ 00002 * gnc-account-xml-v2.c -- account xml i/o implementation * 00003 * * 00004 * Copyright (C) 2001 James LewisMoss <dres@debian.org> * 00005 * Copyright (C) 2002 Linas Vepstas <linas@linas.org> * 00006 * * 00007 * This program is free software; you can redistribute it and/or * 00008 * modify it under the terms of the GNU General Public License as * 00009 * published by the Free Software Foundation; either version 2 of * 00010 * the License, or (at your option) any later version. * 00011 * * 00012 * This program is distributed in the hope that it will be useful, * 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00015 * GNU General Public License for more details. * 00016 * * 00017 * You should have received a copy of the GNU General Public License* 00018 * along with this program; if not, contact: * 00019 * * 00020 * Free Software Foundation Voice: +1-617-542-5942 * 00021 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00022 * Boston, MA 02110-1301, USA gnu@gnu.org * 00023 * * 00024 \********************************************************************/ 00025 00026 #include "config.h" 00027 00028 #include <glib.h> 00029 #include <stdlib.h> 00030 #include <string.h> 00031 00032 #include "gnc-xml-helper.h" 00033 #include "sixtp.h" 00034 #include "sixtp-utils.h" 00035 #include "sixtp-parsers.h" 00036 #include "sixtp-utils.h" 00037 #include "sixtp-dom-parsers.h" 00038 #include "sixtp-dom-generators.h" 00039 00040 #include "gnc-xml.h" 00041 #include "io-gncxml-gen.h" 00042 #include "io-gncxml-v2.h" 00043 00044 #include "sixtp-dom-parsers.h" 00045 #include "AccountP.h" 00046 #include "Account.h" 00047 00048 static QofLogModule log_module = GNC_MOD_IO; 00049 00050 const gchar *account_version_string = "2.0.0"; 00051 00052 /* ids */ 00053 #define gnc_account_string "gnc:account" 00054 #define act_name_string "act:name" 00055 #define act_id_string "act:id" 00056 #define act_type_string "act:type" 00057 #define act_commodity_string "act:commodity" 00058 #define act_commodity_scu_string "act:commodity-scu" 00059 #define act_non_standard_scu_string "act:non-standard-scu" 00060 #define act_code_string "act:code" 00061 #define act_description_string "act:description" 00062 #define act_slots_string "act:slots" 00063 #define act_parent_string "act:parent" 00064 #define act_lots_string "act:lots" 00065 /* The currency and security strings should not appear in newer 00066 * xml files (anything post-gnucash-1.6) */ 00067 #define act_currency_string "act:currency" 00068 #define act_currency_scu_string "act:currency-scu" 00069 #define act_security_string "act:security" 00070 #define act_security_scu_string "act:security-scu" 00071 #define act_hidden_string "act:hidden" 00072 #define act_placeholder_string "act:placeholder" 00073 00074 xmlNodePtr 00075 gnc_account_dom_tree_create(Account *act, 00076 gboolean exporting, 00077 gboolean allow_incompat) 00078 { 00079 const char *str; 00080 kvp_frame *kf; 00081 xmlNodePtr ret; 00082 GList *lots, *n; 00083 Account *parent; 00084 gnc_commodity *acct_commodity; 00085 00086 ENTER ("(account=%p)", act); 00087 00088 ret = xmlNewNode(NULL, BAD_CAST gnc_account_string); 00089 xmlSetProp(ret, BAD_CAST "version", BAD_CAST account_version_string); 00090 00091 xmlAddChild(ret, text_to_dom_tree(act_name_string, 00092 xaccAccountGetName(act))); 00093 00094 xmlAddChild(ret, guid_to_dom_tree(act_id_string, xaccAccountGetGUID(act))); 00095 00096 xmlAddChild(ret, text_to_dom_tree( 00097 act_type_string, 00098 xaccAccountTypeEnumAsString(xaccAccountGetType(act)))); 00099 00100 /* Don't write new XML tags in version 2.3.x and 2.4.x because it 00101 would mean 2.2.x cannot read those files again. But we can 00102 enable writing these tags in 2.5.x or late in 2.4.x. */ 00103 /* 00104 xmlAddChild(ret, boolean_to_dom_tree( 00105 act_hidden_string, 00106 xaccAccountGetHidden(act))); 00107 xmlAddChild(ret, boolean_to_dom_tree( 00108 act_placeholder_string, 00109 xaccAccountGetPlaceholder(act))); 00110 */ 00111 00112 acct_commodity = xaccAccountGetCommodity(act); 00113 if (acct_commodity != NULL) 00114 { 00115 xmlAddChild(ret, commodity_ref_to_dom_tree(act_commodity_string, 00116 acct_commodity)); 00117 00118 xmlAddChild(ret, int_to_dom_tree(act_commodity_scu_string, 00119 xaccAccountGetCommoditySCUi(act))); 00120 00121 if (xaccAccountGetNonStdSCU(act)) 00122 xmlNewChild(ret, NULL, BAD_CAST act_non_standard_scu_string, NULL); 00123 } 00124 00125 str = xaccAccountGetCode(act); 00126 if (str && strlen(str) > 0) 00127 { 00128 xmlAddChild(ret, text_to_dom_tree(act_code_string, str)); 00129 } 00130 00131 str = xaccAccountGetDescription(act); 00132 if (str && strlen(str) > 0) 00133 { 00134 xmlAddChild(ret, text_to_dom_tree(act_description_string, str)); 00135 } 00136 00137 kf = xaccAccountGetSlots(act); 00138 if (kf) 00139 { 00140 xmlNodePtr kvpnode = kvp_frame_to_dom_tree(act_slots_string, kf); 00141 if (kvpnode) 00142 { 00143 xmlAddChild(ret, kvpnode); 00144 } 00145 } 00146 00147 parent = gnc_account_get_parent(act); 00148 if (parent) 00149 { 00150 if (!gnc_account_is_root(parent) || allow_incompat) 00151 xmlAddChild(ret, guid_to_dom_tree(act_parent_string, 00152 xaccAccountGetGUID(parent))); 00153 } 00154 00155 lots = xaccAccountGetLotList (act); 00156 PINFO ("lot list=%p", lots); 00157 if (lots && !exporting) 00158 { 00159 xmlNodePtr toaddto = xmlNewChild(ret, NULL, BAD_CAST act_lots_string, NULL); 00160 00161 lots = g_list_sort(lots, qof_instance_guid_compare); 00162 00163 for (n = lots; n; n = n->next) 00164 { 00165 GNCLot * lot = n->data; 00166 xmlAddChild(toaddto, gnc_lot_dom_tree_create(lot)); 00167 } 00168 } 00169 g_list_free(lots); 00170 00171 LEAVE(""); 00172 return ret; 00173 } 00174 00175 /***********************************************************************/ 00176 00177 struct account_pdata 00178 { 00179 Account *account; 00180 QofBook *book; 00181 }; 00182 00183 static inline gboolean 00184 set_string(xmlNodePtr node, Account* act, 00185 void (*func)(Account *act, const gchar *txt)) 00186 { 00187 gchar* txt = dom_tree_to_text(node); 00188 g_return_val_if_fail(txt, FALSE); 00189 00190 func(act, txt); 00191 00192 g_free(txt); 00193 00194 return TRUE; 00195 } 00196 00197 static gboolean 00198 account_name_handler (xmlNodePtr node, gpointer act_pdata) 00199 { 00200 struct account_pdata *pdata = act_pdata; 00201 00202 return set_string(node, pdata->account, xaccAccountSetName); 00203 } 00204 00205 static gboolean 00206 account_id_handler (xmlNodePtr node, gpointer act_pdata) 00207 { 00208 struct account_pdata *pdata = act_pdata; 00209 GncGUID *guid; 00210 00211 guid = dom_tree_to_guid(node); 00212 g_return_val_if_fail(guid, FALSE); 00213 00214 xaccAccountSetGUID(pdata->account, guid); 00215 00216 g_free(guid); 00217 00218 return TRUE; 00219 } 00220 00221 static gboolean 00222 account_type_handler (xmlNodePtr node, gpointer act_pdata) 00223 { 00224 struct account_pdata *pdata = act_pdata; 00225 GNCAccountType type = ACCT_TYPE_INVALID; 00226 char *string; 00227 00228 string = (char*) xmlNodeGetContent (node->xmlChildrenNode); 00229 xaccAccountStringToType(string, &type); 00230 xmlFree (string); 00231 00232 xaccAccountSetType(pdata->account, type); 00233 00234 return TRUE; 00235 } 00236 00237 static gboolean 00238 account_commodity_handler (xmlNodePtr node, gpointer act_pdata) 00239 { 00240 struct account_pdata *pdata = act_pdata; 00241 gnc_commodity *ref; 00242 00243 // ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book); 00244 ref = dom_tree_to_commodity_ref(node, pdata->book); 00245 xaccAccountSetCommodity(pdata->account, ref); 00246 00247 return TRUE; 00248 } 00249 00250 static gboolean 00251 account_commodity_scu_handler (xmlNodePtr node, gpointer act_pdata) 00252 { 00253 struct account_pdata *pdata = act_pdata; 00254 gint64 val; 00255 00256 dom_tree_to_integer(node, &val); 00257 xaccAccountSetCommoditySCU(pdata->account, val); 00258 00259 return TRUE; 00260 } 00261 00262 static gboolean 00263 account_hidden_handler (xmlNodePtr node, gpointer act_pdata) 00264 { 00265 struct account_pdata *pdata = act_pdata; 00266 gboolean val; 00267 00268 dom_tree_to_boolean(node, &val); 00269 xaccAccountSetHidden(pdata->account, val); 00270 00271 return TRUE; 00272 } 00273 00274 static gboolean 00275 account_placeholder_handler (xmlNodePtr node, gpointer act_pdata) 00276 { 00277 struct account_pdata *pdata = act_pdata; 00278 gboolean val; 00279 00280 dom_tree_to_boolean(node, &val); 00281 xaccAccountSetPlaceholder(pdata->account, val); 00282 00283 return TRUE; 00284 } 00285 00286 static gboolean 00287 account_non_standard_scu_handler (xmlNodePtr node, gpointer act_pdata) 00288 { 00289 struct account_pdata *pdata = act_pdata; 00290 00291 xaccAccountSetNonStdSCU(pdata->account, TRUE); 00292 00293 return TRUE; 00294 } 00295 00296 /* ============================================================== */ 00297 /* The following deprecated routines are here only to service 00298 * older XML files. */ 00299 00300 static gboolean 00301 deprecated_account_currency_handler (xmlNodePtr node, gpointer act_pdata) 00302 { 00303 struct account_pdata *pdata = act_pdata; 00304 gnc_commodity *ref; 00305 00306 PWARN("Account %s: Obsolete xml tag 'act:currency' will not be preserved.", 00307 xaccAccountGetName( pdata->account )); 00308 ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book); 00309 DxaccAccountSetCurrency(pdata->account, ref); 00310 00311 return TRUE; 00312 } 00313 00314 static gboolean 00315 deprecated_account_currency_scu_handler (xmlNodePtr node, gpointer act_pdata) 00316 { 00317 struct account_pdata *pdata = act_pdata; 00318 PWARN("Account %s: Obsolete xml tag 'act:currency-scu' will not be preserved.", 00319 xaccAccountGetName( pdata->account )); 00320 return TRUE; 00321 } 00322 00323 static gboolean 00324 deprecated_account_security_handler (xmlNodePtr node, gpointer act_pdata) 00325 { 00326 struct account_pdata *pdata = act_pdata; 00327 gnc_commodity *ref, *orig = xaccAccountGetCommodity(pdata->account); 00328 00329 PWARN("Account %s: Obsolete xml tag 'act:security' will not be preserved.", 00330 xaccAccountGetName( pdata->account )); 00331 /* If the account has both a commodity and a security elemet, and 00332 the commodity is a currecny, then the commodity is probably 00333 wrong. In that case we want to replace it with the 00334 security. jralls 2010-11-02 */ 00335 if (!orig || gnc_commodity_is_currency( orig ) ) 00336 { 00337 ref = dom_tree_to_commodity_ref_no_engine(node, pdata->book); 00338 xaccAccountSetCommodity(pdata->account, ref); 00339 /* If the SCU was set, it was probably wrong, so zero it out 00340 so that the SCU handler can fix it if there's a 00341 security-scu element. jralls 2010-11-02 */ 00342 xaccAccountSetCommoditySCU(pdata->account, 0); 00343 } 00344 00345 return TRUE; 00346 } 00347 00348 static gboolean 00349 deprecated_account_security_scu_handler (xmlNodePtr node, gpointer act_pdata) 00350 { 00351 struct account_pdata *pdata = act_pdata; 00352 gint64 val; 00353 00354 PWARN("Account %s: Obsolete xml tag 'act:security-scu' will not be preserved.", 00355 xaccAccountGetName( pdata->account )); 00356 if (!xaccAccountGetCommoditySCU(pdata->account)) 00357 { 00358 dom_tree_to_integer(node, &val); 00359 xaccAccountSetCommoditySCU(pdata->account, val); 00360 } 00361 00362 return TRUE; 00363 } 00364 00365 /* ============================================================== */ 00366 00367 static gboolean 00368 account_slots_handler (xmlNodePtr node, gpointer act_pdata) 00369 { 00370 struct account_pdata *pdata = act_pdata; 00371 00372 return dom_tree_to_kvp_frame_given 00373 (node, xaccAccountGetSlots (pdata->account)); 00374 } 00375 00376 static gboolean 00377 account_parent_handler (xmlNodePtr node, gpointer act_pdata) 00378 { 00379 struct account_pdata *pdata = act_pdata; 00380 Account *parent; 00381 GncGUID *gid; 00382 00383 gid = dom_tree_to_guid(node); 00384 g_return_val_if_fail(gid, FALSE); 00385 00386 parent = xaccAccountLookup(gid, pdata->book); 00387 if (!parent) 00388 { 00389 g_free (gid); 00390 g_return_val_if_fail(parent, FALSE); 00391 } 00392 00393 gnc_account_append_child(parent, pdata->account); 00394 00395 g_free (gid); 00396 00397 return TRUE; 00398 } 00399 00400 static gboolean 00401 account_code_handler(xmlNodePtr node, gpointer act_pdata) 00402 { 00403 struct account_pdata *pdata = act_pdata; 00404 00405 return set_string(node, pdata->account, xaccAccountSetCode); 00406 } 00407 00408 static gboolean 00409 account_description_handler(xmlNodePtr node, gpointer act_pdata) 00410 { 00411 struct account_pdata *pdata = act_pdata; 00412 00413 return set_string(node, pdata->account, xaccAccountSetDescription); 00414 } 00415 00416 static gboolean 00417 account_lots_handler(xmlNodePtr node, gpointer act_pdata) 00418 { 00419 struct account_pdata *pdata = act_pdata; 00420 xmlNodePtr mark; 00421 00422 g_return_val_if_fail(node, FALSE); 00423 g_return_val_if_fail(node->xmlChildrenNode, FALSE); 00424 00425 for (mark = node->xmlChildrenNode; mark; mark = mark->next) 00426 { 00427 GNCLot *lot; 00428 00429 if (safe_strcmp("text", (char*) mark->name) == 0) 00430 continue; 00431 00432 lot = dom_tree_to_lot(mark, pdata->book); 00433 00434 if (lot) 00435 { 00436 xaccAccountInsertLot (pdata->account, lot); 00437 } 00438 else 00439 { 00440 return FALSE; 00441 } 00442 } 00443 return TRUE; 00444 } 00445 00446 static struct dom_tree_handler account_handlers_v2[] = 00447 { 00448 { act_name_string, account_name_handler, 1, 0 }, 00449 { act_id_string, account_id_handler, 1, 0 }, 00450 { act_type_string, account_type_handler, 1, 0 }, 00451 { act_commodity_string, account_commodity_handler, 0, 0 }, 00452 { act_commodity_scu_string, account_commodity_scu_handler, 0, 0 }, 00453 { act_non_standard_scu_string, account_non_standard_scu_handler, 0, 0 }, 00454 { act_code_string, account_code_handler, 0, 0 }, 00455 { act_description_string, account_description_handler, 0, 0}, 00456 { act_slots_string, account_slots_handler, 0, 0 }, 00457 { act_parent_string, account_parent_handler, 0, 0 }, 00458 { act_lots_string, account_lots_handler, 0, 0 }, 00459 { act_hidden_string, account_hidden_handler, 0, 0 }, 00460 { act_placeholder_string, account_placeholder_handler, 0, 0 }, 00461 00462 /* These should not appear in newer xml files; only in old 00463 * (circa gnucash-1.6) xml files. We maintain them for backward 00464 * compatibility. */ 00465 { act_currency_string, deprecated_account_currency_handler, 0, 0 }, 00466 { act_currency_scu_string, deprecated_account_currency_scu_handler, 0, 0 }, 00467 { act_security_string, deprecated_account_security_handler, 0, 0 }, 00468 { act_security_scu_string, deprecated_account_security_scu_handler, 0, 0 }, 00469 { NULL, 0, 0, 0 } 00470 }; 00471 00472 static gboolean 00473 gnc_account_end_handler(gpointer data_for_children, 00474 GSList* data_from_children, GSList* sibling_data, 00475 gpointer parent_data, gpointer global_data, 00476 gpointer *result, const gchar *tag) 00477 { 00478 int successful; 00479 Account *acc, *parent, *root; 00480 xmlNodePtr tree = (xmlNodePtr)data_for_children; 00481 gxpf_data *gdata = (gxpf_data*)global_data; 00482 QofBook *book = gdata->bookdata; 00483 int type; 00484 00485 successful = TRUE; 00486 00487 if (parent_data) 00488 { 00489 return TRUE; 00490 } 00491 00492 /* OK. For some messed up reason this is getting called again with a 00493 NULL tag. So we ignore those cases */ 00494 if (!tag) 00495 { 00496 return TRUE; 00497 } 00498 00499 g_return_val_if_fail(tree, FALSE); 00500 00501 acc = dom_tree_to_account(tree, book); 00502 if (acc != NULL) 00503 { 00504 gdata->cb(tag, gdata->parsedata, acc); 00505 /* 00506 * Now return the account to the "edit" state. At the end of reading 00507 * all the transactions, we will Commit. This replaces #splits 00508 * rebalances with #accounts rebalances at the end. A BIG win! 00509 */ 00510 xaccAccountBeginEdit(acc); 00511 00512 /* Backwards compatability. If there's no parent, see if this 00513 * account is of type ROOT. If not, find or create a ROOT 00514 * account and make that the parent. */ 00515 parent = gnc_account_get_parent(acc); 00516 if (parent == NULL) 00517 { 00518 type = xaccAccountGetType(acc); 00519 if (type != ACCT_TYPE_ROOT) 00520 { 00521 root = gnc_book_get_root_account(book); 00522 if (root == NULL) 00523 { 00524 root = gnc_account_create_root(book); 00525 } 00526 gnc_account_append_child(root, acc); 00527 } 00528 } 00529 } 00530 00531 xmlFreeNode(tree); 00532 00533 return acc != NULL; 00534 } 00535 00536 Account* 00537 dom_tree_to_account (xmlNodePtr node, QofBook *book) 00538 { 00539 struct account_pdata act_pdata; 00540 Account *accToRet; 00541 gboolean successful; 00542 00543 accToRet = xaccMallocAccount(book); 00544 xaccAccountBeginEdit(accToRet); 00545 00546 act_pdata.account = accToRet; 00547 act_pdata.book = book; 00548 00549 successful = dom_tree_generic_parse (node, account_handlers_v2, 00550 &act_pdata); 00551 if (successful) 00552 { 00553 xaccAccountCommitEdit (accToRet); 00554 } 00555 else 00556 { 00557 PERR ("failed to parse account tree"); 00558 xaccAccountDestroy (accToRet); 00559 accToRet = NULL; 00560 } 00561 00562 return accToRet; 00563 } 00564 00565 sixtp* 00566 gnc_account_sixtp_parser_create(void) 00567 { 00568 return sixtp_dom_parser_new(gnc_account_end_handler, NULL, NULL); 00569 } 00570 00571 /* ====================== END OF FILE ===================*/
1.7.4