PageRenderTime 53ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/src/import-export/qif/qif-parse.c

http://github.com/mchochlov/Gnucash
C | 935 lines | 642 code | 154 blank | 139 comment | 70 complexity | 0022d93a5aa64a9743ec54dbb522c3ad MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * qif-parse.c -- parse QIF
  3. *
  4. * Written by: Derek Atkins <derek@ihtfp.com>
  5. * Copyright (c) 2003 Derek Atkins <warlord@MIT.EDU>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, contact:
  19. *
  20. * Free Software Foundation Voice: +1-617-542-5942
  21. * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
  22. * Boston, MA 02110-1301, USA gnu@gnu.org
  23. */
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27. #include <glib.h>
  28. #include <glib/gi18n.h>
  29. #include <string.h>
  30. /* For regex */
  31. #include <sys/types.h>
  32. #include <regex.h>
  33. #include <stdarg.h>
  34. #include "gnc-engine.h"
  35. #include "gnc-ui-util.h"
  36. #include "qif-import-p.h"
  37. #include "qif-objects-p.h"
  38. #include "import-parse.h"
  39. static QofLogModule log_module = GNC_MOD_IMPORT;
  40. /* An array of handlers for the various bang-types */
  41. static QifHandler qif_handlers[QIF_TYPE_MAX+1] = { NULL };
  42. /* Parser Regular Expressions */
  43. static gboolean qifp_regex_compiled = FALSE;
  44. static regex_t category_regex;
  45. /* A Hash Table of bang-types */
  46. static GHashTable *qif_bangtype_map = NULL;
  47. /* A Hash Table of action strings */
  48. static GHashTable *qif_action_map = NULL;
  49. /* A Hash Table of account types */
  50. static GHashTable *qif_atype_map = NULL;
  51. /************************************************************************/
  52. /* Register a handler */
  53. void
  54. qif_register_handler(QifType type, QifHandler handler)
  55. {
  56. if (type <= 0 || type > QIF_TYPE_MAX)
  57. {
  58. PERR("Invalid type: %d", type);
  59. return;
  60. }
  61. qif_handlers[type] = handler;
  62. }
  63. static void
  64. compile_regex()
  65. {
  66. regcomp(&category_regex,
  67. "^ *(\\[)?([^]/|]*)(]?)(/([^|]*))?(\\|(\\[)?([^]/]*)(]?)(/(.*))?)? *$",
  68. REG_EXTENDED);
  69. qifp_regex_compiled = TRUE;
  70. }
  71. #define QIF_ADD_TYPE(ts,t) \
  72. g_hash_table_insert(qif_bangtype_map, ts, GINT_TO_POINTER(t)); \
  73. g_hash_table_insert(qif_bangtype_map, _(ts), GINT_TO_POINTER(t));
  74. static void
  75. build_bangtype_map()
  76. {
  77. g_return_if_fail(!qif_bangtype_map);
  78. qif_bangtype_map = g_hash_table_new(g_str_hash, g_str_equal);
  79. g_assert(qif_bangtype_map);
  80. /* Translators FIXME: It is unclear whether these strings should
  81. really be translated, and if yes, into which translation. */
  82. QIF_ADD_TYPE(N_("type:bank"), QIF_TYPE_BANK);
  83. QIF_ADD_TYPE(N_("type:cash"), QIF_TYPE_CASH);
  84. QIF_ADD_TYPE(N_("type:ccard"), QIF_TYPE_CCARD);
  85. QIF_ADD_TYPE(N_("type:invst"), QIF_TYPE_INVST);
  86. QIF_ADD_TYPE(N_("type:port"), QIF_TYPE_PORT);
  87. QIF_ADD_TYPE(N_("type:oth a"), QIF_TYPE_OTH_A);
  88. QIF_ADD_TYPE(N_("type:oth l"), QIF_TYPE_OTH_L);
  89. QIF_ADD_TYPE(N_("type:class"), QIF_TYPE_CLASS);
  90. QIF_ADD_TYPE(N_("type:cat"), QIF_TYPE_CAT);
  91. QIF_ADD_TYPE(N_("type:security"), QIF_TYPE_SECURITY);
  92. QIF_ADD_TYPE(N_("account"), QIF_ACCOUNT);
  93. QIF_ADD_TYPE(N_("option:autoswitch"), QIF_AUTOSWITCH);
  94. QIF_ADD_TYPE(N_("clear:autoswitch"), QIF_CLEAR_AUTOSWITCH);
  95. }
  96. #undef QIF_ADD_TYPE
  97. #define QIF_ADD_ACT(ts,t) \
  98. g_hash_table_insert(qif_action_map, ts, GINT_TO_POINTER(t));
  99. static void
  100. build_action_map()
  101. {
  102. g_return_if_fail(!qif_action_map);
  103. qif_action_map = g_hash_table_new(g_str_hash, g_str_equal);
  104. g_assert(qif_action_map);
  105. QIF_ADD_ACT("buy", QIF_A_BUY);
  106. QIF_ADD_ACT("cvrshrt", QIF_A_BUY);
  107. QIF_ADD_ACT("kauf", QIF_A_BUY);
  108. QIF_ADD_ACT("buyx", QIF_A_BUYX);
  109. QIF_ADD_ACT("cvrshrtx", QIF_A_BUYX);
  110. QIF_ADD_ACT("kaufx", QIF_A_BUYX);
  111. QIF_ADD_ACT("cglong", QIF_A_CGLONG);
  112. QIF_ADD_ACT("kapgew", QIF_A_CGLONG); /* Kapitalgewinnsteuer */
  113. QIF_ADD_ACT("cglongx", QIF_A_CGLONG);
  114. QIF_ADD_ACT("kapgewx", QIF_A_CGLONG);
  115. QIF_ADD_ACT("cgmid", QIF_A_CGMID);
  116. QIF_ADD_ACT("cgmidx", QIF_A_CGMIDX);
  117. QIF_ADD_ACT("cgshort", QIF_A_CGSHORT);
  118. QIF_ADD_ACT("k.gewsp", QIF_A_CGSHORT);
  119. QIF_ADD_ACT("cgshortx", QIF_A_CGSHORTX);
  120. QIF_ADD_ACT("k.gewspx", QIF_A_CGSHORTX);
  121. QIF_ADD_ACT("div", QIF_A_DIV); /* dividende */
  122. QIF_ADD_ACT("divx", QIF_A_DIVX);
  123. //QIF_ADD_ACT("exercise", QIF_A_EXERCISE);
  124. //QIF_ADD_ACT("exercisex", QIF_A_EXERCISEX);
  125. //QIF_ADD_ACT("expire", QIF_A_EXPIRE);
  126. //QIF_ADD_ACT("grant", QIF_A_GRANT);
  127. QIF_ADD_ACT("int", QIF_A_INTINC);
  128. QIF_ADD_ACT("intinc", QIF_A_INTINC);
  129. QIF_ADD_ACT("aktzu", QIF_A_INTINC); /* zinsen */
  130. QIF_ADD_ACT("intx", QIF_A_INTINCX);
  131. QIF_ADD_ACT("intincx", QIF_A_INTINCX);
  132. QIF_ADD_ACT("margint", QIF_A_MARGINT);
  133. QIF_ADD_ACT("margintx", QIF_A_MARGINTX);
  134. QIF_ADD_ACT("miscexp", QIF_A_MISCEXP);
  135. QIF_ADD_ACT("miscexpx", QIF_A_MISCEXPX);
  136. QIF_ADD_ACT("miscinc", QIF_A_MISCINC);
  137. QIF_ADD_ACT("cash", QIF_A_MISCINC);
  138. QIF_ADD_ACT("miscincx", QIF_A_MISCINCX);
  139. QIF_ADD_ACT("reinvdiv", QIF_A_REINVDIV);
  140. QIF_ADD_ACT("reinvint", QIF_A_REINVINT);
  141. QIF_ADD_ACT("reinvzin", QIF_A_REINVINT);
  142. QIF_ADD_ACT("reinvlg", QIF_A_REINVLG);
  143. QIF_ADD_ACT("reinvkur", QIF_A_REINVLG);
  144. QIF_ADD_ACT("reinvmd", QIF_A_REINVMD);
  145. QIF_ADD_ACT("reinvsg", QIF_A_REINVSG);
  146. QIF_ADD_ACT("reinvksp", QIF_A_REINVSG);
  147. QIF_ADD_ACT("reinvsh", QIF_A_REINVSH);
  148. QIF_ADD_ACT("reminder", QIF_A_REMINDER);
  149. QIF_ADD_ACT("erinnerg", QIF_A_REMINDER);
  150. QIF_ADD_ACT("rtrncap", QIF_A_RTRNCAP);
  151. QIF_ADD_ACT("rtrncapx", QIF_A_RTRNCAPX);
  152. QIF_ADD_ACT("sell", QIF_A_SELL);
  153. QIF_ADD_ACT("shtsell", QIF_A_SELL);
  154. QIF_ADD_ACT("verkauf", QIF_A_SELL); /* verkaufen */
  155. QIF_ADD_ACT("sellx", QIF_A_SELLX);
  156. QIF_ADD_ACT("shtsellx", QIF_A_SELLX);
  157. QIF_ADD_ACT("verkaufx", QIF_A_SELLX); /* verkaufen */
  158. QIF_ADD_ACT("shrsin", QIF_A_SHRSIN);
  159. QIF_ADD_ACT("aktzu", QIF_A_SHRSIN);
  160. QIF_ADD_ACT("shrsout", QIF_A_SHRSOUT);
  161. QIF_ADD_ACT("aktab", QIF_A_SHRSOUT);
  162. QIF_ADD_ACT("stksplit", QIF_A_STKSPLIT);
  163. QIF_ADD_ACT("aktsplit", QIF_A_STKSPLIT);
  164. //QIF_ADD_ACT("vest", QIF_A_VEST);
  165. QIF_ADD_ACT("xin", QIF_A_XIN);
  166. QIF_ADD_ACT("contribx", QIF_A_XIN);
  167. QIF_ADD_ACT("xout", QIF_A_XOUT);
  168. QIF_ADD_ACT("withdrwx", QIF_A_XOUT);
  169. }
  170. #undef QIF_ADD_ACT
  171. static GList *
  172. make_list(int count, ...)
  173. {
  174. GList *result = NULL;
  175. GNCAccountType type;
  176. va_list ap;
  177. va_start (ap, count);
  178. while (count--)
  179. {
  180. type = va_arg (ap, GNCAccountType);
  181. result = g_list_prepend (result, GINT_TO_POINTER(type));
  182. }
  183. va_end (ap);
  184. return g_list_reverse(result);
  185. }
  186. #define QIF_ADD_ATYPE(a,t) g_hash_table_insert(qif_atype_map, a, t);
  187. static void
  188. build_atype_map()
  189. {
  190. g_return_if_fail(!qif_atype_map);
  191. qif_atype_map = g_hash_table_new(g_str_hash, g_str_equal);
  192. g_assert(qif_atype_map);
  193. QIF_ADD_ATYPE("bank", make_list(1, ACCT_TYPE_BANK));
  194. QIF_ADD_ATYPE("port", make_list(1, ACCT_TYPE_BANK));
  195. QIF_ADD_ATYPE("cash", make_list(1, ACCT_TYPE_CASH));
  196. QIF_ADD_ATYPE("ccard", make_list(1, ACCT_TYPE_CREDIT));
  197. QIF_ADD_ATYPE("invst", make_list(3, ACCT_TYPE_BANK, ACCT_TYPE_STOCK,
  198. ACCT_TYPE_MUTUAL));
  199. QIF_ADD_ATYPE("oth a", make_list(3, ACCT_TYPE_ASSET, ACCT_TYPE_BANK,
  200. ACCT_TYPE_CASH));
  201. QIF_ADD_ATYPE("oth l", make_list(2, ACCT_TYPE_LIABILITY, ACCT_TYPE_CREDIT));
  202. QIF_ADD_ATYPE("mutual", make_list(3, ACCT_TYPE_BANK, ACCT_TYPE_MUTUAL,
  203. ACCT_TYPE_STOCK));
  204. /* Internal types */
  205. QIF_ADD_ATYPE("__any_bank__", make_list(5, ACCT_TYPE_BANK, ACCT_TYPE_CREDIT,
  206. ACCT_TYPE_CASH, ACCT_TYPE_ASSET,
  207. ACCT_TYPE_LIABILITY));
  208. QIF_ADD_ATYPE("__all__", make_list(7, ACCT_TYPE_BANK, ACCT_TYPE_CREDIT,
  209. ACCT_TYPE_CASH, ACCT_TYPE_ASSET,
  210. ACCT_TYPE_LIABILITY, ACCT_TYPE_STOCK,
  211. ACCT_TYPE_MUTUAL));
  212. QIF_ADD_ATYPE("__stock__", make_list(2, ACCT_TYPE_STOCK, ACCT_TYPE_MUTUAL));
  213. QIF_ADD_ATYPE("__income__", make_list(1, ACCT_TYPE_INCOME));
  214. QIF_ADD_ATYPE("__expense__", make_list(1, ACCT_TYPE_EXPENSE));
  215. QIF_ADD_ATYPE("__equity__", make_list(1, ACCT_TYPE_EQUITY));
  216. }
  217. #undef QIF_ADD_ATYPE
  218. /************************************************************************/
  219. /*
  220. * We've got a !Type line. Parse the line into the appropriate
  221. * type and then initialize the handler.
  222. */
  223. void
  224. qif_parse_bangtype(QifContext ctx, const char *line)
  225. {
  226. QifType type;
  227. char *bangtype;
  228. gpointer result;
  229. g_return_if_fail(line && *line == '!');
  230. if (!qif_bangtype_map)
  231. build_bangtype_map();
  232. /* Make a local copy so we can manipulate it.
  233. * - strip off leading/trailing whitespace
  234. * - make it all lower case
  235. */
  236. bangtype = g_utf8_strdown(line + 1, -1);
  237. g_strstrip(bangtype);
  238. /* In some cases we get "!Type Bank" -- change the space to a colon */
  239. if (!strncmp(bangtype, "type ", 5))
  240. bangtype[5] = ':';
  241. /* Lookup the bangtype in the map and then destroy the local copy */
  242. result = g_hash_table_lookup(qif_bangtype_map, bangtype);
  243. g_free(bangtype);
  244. if (!result)
  245. {
  246. PWARN("Unknown bang-type at line %d: %s. Ignored", ctx->lineno, line);
  247. return;
  248. }
  249. type = GPOINTER_TO_INT(result);
  250. /* Set the current context parse type and handler */
  251. ctx->parse_type = type;
  252. ctx->handler = qif_handlers[type];
  253. /* now initialize this new parse type (if there's an init function) */
  254. if (ctx->handler && ctx->handler->init)
  255. ctx->handler->init(ctx);
  256. }
  257. /* returns TRUE if successful, FALSE if there is a problem */
  258. gboolean
  259. qif_parse_split_category(const char* str,
  260. char** cat, gboolean *cat_is_acct, char** cat_class,
  261. char** miscx_cat, gboolean *miscx_cat_is_acct,
  262. char **miscx_class)
  263. {
  264. /* This is a pretty f**ked up string. Basically it looks like:
  265. * ([)cat-or-acct(])(/(class))(|([)cat-of-acct(])(/ext))
  266. *
  267. * where data in parens is "optional" (depending on the context).
  268. *
  269. * examples from reality:
  270. *
  271. * category
  272. * category:subcategory
  273. * category/class
  274. * category:subcat/class
  275. * [account]
  276. * [account]/class
  277. *
  278. * cat/cat-class|miscx-cat/miscx-class
  279. */
  280. regmatch_t pmatch[12];
  281. g_return_val_if_fail(cat && cat_is_acct && cat_class &&
  282. miscx_cat && miscx_cat_is_acct && miscx_class, FALSE);
  283. if (!qifp_regex_compiled)
  284. compile_regex();
  285. if (regexec(&category_regex, str, 12, pmatch, 0) != 0)
  286. {
  287. PERR("category match failed");
  288. return FALSE;
  289. }
  290. /*
  291. * what the substrings mean:
  292. * 1 the opening [ for a transfer
  293. * 2 the category
  294. * 3 the closing ]
  295. * 4 the class /
  296. * 5 the class
  297. * 6 the miscx expression (whole thing)
  298. * 7 the opening [
  299. * 8 the miscx category
  300. * 9 the closing ]
  301. * 10 the class /
  302. * 11 the class
  303. */
  304. if (pmatch[2].rm_so == -1)
  305. {
  306. PERR("no category match found!");
  307. return FALSE;
  308. }
  309. /* catgory name */
  310. *cat = g_strndup(str + pmatch[2].rm_so, pmatch[2].rm_eo - pmatch[2].rm_so);
  311. /* category is account? */
  312. *cat_is_acct = (pmatch[1].rm_so != -1 && pmatch[3].rm_so != -1);
  313. /* category class */
  314. *cat_class = (pmatch[4].rm_so != -1 ?
  315. g_strndup(str + pmatch[5].rm_so, pmatch[5].rm_eo - pmatch[5].rm_so) :
  316. NULL);
  317. /* miscx category name */
  318. *miscx_cat = (pmatch[6].rm_so != -1 ?
  319. g_strndup(str + pmatch[8].rm_so, pmatch[8].rm_eo - pmatch[8].rm_so) :
  320. NULL);
  321. /* miscx cat is acct */
  322. *miscx_cat_is_acct = (pmatch[7].rm_so != -1 && pmatch[9].rm_so != -1);
  323. /* miscx class */
  324. *miscx_class = (pmatch[10].rm_so != -1 ?
  325. g_strndup(str + pmatch[11].rm_so,
  326. pmatch[11].rm_eo - pmatch[11].rm_so) : NULL);
  327. return TRUE;
  328. }
  329. /*
  330. * qif_parse_cleared -- parse the 'C'leared field of a QIF Transaction.
  331. * returns the QIF reconciled flag.
  332. *
  333. * * means cleared, x or X means reconciled, and ! or ? mean some
  334. * budget related stuff I don't understand.
  335. */
  336. QifRecnFlag
  337. qif_parse_cleared(QifLine line)
  338. {
  339. g_return_val_if_fail(line, QIF_R_NO);
  340. g_return_val_if_fail(line->line, QIF_R_NO);
  341. switch (*line->line)
  342. {
  343. case '*':
  344. return QIF_R_CLEARED;
  345. case 'x':
  346. case 'X':
  347. return QIF_R_RECONCILED;
  348. case '?':
  349. case '!':
  350. return QIF_R_BUDGETED;
  351. default:
  352. PERR("Unknown QIF Cleared flag at line %d: %s", line->lineno, line->line);
  353. return QIF_R_NO;
  354. }
  355. }
  356. QifAction qif_parse_action(QifLine line)
  357. {
  358. QifAction qaction;
  359. gpointer result;
  360. char *action;
  361. g_return_val_if_fail(line, QIF_A_NONE);
  362. g_return_val_if_fail(line->line, QIF_A_NONE);
  363. if (!qif_action_map)
  364. build_action_map();
  365. /* Duplicate the action and force it to lower case and strip any spaces */
  366. action = g_utf8_strdown(line->line, -1);
  367. g_strstrip(action);
  368. result = g_hash_table_lookup(qif_action_map, action);
  369. g_free(action);
  370. if (!result)
  371. {
  372. /* XXX: pop up a dialog? */
  373. PWARN("Unknown Action at line %d: %s. Some transactions may be discarded",
  374. line->lineno, line->line);
  375. return QIF_A_NONE;
  376. }
  377. qaction = GPOINTER_TO_INT(result);
  378. return qaction;
  379. }
  380. GList * qif_parse_acct_type(const char *str, gint lineno)
  381. {
  382. GList *result;
  383. char *type;
  384. if (!qif_atype_map)
  385. build_atype_map();
  386. /* Duplicate the type and force it to lower case and strip any spaces */
  387. type = g_utf8_strdown(str, -1);
  388. g_strstrip(type);
  389. result = g_hash_table_lookup(qif_atype_map, type);
  390. g_free(type);
  391. if (!result)
  392. {
  393. PWARN("Unknown account type at line %d: %s. ", lineno, str);
  394. result = g_hash_table_lookup(qif_atype_map, "bank");
  395. g_return_val_if_fail(result, NULL);
  396. }
  397. return result;
  398. }
  399. GList * qif_parse_acct_type_guess(QifType type)
  400. {
  401. const char *atype = NULL;
  402. switch (type)
  403. {
  404. case QIF_TYPE_BANK:
  405. atype = "bank";
  406. break;
  407. case QIF_TYPE_CASH:
  408. atype = "cash";
  409. break;
  410. case QIF_TYPE_CCARD:
  411. atype = "ccard";
  412. break;
  413. case QIF_TYPE_INVST:
  414. atype = "invst";
  415. break;
  416. case QIF_TYPE_PORT:
  417. atype = "port";
  418. break;
  419. case QIF_TYPE_OTH_A:
  420. atype = "oth a";
  421. break;
  422. case QIF_TYPE_OTH_L:
  423. atype = "oth l";
  424. break;
  425. default:
  426. return NULL;
  427. }
  428. return qif_parse_acct_type(atype, -1);
  429. }
  430. /***********************************************************************
  431. * Parsing numbers and dates...
  432. */
  433. typedef struct _parse_helper
  434. {
  435. QifContext ctx;
  436. GncImportFormat budget;
  437. GncImportFormat limit;
  438. GncImportFormat amount;
  439. GncImportFormat d_amount;
  440. GncImportFormat price;
  441. GncImportFormat shares;
  442. GncImportFormat commission;
  443. GncImportFormat date;
  444. } *parse_helper_t;
  445. #define QIF_PARSE_CHECK_NUMBER(str,help) { \
  446. if (str) (help) = gnc_import_test_numeric((str), (help)); \
  447. }
  448. #define QIF_PARSE_PARSE_NUMBER(str,fmt,val) { \
  449. if (str) gnc_import_parse_numeric((str), (fmt), (val)); \
  450. }
  451. static void
  452. qif_parse_check_account(gpointer key, gpointer val, gpointer data)
  453. {
  454. parse_helper_t helper = data;
  455. QifAccount acct = val;
  456. QIF_PARSE_CHECK_NUMBER(acct->limitstr, helper->limit);
  457. QIF_PARSE_CHECK_NUMBER(acct->budgetstr, helper->budget);
  458. }
  459. static void
  460. qif_parse_parse_account(gpointer key, gpointer val, gpointer data)
  461. {
  462. parse_helper_t helper = data;
  463. QifAccount acct = val;
  464. QIF_PARSE_PARSE_NUMBER(acct->limitstr, helper->limit, &acct->limit);
  465. QIF_PARSE_PARSE_NUMBER(acct->budgetstr, helper->budget, &acct->budget);
  466. }
  467. static void
  468. qif_parse_check_category(gpointer key, gpointer val, gpointer data)
  469. {
  470. parse_helper_t helper = data;
  471. QifCategory cat = val;
  472. QIF_PARSE_CHECK_NUMBER(cat->budgetstr, helper->budget);
  473. }
  474. static void
  475. qif_parse_parse_category(gpointer key, gpointer val, gpointer data)
  476. {
  477. parse_helper_t helper = data;
  478. QifCategory cat = val;
  479. QIF_PARSE_PARSE_NUMBER(cat->budgetstr, helper->budget, &cat->budget);
  480. }
  481. static void
  482. qif_parse_check_txn(gpointer val, gpointer data)
  483. {
  484. parse_helper_t helper = data;
  485. QifTxn txn = val;
  486. QifSplit split;
  487. QifInvstTxn itxn;
  488. GList *node;
  489. /* Check the date */
  490. helper->date = gnc_import_test_date(txn->datestr, helper->date);
  491. /* If this is an investment transaction, then all the info is in
  492. * the invst_info. Otherwise it's all in the splits.
  493. */
  494. itxn = txn->invst_info;
  495. if (itxn)
  496. {
  497. QIF_PARSE_CHECK_NUMBER(itxn->amountstr, helper->amount);
  498. QIF_PARSE_CHECK_NUMBER(itxn->d_amountstr, helper->d_amount);
  499. QIF_PARSE_CHECK_NUMBER(itxn->pricestr, helper->price);
  500. QIF_PARSE_CHECK_NUMBER(itxn->sharesstr, helper->shares);
  501. QIF_PARSE_CHECK_NUMBER(itxn->commissionstr, helper->commission);
  502. }
  503. else
  504. {
  505. split = txn->default_split;
  506. node = txn->splits;
  507. do
  508. {
  509. QIF_PARSE_CHECK_NUMBER(split->amountstr, helper->amount);
  510. if (node)
  511. {
  512. split = node->data;
  513. node = node->next;
  514. }
  515. else
  516. split = NULL;
  517. }
  518. while (split);
  519. }
  520. }
  521. static void
  522. qif_parse_parse_txn(gpointer val, gpointer data)
  523. {
  524. parse_helper_t helper = data;
  525. QifTxn txn = val;
  526. QifSplit split;
  527. QifInvstTxn itxn;
  528. GList *node;
  529. /* Parse the date */
  530. gnc_import_parse_date(txn->datestr, helper->date, &txn->date);
  531. /* If this is an investment transaction, then all the info is in
  532. * the invst_info. Otherwise it's all in the splits.
  533. */
  534. itxn = txn->invst_info;
  535. if (itxn)
  536. {
  537. QIF_PARSE_PARSE_NUMBER(itxn->amountstr, helper->amount, &itxn->amount);
  538. QIF_PARSE_PARSE_NUMBER(itxn->d_amountstr, helper->d_amount, &itxn->d_amount);
  539. QIF_PARSE_PARSE_NUMBER(itxn->pricestr, helper->price, &itxn->price);
  540. QIF_PARSE_PARSE_NUMBER(itxn->sharesstr, helper->shares, &itxn->shares);
  541. QIF_PARSE_PARSE_NUMBER(itxn->commissionstr, helper->commission,
  542. &itxn->commission);
  543. qif_invst_txn_setup_splits(helper->ctx, txn);
  544. }
  545. else
  546. {
  547. split = txn->default_split;
  548. node = txn->splits;
  549. do
  550. {
  551. QIF_PARSE_PARSE_NUMBER(split->amountstr, helper->amount, &split->amount);
  552. if (node)
  553. {
  554. split = node->data;
  555. node = node->next;
  556. }
  557. else
  558. split = NULL;
  559. }
  560. while (split);
  561. qif_txn_setup_splits(txn);
  562. }
  563. }
  564. void
  565. qif_parse_all(QifContext ctx, gpointer arg)
  566. {
  567. struct _parse_helper helper;
  568. helper.ctx = ctx;
  569. /* PARSE ACCOUNTS */
  570. /* First, figure out the formats */
  571. helper.limit = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
  572. helper.budget = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
  573. qif_object_map_foreach(ctx, QIF_O_ACCOUNT, qif_parse_check_account, &helper);
  574. /* Make sure it's not ambiguous */
  575. if (helper.limit & (helper.limit - 1)) helper.limit = GNCIF_NUM_PERIOD;
  576. if (helper.budget & (helper.budget - 1)) helper.budget = GNCIF_NUM_PERIOD;
  577. /* Now convert the numbers */
  578. qif_object_map_foreach(ctx, QIF_O_ACCOUNT, qif_parse_parse_account, &helper);
  579. /* PARSE CATEGORIES */
  580. helper.budget = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
  581. qif_object_map_foreach(ctx, QIF_O_CATEGORY, qif_parse_check_category, &helper);
  582. /* make sure it's not ambiguous */
  583. if (helper.budget & (helper.budget - 1)) helper.budget = GNCIF_NUM_PERIOD;
  584. /* Now convert the numbers */
  585. qif_object_map_foreach(ctx, QIF_O_CATEGORY, qif_parse_parse_category, &helper);
  586. /* PARSE TRANSACTIONS */
  587. helper.amount = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
  588. helper.d_amount = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
  589. helper.price = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
  590. helper.shares = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
  591. helper.commission = GNCIF_NUM_PERIOD | GNCIF_NUM_COMMA;
  592. helper.date = GNCIF_DATE_MDY | GNCIF_DATE_DMY | GNCIF_DATE_YMD | GNCIF_DATE_YDM;
  593. qif_object_list_foreach(ctx, QIF_O_TXN, qif_parse_check_txn, &helper);
  594. /* check/fix ambiguities */
  595. if (helper.amount & (helper.amount - 1)) helper.amount = GNCIF_NUM_PERIOD;
  596. if (helper.d_amount & (helper.d_amount - 1)) helper.d_amount = GNCIF_NUM_PERIOD;
  597. if (helper.price & (helper.price - 1)) helper.price = GNCIF_NUM_PERIOD;
  598. if (helper.shares & (helper.shares - 1)) helper.shares = GNCIF_NUM_PERIOD;
  599. if (helper.commission & (helper.commission - 1))
  600. helper.commission = GNCIF_NUM_PERIOD;
  601. if (helper.date & (helper.date - 1))
  602. {
  603. helper.date = gnc_import_choose_fmt(_("The Date format is ambiguous. "
  604. "Please choose the correct format."),
  605. helper.date, arg);
  606. }
  607. /* now parse it.. */
  608. qif_object_list_foreach(ctx, QIF_O_TXN, qif_parse_parse_txn, &helper);
  609. }
  610. typedef struct
  611. {
  612. QifContext ctx;
  613. GList * list;
  614. const char* type;
  615. } qif_merge_t;
  616. static void
  617. qif_merge_accts(gpointer key, gpointer value, gpointer data)
  618. {
  619. qif_merge_t *merge = data;
  620. QifAccount acct = value;
  621. /* Merge into the context. Remember items moved into the parent */
  622. if (qif_account_merge(merge->ctx, acct) == acct)
  623. merge->list = g_list_prepend(merge->list, acct->name);
  624. }
  625. static void
  626. qif_merge_cats(gpointer key, gpointer value, gpointer data)
  627. {
  628. qif_merge_t *merge = data;
  629. QifCategory cat = value;
  630. /* Merge into the context. Remember items moved into the parent */
  631. if (qif_cat_merge(merge->ctx, cat) == cat)
  632. merge->list = g_list_prepend(merge->list, cat->name);
  633. }
  634. static void
  635. qif_merge_classes(gpointer key, gpointer value, gpointer data)
  636. {
  637. qif_merge_t *merge = data;
  638. QifClass qclass = value;
  639. /* Merge into the context. Remember items moved into the parent */
  640. if (qif_class_merge(merge->ctx, qclass) == qclass)
  641. merge->list = g_list_prepend(merge->list, qclass->name);
  642. }
  643. static void
  644. qif_merge_secs(gpointer key, gpointer value, gpointer data)
  645. {
  646. qif_merge_t *merge = data;
  647. QifSecurity sec = value;
  648. /* Merge into the context. Remember items moved into the parent */
  649. if (qif_security_merge(merge->ctx, sec) == sec)
  650. merge->list = g_list_prepend(merge->list, sec->name);
  651. }
  652. static void
  653. qif_merge_del(gpointer obj, gpointer data)
  654. {
  655. qif_merge_t *merge = data;
  656. const char *name = obj;
  657. qif_object_map_remove(merge->ctx, merge->type, name);
  658. }
  659. static void
  660. qif_massage_split(QifSplit split, QifContext ctx)
  661. {
  662. const char *type = QIF_O_CATEGORY;
  663. char *name;
  664. if (split->cat.obj)
  665. {
  666. if (split->cat_is_acct)
  667. {
  668. type = QIF_O_ACCOUNT;
  669. name = split->cat.acct->name;
  670. }
  671. else
  672. name = split->cat.cat->name;
  673. split->cat.obj = qif_object_map_lookup(ctx, type, name);
  674. }
  675. if (split->cat_class)
  676. {
  677. split->cat_class = (QifClass) qif_object_map_lookup(ctx, QIF_O_CLASS,
  678. split->cat_class->name);
  679. }
  680. }
  681. static void
  682. qif_massage_itxn(QifInvstTxn itxn, QifContext ctx)
  683. {
  684. const char *type = QIF_O_CATEGORY;
  685. char *name;
  686. if (itxn->far_cat.obj)
  687. {
  688. if (itxn->far_cat_is_acct)
  689. {
  690. type = QIF_O_ACCOUNT;
  691. name = itxn->far_cat.acct->name;
  692. }
  693. else
  694. name = itxn->far_cat.cat->name;
  695. itxn->far_cat.obj = qif_object_map_lookup(ctx, type, name);
  696. }
  697. }
  698. static void
  699. qif_massage_txn(gpointer obj, gpointer data)
  700. {
  701. QifTxn txn = obj;
  702. QifContext ctx = data;
  703. QifSplit split;
  704. GList *node;
  705. if (txn->from_acct)
  706. txn->from_acct = (QifAccount) qif_object_map_lookup(ctx, QIF_O_ACCOUNT,
  707. txn->from_acct->name);
  708. if (txn->invst_info)
  709. qif_massage_itxn(txn->invst_info, ctx);
  710. if (txn->default_split)
  711. qif_massage_split(txn->default_split, ctx);
  712. for (node = txn->splits; node; node = node->next)
  713. {
  714. split = node->data;
  715. qif_massage_split(split, ctx);
  716. }
  717. }
  718. void
  719. qif_parse_merge_files(QifContext ctx)
  720. {
  721. GList *node;
  722. GList *accts = NULL;
  723. GList *cats = NULL;
  724. GList *classes = NULL;
  725. GList *securities = NULL;
  726. QifContext fctx;
  727. qif_merge_t merge;
  728. g_return_if_fail(ctx);
  729. /* Make sure each of the "file" contexts have been parsed.
  730. * note that we don't care about OUR context -- we can run this
  731. * process multiple times safely.
  732. */
  733. for (node = ctx->files; node; node = node->next)
  734. {
  735. fctx = node->data;
  736. g_return_if_fail(fctx->parsed);
  737. }
  738. /* Iterate over each file. Merge the Accounts, Categories, Classes,
  739. * Securities, and Transactions into the top-level context. Be sure
  740. * to re-point all Transaction/Split category/class/account pointers
  741. * to the new top-level item. Then be sure to remove the
  742. * "duplicated" items so we don't double-free (as we don't refcount,
  743. * either).
  744. */
  745. for (node = ctx->files; node; node = node->next)
  746. {
  747. fctx = node->data;
  748. /* Merge accts, categories, classes, and securities */
  749. merge.ctx = ctx;
  750. merge.list = NULL;
  751. qif_object_map_foreach(fctx, QIF_O_ACCOUNT, qif_merge_accts, &merge);
  752. accts = merge.list;
  753. merge.list = NULL;
  754. qif_object_map_foreach(fctx, QIF_O_CATEGORY, qif_merge_cats, &merge);
  755. cats = merge.list;
  756. merge.list = NULL;
  757. qif_object_map_foreach(fctx, QIF_O_CLASS, qif_merge_classes, &merge);
  758. classes = merge.list;
  759. merge.list = NULL;
  760. qif_object_map_foreach(fctx, QIF_O_SECURITY, qif_merge_secs, &merge);
  761. securities = merge.list;
  762. /* repoint the transactions to the merged context data */
  763. qif_object_list_foreach(fctx, QIF_O_TXN, qif_massage_txn, ctx);
  764. /* then remove from the file context objects referenced in the top context */
  765. merge.ctx = fctx;
  766. merge.type = QIF_O_ACCOUNT;
  767. g_list_foreach(accts, qif_merge_del, &merge);
  768. g_list_free(accts);
  769. merge.type = QIF_O_CATEGORY;
  770. g_list_foreach(cats, qif_merge_del, &merge);
  771. g_list_free(cats);
  772. merge.type = QIF_O_CLASS;
  773. g_list_foreach(classes, qif_merge_del, &merge);
  774. g_list_free(classes);
  775. merge.type = QIF_O_SECURITY;
  776. g_list_foreach(securities, qif_merge_del, &merge);
  777. g_list_free(securities);
  778. }
  779. /* We've been parsed */
  780. ctx->parsed = TRUE;
  781. }