]>
Dogcows Code - chaz/homebank/blob - src/hb-import-qif.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 Maxime DOYEN
4 * This file is part of HomeBank.
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * HomeBank 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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 //#include "ui-assist-import.h"
23 #include "hb-import.h"
25 /****************************************************************************/
27 /****************************************************************************/
36 /* our global datas */
37 extern struct HomeBank
*GLOBALS
;
38 extern struct Preferences
*PREFS
;
41 hb_qif_parser_parse(ImportContext
*ctx
, GenFile
*genfile
);
43 /* = = = = = = = = = = = = = = = = */
45 GList
*homebank_qif_import(ImportContext
*ictx
, GenFile
*genfile
)
47 DB( g_print("\n[import] homebank QIF\n") );
49 hb_qif_parser_parse(ictx
, genfile
);
51 return ictx
->gen_lst_txn
;;
55 /* = = = = = = = = = = = = = = = = */
58 hb_qif_parser_get_amount(gchar
*string
)
66 //DB( g_print("\n[qif] hb_qif_parser_get_amount\n") );
72 l
= strlen(string
) - 1;
74 // the first non-digit is a grouping, or a decimal separator
75 // if the non-digit is after a 3 digit serie, it might be a grouping
79 //DB( g_print(" %d :: %c :: ds='%c' ndcount=%d\n", i, string[i], dc, ndcount) );
81 if( string
[i
] == '-' || string
[i
] == '+' ) continue;
83 if( g_ascii_isdigit( string
[i
] ))
89 if( (ndcount
!= 3) && (string
[i
] == '.' || string
[i
]==',') )
97 //DB( g_print(" s='%s' :: ds='%c'\n", string, dc) );
100 new_str
= g_malloc (l
+3); //#1214077
104 if( g_ascii_isdigit( string
[i
] ) || string
[i
] == '-' )
109 if( string
[i
] == dc
)
113 amount
= g_ascii_strtod(new_str
, NULL
);
115 //DB( g_print(" -> amount was='%s' => to='%s' double='%f'\n", string, new_str, amount) );
122 /* O if m-d-y (american)
123 1 if d-m-y (european) */
126 hb_qif_parser_guess_datefmt(ImportContext *ctx)
128 gboolean retval = TRUE;
133 DB( g_print("(qif) get_datetype\n") );
135 qiflist = g_list_first(ctx->gen_lst_txn);
136 while (qiflist != NULL)
138 GenTxn *item = qiflist->data;
140 r = hb_qif_parser_get_dmy(item->date, &d, &m, &y);
141 valid = g_date_valid_dmy(d, m, y);
143 DB( g_print(" -> date: %s :: %d %d %d :: %d\n", item->date, d, m, y, valid ) );
151 qiflist = g_list_next(qiflist);
160 hb_qif_parser_get_block_type(gchar
*qif_line
)
163 gint type
= QIF_NONE
;
165 DB( g_print("--------\n[qif] block type\n") );
167 //DB( g_print(" -> str: %s type: %d\n", qif_line, type) );
170 if(g_str_has_prefix(qif_line
, "!Account") || g_str_has_prefix(qif_line
, "!account"))
176 typestr
= g_strsplit(qif_line
, ":", 2);
178 if( g_strv_length(typestr
) == 2 )
180 gchar
*qif_line
= g_utf8_casefold(typestr
[1], -1);
182 //DB( g_print(" -> str[1]: %s\n", typestr[1]) );
184 if( g_str_has_prefix(qif_line
, "bank") )
186 type
= QIF_TRANSACTION
;
189 if( g_str_has_prefix(qif_line
, "cash") )
191 type
= QIF_TRANSACTION
;
194 if( g_str_has_prefix(qif_line
, "ccard") )
196 type
= QIF_TRANSACTION
;
199 if( g_str_has_prefix(qif_line
, "invst") )
201 type
= QIF_TRANSACTION
;
204 if( g_str_has_prefix(qif_line
, "oth a") )
206 type
= QIF_TRANSACTION
;
209 if( g_str_has_prefix(qif_line
, "oth l") )
211 type
= QIF_TRANSACTION
;
214 if( g_str_has_prefix(qif_line
, "security") )
219 if( g_str_has_prefix(qif_line
, "prices") )
229 //DB( g_print(" -> return type: %d\n", type) );
236 hb_qif_parser_parse(ImportContext
*ctx
, GenFile
*genfile
)
241 DB( g_print("\n[qif] hb_qif_parser_parse\n") );
243 io
= g_io_channel_new_file(genfile
->filepath
, "r", NULL
);
249 gint type
= QIF_NONE
;
251 GenAcc tmpgenacc
= { 0 };
254 DB( g_print(" -> encoding should be %s\n", genfile
->encoding
) );
255 if( genfile
->encoding
!= NULL
)
257 g_io_channel_set_encoding(io
, genfile
->encoding
, NULL
);
260 DB( g_print(" -> encoding is %s\n", g_io_channel_get_encoding(io
)) );
262 // within a single qif file, if there is no accoutn data
263 // then txn are related to a single account
268 io_stat
= g_io_channel_read_line(io
, &qif_line
, NULL
, NULL
, &err
);
270 if( io_stat
== G_IO_STATUS_EOF
)
272 if( io_stat
== G_IO_STATUS_ERROR
)
274 DB (g_print(" + ERROR %s\n",err
->message
));
277 if( io_stat
== G_IO_STATUS_NORMAL
)
279 hb_string_strip_crlf(qif_line
);
281 //DB (g_print("** new QIF line: '%s' **\n", qif_line));
284 if(g_str_has_prefix(qif_line
, "!")) /* !Type: or !Option: or !Account otherwise ignore */
286 type
= hb_qif_parser_get_block_type(qif_line
);
287 DB ( g_print("-> ---- QIF block: '%s' (type = %d) ----\n", qif_line
, type
) );
290 value
= &qif_line
[1];
292 if( type
== QIF_ACCOUNT
)
299 tmpgenacc
.name
= g_strdup(value
);
300 DB ( g_print(" name: '%s'\n", value
) );
304 case 'T': // Type of account
306 DB ( g_print(" type: '%s'\n", value
) );
308 if( g_ascii_strcasecmp("CCard", value
) == 0 )
310 tmpgenacc
.is_ccard
= TRUE
;
315 case 'D': // Description
318 DB ( g_print(" description: '%s'\n", value) );
322 case 'L': // Credit limit (only for credit card accounts)
323 if(g_str_has_prefix(qif_line, "L"))
326 DB ( g_print(" credit limit: '%s'\n", value) );
330 case '$': // Statement balance amount
333 DB ( g_print(" balance: '%s'\n", value) );
341 genacc
= hb_import_gen_acc_get_next (ctx
, FILETYPE_QIF
, tmpgenacc
.name
, NULL
);
342 dst_acc
= hb_import_acc_find_existing(tmpgenacc
.name
, NULL
);
343 if( dst_acc
!= NULL
)
345 DB( g_print(" - set dst_acc to %d\n", dst_acc
->key
) );
346 genacc
->kacc
= dst_acc
->key
;
348 genacc
->is_ccard
= tmpgenacc
.is_ccard
;
350 g_free(tmpgenacc
.name
);
351 tmpgenacc
.name
= NULL
;
352 tmpgenacc
.is_ccard
= FALSE
;
354 DB ( g_print(" ----------------\n") );
360 if( type
== QIF_TRANSACTION
)
368 // US Quicken seems to be using the ' to indicate post-2000 two-digit years
369 //(such as 01/01'00 for Jan 1 2000)
370 ptr
= g_strrstr (value
, "\'");
371 if(ptr
!= NULL
) { *ptr
= '/'; }
373 ptr
= g_strrstr (value
, " ");
374 if(ptr
!= NULL
) { *ptr
= '0'; }
377 tran
.date
= g_strdup(value
);
383 tran
.amount
= hb_qif_parser_get_amount(value
);
387 case 'C': // cleared status
389 tran
.reconciled
= FALSE
;
390 if(g_str_has_prefix(value
, "X") || g_str_has_prefix(value
, "R") )
392 tran
.reconciled
= TRUE
;
394 tran
.cleared
= FALSE
;
395 if(g_str_has_prefix(value
, "*") || g_str_has_prefix(value
, "c") )
402 case 'N': // check num or reference number
408 tran
.info
= g_strdup(value
);
419 tran
.rawpayee
= g_strdup(value
);
429 tran
.rawmemo
= g_strdup(value
);
434 case 'L': // category
436 // LCategory of transaction
437 // L[Transfer account name]
438 // LCategory of transaction/Class of transaction
439 // L[Transfer account]/Class of transaction
440 // this is managed at insertion
443 g_free(tran
.category
);
445 tran
.category
= g_strdup(value
);
454 if(tran
.nb_splits
< TXN_MAX_SPLIT
)
458 case 'S': // split category
460 GenSplit
*s
= &tran
.splits
[tran
.nb_splits
];
465 s
->category
= g_strdup(value
);
470 case 'E': // split memo
472 GenSplit
*s
= &tran
.splits
[tran
.nb_splits
];
476 s
->memo
= g_strdup(value
);
481 case '$': // split amount
483 GenSplit
*s
= &tran
.splits
[tran
.nb_splits
];
485 s
->amount
= hb_qif_parser_get_amount(value
);
486 // $ line normally end a split
488 g_print(" -> new split added: [%d] S=%s, E=%s, $=%.2f\n", tran
.nb_splits
, s
->category
, s
->memo
, s
->amount
);
501 case '^': // end of line
508 //ensure we have an account
512 genacc
= hb_import_gen_acc_get_next (ctx
, FILETYPE_QIF
, NULL
, NULL
);
515 tran
.account
= g_strdup(genacc
->name
);
517 DB ( g_print(" -> store qif txn: dat:'%s' amt:%.2f pay:'%s' mem:'%s' cat:'%s' acc:'%s' nbsplit:%d\n", tran
.date
, tran
.amount
, tran
.payee
, tran
.memo
, tran
.category
, tran
.account
, tran
.nb_splits
) );
519 newitem
= da_gen_txn_malloc();
520 da_gen_txn_move(&tran
, newitem
);
521 da_gen_txn_append(ctx
, newitem
);
526 //todo: should clear mem alloc here
536 // end QIF_TRANSACTION
538 // end of stat normal
543 g_io_channel_unref (io
);
This page took 0.054329 seconds and 4 git commands to generate.