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/>.
21 //nota: this file should be renamed hb-utils
34 /* our global datas */
35 extern struct HomeBank
*GLOBALS
;
36 extern struct Preferences
*PREFS
;
38 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
40 static const double fac
[9] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
42 double hb_amount_round(const double x
, unsigned int digits
)
44 digits
= MAX(digits
, 8);
45 return floor((x
* fac
[digits
]) + 0.5) / fac
[digits
];
49 // used to convert from national to euro currency
50 // used in hb_account.c :: only when convert account to euro
51 // round option is to 0.5 case so 1.32 is 1.3, but 1.35 is 1.4
53 gdouble
hb_amount_to_euro(gdouble amount
)
55 return hb_amount_round((amount
* PREFS
->euro_value
), PREFS
->minor_cur
.frac_digits
);
59 /* new >5.1 currency fct
61 * convert an amount in base currency
64 gdouble
hb_amount_base(gdouble value
, guint32 kcur
)
69 if(kcur
== GLOBALS
->kcur
)
72 cur
= da_cur_get(kcur
);
73 if(cur
== NULL
|| cur
->rate
== 0.0)
76 newvalue
= value
/ cur
->rate
;
77 return hb_amount_round(newvalue
, cur
->frac_digits
);
81 static Currency
*hb_strfmon_check(gchar
*outstr
, guint32 kcur
)
83 Currency
*cur
= da_cur_get(kcur
);
86 g_stpcpy(outstr
, "nan");
91 gchar
*hb_str_rate(gchar
*outstr
, gint outlen
, gdouble rate
)
96 count
= g_snprintf(outstr
, outlen
, "%.6f", rate
);
97 //remove trailing 0 and decimal point
107 if(*p
== '.' || *p
== ',')
113 /* this function copy a number 99999.99 at s into d and count
114 * number of digits for integer part and decimal part
116 static gchar
* _strfnumcopycount(gchar
*s
, gchar
*d
, gchar
*decchar
, gint
*plen
, gint
*pnbint
, gint
*pnbdec
)
118 gint len
=0, nbint
=0, nbdec
=0;
126 while(*s
!= 0 && *s
!= '.') {
133 d
= g_stpcpy(d
, decchar
);
143 // end string | fill external count
152 //todo: used only in ui_prefs.c
153 gchar
*hb_str_formatd(gchar
*outstr
, gint outlen
, gchar
*buf1
, Currency
*cur
, gboolean showsymbol
)
159 if(showsymbol
&& cur
->sym_prefix
)
161 d
= g_stpcpy (d
, cur
->symbol
);
166 d
= _strfnumcopycount(buf1
, d
, cur
->decimal_char
, &len
, &nbi
, &nbd
);
168 if( cur
->grouping_char
!= NULL
&& strlen(cur
->grouping_char
) > 0 )
181 if( !(grpcnt
% 3) && i
<(nbi
-1))
183 d
= g_stpcpy(d
, cur
->grouping_char
);
190 d
= g_stpcpy(d
, cur
->decimal_char
);
191 d
= g_stpcpy(d
, s
+1);
196 if(showsymbol
&& !cur
->sym_prefix
)
199 d
= g_stpcpy (d
, cur
->symbol
);
208 void hb_strfmon(gchar
*outstr
, gint outlen
, gdouble value
, guint32 kcur
, gboolean minor
)
210 gchar formatd_buf
[outlen
];
216 cur
= hb_strfmon_check(outstr
, kcur
);
219 monval
= hb_amount_round(value
, cur
->frac_digits
);
220 g_ascii_formatd(formatd_buf
, outlen
, cur
->format
, monval
);
221 hb_str_formatd(outstr
, outlen
, formatd_buf
, cur
, TRUE
);
226 monval
= hb_amount_base(value
, kcur
);
227 monval
= hb_amount_to_euro(monval
);
228 cur
= &PREFS
->minor_cur
;
229 g_ascii_formatd(formatd_buf
, outlen
, cur
->format
, monval
);
230 hb_str_formatd(outstr
, outlen
, formatd_buf
, cur
, TRUE
);
236 void hb_strfmon_int(gchar
*outstr
, gint outlen
, gdouble value
, guint32 kcur
, gboolean minor
)
238 gchar formatd_buf
[outlen
];
244 cur
= hb_strfmon_check(outstr
, kcur
);
247 monval
= hb_amount_round(value
, cur
->frac_digits
);
248 g_ascii_formatd(formatd_buf
, outlen
, "%0.f", monval
);
249 hb_str_formatd(outstr
, outlen
, formatd_buf
, cur
, TRUE
);
254 monval
= hb_amount_base(value
, kcur
);
255 monval
= hb_amount_to_euro(monval
);
256 cur
= &PREFS
->minor_cur
;
257 g_ascii_formatd(formatd_buf
, outlen
, cur
->format
, monval
);
258 hb_str_formatd(outstr
, outlen
, formatd_buf
, cur
, TRUE
);
264 void hb_strfnum(gchar
*outstr
, gint outlen
, gdouble value
, guint32 kcur
, gboolean minor
)
266 gchar formatd_buf
[outlen
];
272 cur
= hb_strfmon_check(outstr
, kcur
);
275 monval
= hb_amount_round(value
, cur
->frac_digits
);
276 g_ascii_formatd(formatd_buf
, outlen
, "%.2f", monval
);
277 hb_str_formatd(outstr
, outlen
, formatd_buf
, cur
, TRUE
);
282 cur
= &PREFS
->minor_cur
;
283 monval
= hb_amount_to_euro(value
);
284 g_ascii_formatd(formatd_buf
, outlen
, "%.2f", monval
);
285 hb_str_formatd(outstr
, outlen
, formatd_buf
, cur
, TRUE
);
292 gchar
*get_normal_color_amount(gdouble value
)
297 value
= hb_amount_round(value
, 2);
299 if(value
!= 0.0 && PREFS
->custom_colors
== TRUE
)
301 color
= (value
> 0.0) ? PREFS
->color_inc
: PREFS
->color_exp
;
307 gchar
*get_minimum_color_amount(gdouble value
, gdouble minvalue
)
312 value
= hb_amount_round(value
, 2);
313 if(value
!= 0.0 && PREFS
->custom_colors
== TRUE
)
315 color
= (value
> 0.0) ? PREFS
->color_inc
: PREFS
->color_exp
;
316 if( value
< minvalue
)
317 color
= PREFS
->color_warn
;
322 void hb_label_set_amount(GtkLabel
*label
, gdouble value
, guint32 kcur
, gboolean minor
)
324 gchar strbuffer
[G_ASCII_DTOSTR_BUF_SIZE
];
326 hb_strfmon(strbuffer
, G_ASCII_DTOSTR_BUF_SIZE
-1, value
, kcur
, minor
);
327 gtk_label_set_text(GTK_LABEL(label
), strbuffer
);
333 ** format/color and set a label text with a amount value
335 void hb_label_set_colvalue(GtkLabel
*label
, gdouble value
, guint32 kcur
, gboolean minor
)
337 gchar strbuffer
[G_ASCII_DTOSTR_BUF_SIZE
];
341 hb_strfmon(strbuffer
, G_ASCII_DTOSTR_BUF_SIZE
-1, value
, kcur
, minor
);
343 if(value
!= 0.0 && PREFS
->custom_colors
== TRUE
)
345 color
= get_normal_color_amount(value
);
347 //g_print("color: %s\n", color);
351 markuptxt
= g_strdup_printf("<span color='%s'>%s</span>", color
, strbuffer
);
352 gtk_label_set_markup(GTK_LABEL(label
), markuptxt
);
358 gtk_label_set_text(GTK_LABEL(label
), strbuffer
);
369 gint
hb_string_compare(gchar
*s1
, gchar
*s2
)
373 if (s1
== NULL
|| s2
== NULL
)
375 if (s1
== NULL
&& s2
== NULL
)
378 retval
= (s1
== NULL
) ? -1 : 1;
382 retval
= strcasecmp(s1
, s2
);
389 gint
hb_string_utf8_strstr(gchar
*haystack
, gchar
*needle
, gboolean exact
)
395 if( g_strstr_len(haystack
, -1, needle
) != NULL
)
397 DB( g_print(" found case '%s'\n", needle
) );
403 gchar
*nchaystack
= g_utf8_casefold(haystack
, -1);
404 gchar
*ncneedle
= g_utf8_casefold(needle
, -1);
406 if( g_strrstr(nchaystack
, ncneedle
) != NULL
)
408 DB( g_print(" found nocase '%s'\n", ncneedle
) );
423 * compare 2 utf8 string
425 gint
hb_string_utf8_compare(gchar
*s1
, gchar
*s2
)
430 if (s1
== NULL
|| s2
== NULL
)
432 if (s1
== NULL
&& s2
== NULL
)
435 retval
= (s1
== NULL
) ? -1 : 1;
440 //retval = g_utf8_collate(s1 != NULL ? s1 : "", s2 != NULL ? s2 : "");
441 ns1
= g_utf8_normalize(s1
, -1, G_NORMALIZE_DEFAULT
);
442 ns2
= g_utf8_normalize(s2
, -1, G_NORMALIZE_DEFAULT
);
443 retval
= strcasecmp(ns1
, ns2
);
452 void hb_string_strip_crlf(gchar
*str
)
460 if( *p
== '\n' || *p
== '\r')
470 void hb_string_replace_char(gchar c
, gchar
*str
)
490 gchar
*hb_string_copy_jsonpair(gchar
*dst
, gchar
*str
)
504 if( *str
!='{' && *str
!='\"' )
515 void hb_string_inline(gchar
*str
)
524 if( !(*s
==' ' || *s
=='\t' || *s
=='\n' || *s
=='\r') )
535 /*void strip_extra_spaces(char* str) {
537 for(i=x=1; str[i]; ++i)
538 if(!isspace(str[i]) || (i>0 && !isspace(str[i-1])))
546 hb_strdup_nobrackets (const gchar
*str
)
554 length
= strlen (str
) + 1;
555 new_str
= g_new (char, length
);
560 if( *s
!= '[' && *s
!= ']' )
574 hb_date_parser_get_nums(gchar
*string
, gint
*n1
, gint
*n2
, gint
*n3
)
579 //DB( g_print("(qif) hb_qif_parser_get_dmy for '%s'\n", string) );
584 str_array
= g_strsplit (string
, "/", 3);
585 if( g_strv_length( str_array
) != 3 )
587 g_strfreev (str_array
);
588 str_array
= g_strsplit (string
, ".", 3);
591 if( g_strv_length( str_array
) != 3 )
593 g_strfreev (str_array
);
594 str_array
= g_strsplit (string
, "-", 3);
598 if( g_strv_length( str_array
) == 3 )
600 *n1
= atoi(str_array
[0]);
601 *n2
= atoi(str_array
[1]);
602 *n3
= atoi(str_array
[2]);
606 g_strfreev (str_array
);
612 guint32
hb_date_get_julian(gchar
*string
, gint datefmt
)
615 gint n1
, n2
, n3
, d
, m
, y
;
618 DB( g_print("\n[utils] hb_date_get_julian\n") );
620 DB( g_print(" - '%s' dateorder=%d\n", string
, datefmt
) );
622 if( hb_date_parser_get_nums(string
, &n1
, &n2
, &n3
) )
624 DB( g_print(" - '%d' '%d' '%d'\n", n1
, n2
, n3
) );
628 case PRF_DATEFMT_MDY
:
633 case PRF_DATEFMT_DMY
:
639 case PRF_DATEFMT_YMD
:
646 //correct for 2 digits year
655 if(d
<= 31 && m
<= 12)
657 if( g_date_valid_dmy(d
, m
, y
) )
659 date
= g_date_new_dmy(d
, m
, y
);
660 julian
= g_date_get_julian (date
);
665 DB( g_print(" > %d %d %d julian=%d\n", d
, m
, y
, julian
) );
673 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
675 gint
hb_filename_type_get_by_extension(gchar
*filepath
)
677 gint retval
= FILETYPE_UNKNOWN
;
680 g_return_val_if_fail(filepath
!= NULL
, FILETYPE_UNKNOWN
);
682 str_len
= strlen(filepath
);
685 if( strcasecmp(filepath
+ str_len
- 4, ".ofx") == 0)
686 retval
= FILETYPE_OFX
;
688 if( strcasecmp(filepath
+ str_len
- 4, ".qif") == 0)
689 retval
= FILETYPE_QIF
;
691 if( strcasecmp(filepath
+ str_len
- 4, ".qfx") == 0)
692 retval
= FILETYPE_OFX
;
694 if( strcasecmp(filepath
+ str_len
- 4, ".csv") == 0)
695 retval
= FILETYPE_CSV_HB
;
697 if( strcasecmp(filepath
+ str_len
- 4, ".xhb") == 0)
698 retval
= FILETYPE_HOMEBANK
;
704 static gchar
*hb_filename_new_without_extension(gchar
*filename
)
708 lastdot
= g_strrstr (filename
, ".");
711 return g_strndup(filename
, strlen(filename
) - strlen(lastdot
));
713 return g_strdup(filename
);
717 static gint
hb_filename_backup_list_sort_func(gchar
**a
, gchar
**b
)
719 gint da
= atoi( *a
+ strlen(*a
) - 12);
720 gint db
= atoi( *b
+ strlen(*b
) - 12);
726 GPtrArray
*hb_filename_backup_list(gchar
*filename
)
728 gchar
*dirname
, *basename
;
729 gchar
*rawfilename
, *pattern
;
731 const gchar
*tmpname
;
735 DB( g_print("\n[util] filename backup list\n") );
737 dirname
= g_path_get_dirname(filename
);
738 basename
= g_path_get_basename(filename
);
740 DB( g_print(" dir='%s' base='%s'\n", dirname
, basename
) );
742 rawfilename
= hb_filename_new_without_extension(basename
);
743 pattern
= g_strdup_printf("%s-????????.bak", rawfilename
);
745 pspec
= g_pattern_spec_new(pattern
);
748 DB( g_print(" pattern='%s'\n", pattern
) );
750 array
= g_ptr_array_new_with_free_func(g_free
);
752 dir
= g_dir_open (PREFS
->path_hbfile
, 0, NULL
);
755 while ((tmpname
= g_dir_read_name (dir
)) != NULL
)
759 match
= g_pattern_match_string(pspec
, tmpname
);
762 DB( g_print(" %d => '%s'\n", match
, tmpname
) );
763 g_ptr_array_add(array
, g_strdup(tmpname
));
769 g_pattern_spec_free(pspec
);
775 g_ptr_array_sort(array
, (GCompareFunc
)hb_filename_backup_list_sort_func
);
781 gchar
*hb_filename_backup_get_filtername(gchar
*filename
)
783 gchar
*dirname
, *basename
;
784 gchar
*rawfilename
, *pattern
;
786 DB( g_print("\n[util] filename backup get filtername\n") );
788 dirname
= g_path_get_dirname(filename
);
789 basename
= g_path_get_basename(filename
);
791 DB( g_print(" dir='%s' base='%s'\n", dirname
, basename
) );
793 rawfilename
= hb_filename_new_without_extension(basename
);
795 pattern
= g_strdup_printf("%s*.[Bb][Aa][Kk]", rawfilename
);
805 gchar
*hb_filename_new_for_backup(gchar
*filename
)
807 gchar
*rawfilename
, *newfilename
;
810 DB( g_print("\n[util] filename new for backup\n") );
812 rawfilename
= hb_filename_new_without_extension(filename
);
814 g_date_clear(&date
, 1);
815 g_date_set_julian (&date
, GLOBALS
->today
);
817 newfilename
= g_strdup_printf("%s-%04d%02d%02d.bak",
819 g_date_get_year(&date
),
820 g_date_get_month(&date
),
821 g_date_get_day(&date
)
826 DB( g_print(" - '%s' => '%s'\n", filename
, newfilename
) );
832 gchar
*hb_filename_new_with_extension(gchar
*filename
, const gchar
*extension
)
834 gchar
*rawfilename
, *newfilename
;
836 DB( g_print("\n[util] filename new with extension\n") );
838 rawfilename
= hb_filename_new_without_extension(filename
);
839 newfilename
= g_strdup_printf("%s.%s", rawfilename
, extension
);
842 DB( g_print(" - '%s' => '%s'\n", filename
, newfilename
) );
848 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
851 gboolean
hb_string_isdate(gchar
*str
)
855 return(hb_date_parser_get_nums(str
, &d
, &m
, &y
));
859 gboolean
hb_string_isdigit(gchar
*str
)
861 gboolean valid
= TRUE
;
863 valid
= g_ascii_isdigit(*str
++);
868 gboolean hb_string_isprint(gchar *str)
870 gboolean valid = TRUE;
872 valid = g_ascii_isprint(*str++);
879 gboolean
hb_string_isprint(gchar
*str
)
881 gboolean valid
= TRUE
;
885 if(g_utf8_validate(str
, -1, NULL
))
890 c
= g_utf8_get_char(p
);
891 valid
= g_unichar_isprint(c
);
892 p
= g_utf8_next_char(p
);
899 gchar
*hb_sprint_date(gchar
*outstr
, guint32 julian
)
903 g_date_clear(&date
, 1);
904 g_date_set_julian (&date
, julian
);
905 switch(PREFS
->dtex_datefmt
)
907 case PRF_DATEFMT_MDY
:
909 g_sprintf(outstr
, "%02d/%02d/%04d",
910 g_date_get_month(&date
),
911 g_date_get_day(&date
),
912 g_date_get_year(&date
)
916 case PRF_DATEFMT_DMY
:
918 g_sprintf(outstr
, "%02d/%02d/%04d",
919 g_date_get_day(&date
),
920 g_date_get_month(&date
),
921 g_date_get_year(&date
)
926 g_sprintf(outstr
, "%04d/%02d/%02d",
927 g_date_get_year(&date
),
928 g_date_get_month(&date
),
929 g_date_get_day(&date
)
937 //used only in DB() macro !!
938 void hb_print_date(guint32 jdate
, gchar
*label
)
943 date
= g_date_new_julian(jdate
);
944 g_date_strftime (buffer1
, 128-1, "%x", date
);
946 g_print(" - %s %s\n", label
!= NULL
? label
:"date is", buffer1
);
952 ** parse a string an retrieve an iso date (dd-mm-yy(yy) or dd/mm/yy(yy))
956 guint32 hb_date_get_julian_parse(gchar *str)
958 gchar **str_array = NULL;
961 guint32 julian = GLOBALS->today;
963 // try with - separator
964 if( g_strrstr(str, "-") != NULL )
966 str_array = g_strsplit (str, "-", 3);
970 if( g_strrstr(str, "/") != NULL )
972 str_array = g_strsplit (str, "/", 3);
976 if( g_strv_length( str_array ) == 3 )
978 d = atoi(str_array[0]);
979 m = atoi(str_array[1]);
980 y = atoi(str_array[2]);
982 //correct for 2 digits year
991 //todo: here if month is > 12 then the format is probably mm/dd/yy(yy)
992 //or maybe check with g_date_valid_julian(julian)
997 g_date_set_dmy(date, d, m, y);
998 julian = g_date_get_julian (date);
1001 DB( g_print("date: %s :: %d %d %d :: %d\n", str, d, m, y, julian ) );
1005 g_strfreev (str_array);
1011 /* -------------------- */
1019 void hex_dump(guchar
*ptr
, guint length
)
1021 guchar ascii
[MAX_DUMP
+4];
1024 g_print("**hex_dump - %d bytes\n", length
);
1028 g_print("%08x: ", (guint
)ptr
+i
);
1030 for(j
=0;j
<MAX_DUMP
;j
++)
1032 if(i
>= length
) break;
1035 if(ptr
[i
] >= 32 && ptr
[i
] <= 126)
1040 g_print("%02x ", ptr
[i
]);
1045 g_print(" '%s'\n", ascii
);