]> Dogcows Code - chaz/homebank/blob - src/hb-misc.c
import homebank-5.1.2
[chaz/homebank] / src / hb-misc.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2016 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
20
21 //nota: this file should be renamed hb-utils
22
23 #include "homebank.h"
24 #include "hb-misc.h"
25
26 #define MYDEBUG 0
27
28 #if MYDEBUG
29 #define DB(x) (x);
30 #else
31 #define DB(x);
32 #endif
33
34 /* our global datas */
35 extern struct HomeBank *GLOBALS;
36 extern struct Preferences *PREFS;
37
38 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
39
40 static const double fac[7] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
41
42 double hb_amount_round(const double x, unsigned int digits)
43 {
44 digits = MAX(digits, 6);
45 return floor((x * fac[digits]) + 0.5) / fac[digits];
46 }
47
48
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
52
53 gdouble hb_amount_to_euro(gdouble amount)
54 {
55 return hb_amount_round((amount / PREFS->euro_value), 2);
56 //return hb_amount_round((amount * PREFS->euro_value), PREFS.minor_cur->frac_digits);
57 }
58
59
60 /* new >5.1 currency fct
61 *
62 * convert an amount in base currency
63 *
64 */
65 gdouble hb_amount_base(gdouble value, guint32 kcur)
66 {
67 gdouble newvalue;
68 Currency *cur;
69
70 if(kcur == GLOBALS->kcur)
71 return value;
72
73 cur = da_cur_get(kcur);
74 if(cur == NULL || cur->rate == 0.0)
75 return 0;
76
77 newvalue = value / cur->rate;
78 return hb_amount_round(newvalue, cur->frac_digits);
79 }
80
81
82 static Currency *hb_strfmon_check(gchar *outstr, guint32 kcur)
83 {
84 Currency *cur = da_cur_get(kcur);
85
86 if(cur == NULL)
87 g_stpcpy(outstr, "nan");
88 return cur;
89 }
90
91
92 gchar *hb_str_rate(gchar *outstr, gint outlen, gdouble rate)
93 {
94 gint count, i;
95 gchar *p;
96
97 count = g_snprintf(outstr, outlen, "%.6f", rate);
98 //remove trailing 0 and decimal point
99 p = &outstr[count-1];
100 for(i=count;i>0;i--)
101 {
102 if(*p == '0')
103 *p = '\0';
104 else
105 break;
106 p--;
107 }
108 if(*p == '.' || *p == ',')
109 *p = '\0';
110
111 return outstr;
112 }
113
114 /* this function copy a number 99999.99 at s into d and count
115 * number of digits for integer part and decimal part
116 */
117 static gchar * _strfnumcopycount(gchar *s, gchar *d, gchar *decchar, gint *plen, gint *pnbint, gint *pnbdec)
118 {
119 gint len=0, nbint=0, nbdec=0;
120
121 // sign part
122 if(*s == '-') {
123 *d++ = *s++;
124 len++;
125 }
126 // integer part
127 while(*s != 0 && *s != '.') {
128 *d++ = *s++;
129 nbint++;
130 len++;
131 }
132 // decimal separator
133 if(*s == '.') {
134 d = g_stpcpy(d, decchar);
135 len++;
136 s++;
137 }
138 // decimal part
139 while(*s != 0) {
140 *d++ = *s++;
141 nbdec++;
142 len++;
143 }
144 // end string | fill external count
145 *d = 0;
146 *plen = len;
147 *pnbint = nbint;
148 *pnbdec = nbdec;
149
150 return d;
151 }
152
153 //todo: used only in ui_prefs.c
154 gchar *hb_str_formatd(gchar *outstr, gint outlen, gchar *buf1, Currency *cur, gboolean showsymbol)
155 {
156 gint len, nbd, nbi;
157 gchar *s, *d, *tmp;
158
159 d = tmp = outstr;
160 if(showsymbol && cur->sym_prefix)
161 {
162 d = g_stpcpy (d, cur->symbol);
163 *d++ = ' ';
164 tmp = d;
165 }
166
167 d = _strfnumcopycount(buf1, d, cur->decimal_char, &len, &nbi, &nbd);
168
169 if( cur->grouping_char != NULL && strlen(cur->grouping_char) > 0 )
170 {
171 gint i, grpcnt;
172
173 s = buf1;
174 d = tmp;
175 if(*s == '-')
176 *d++ = *s++;
177
178 grpcnt = 4 - nbi;
179 for(i=0;i<nbi;i++)
180 {
181 *d++ = *s++;
182 if( !(grpcnt % 3) && i<(nbi-1))
183 {
184 d = g_stpcpy(d, cur->grouping_char);
185 }
186 grpcnt++;
187 }
188
189 if(nbd > 0)
190 {
191 d = g_stpcpy(d, cur->decimal_char);
192 d = g_stpcpy(d, s+1);
193 }
194 *d = 0;
195 }
196
197 if(showsymbol && !cur->sym_prefix)
198 {
199 *d++ = ' ';
200 d = g_stpcpy (d, cur->symbol);
201 }
202
203 *d = 0;
204
205 return d;
206 }
207
208
209 void hb_strfmon(gchar *outstr, gint outlen, gdouble value, guint32 kcur, gboolean minor)
210 {
211 gchar formatd_buf[outlen];
212 Currency *cur;
213 gdouble monval;
214
215 if(minor == FALSE)
216 {
217 cur = hb_strfmon_check(outstr, kcur);
218 if(cur != NULL)
219 {
220 monval = hb_amount_round(value, cur->frac_digits);
221 g_ascii_formatd(formatd_buf, outlen, cur->format, monval);
222 hb_str_formatd(outstr, outlen, formatd_buf, cur, TRUE);
223 }
224 }
225 else
226 {
227 cur = &PREFS->minor_cur;
228 monval = hb_amount_to_euro(value);
229 g_ascii_formatd(formatd_buf, outlen, cur->format, monval);
230 hb_str_formatd(outstr, outlen, formatd_buf, cur, TRUE);
231 }
232
233 }
234
235 void hb_strfmon_int(gchar *outstr, gint outlen, gdouble value, guint32 kcur, gboolean minor)
236 {
237 gchar formatd_buf[outlen];
238 Currency *cur;
239 gdouble monval;
240
241 if(minor == FALSE)
242 {
243 cur = hb_strfmon_check(outstr, kcur);
244 if(cur != NULL)
245 {
246 monval = hb_amount_round(value, cur->frac_digits);
247 g_ascii_formatd(formatd_buf, outlen, "%0.f", monval);
248 hb_str_formatd(outstr, outlen, formatd_buf, cur, TRUE);
249 }
250 }
251 else
252 {
253 cur = &PREFS->minor_cur;
254 monval = hb_amount_to_euro(value);
255 g_ascii_formatd(formatd_buf, outlen, cur->format, monval);
256 hb_str_formatd(outstr, outlen, formatd_buf, cur, TRUE);
257 }
258
259 }
260
261
262 void hb_strfnum(gchar *outstr, gint outlen, gdouble value, guint32 kcur, gboolean minor)
263 {
264 gchar formatd_buf[outlen];
265 Currency *cur;
266 gdouble monval;
267
268 if(minor == FALSE)
269 {
270 cur = hb_strfmon_check(outstr, kcur);
271 if(cur != NULL)
272 {
273 monval = hb_amount_round(value, cur->frac_digits);
274 g_ascii_formatd(formatd_buf, outlen, "%0.f", monval);
275 hb_str_formatd(outstr, outlen, formatd_buf, cur, TRUE);
276 }
277 }
278 else
279 {
280 cur = &PREFS->minor_cur;
281 monval = hb_amount_to_euro(value);
282 g_ascii_formatd(formatd_buf, outlen, "%0.f", monval);
283 hb_str_formatd(outstr, outlen, formatd_buf, cur, TRUE);
284 }
285
286
287 }
288
289
290
291 gchar *get_normal_color_amount(gdouble value)
292 {
293 gchar *color = NULL;
294
295 //fix: 400483
296 value = hb_amount_round(value, 2);
297
298 if(value != 0.0 && PREFS->custom_colors == TRUE)
299 {
300 color = (value > 0.0) ? PREFS->color_inc : PREFS->color_exp;
301 }
302 return color;
303 }
304
305
306 gchar *get_minimum_color_amount(gdouble value, gdouble minvalue)
307 {
308 gchar *color = NULL;
309
310 //fix: 400483
311 value = hb_amount_round(value, 2);
312 if(value != 0.0 && PREFS->custom_colors == TRUE)
313 {
314 color = (value > 0.0) ? PREFS->color_inc : PREFS->color_exp;
315 if( value < minvalue)
316 color = PREFS->color_warn;
317 }
318 return color;
319 }
320
321 void hb_label_set_amount(GtkLabel *label, gdouble value, guint32 kcur, gboolean minor)
322 {
323 gchar strbuffer[G_ASCII_DTOSTR_BUF_SIZE];
324
325 hb_strfmon(strbuffer, G_ASCII_DTOSTR_BUF_SIZE-1, value, kcur, minor);
326 gtk_label_set_text(GTK_LABEL(label), strbuffer);
327
328 }
329
330
331 /*
332 ** format/color and set a label text with a amount value
333 */
334 void hb_label_set_colvalue(GtkLabel *label, gdouble value, guint32 kcur, gboolean minor)
335 {
336 gchar strbuffer[G_ASCII_DTOSTR_BUF_SIZE];
337 gchar *markuptxt;
338 gchar *color = NULL;
339
340 hb_strfmon(strbuffer, G_ASCII_DTOSTR_BUF_SIZE-1, value, kcur, minor);
341
342 if(value != 0.0 && PREFS->custom_colors == TRUE)
343 {
344 color = get_normal_color_amount(value);
345
346 //g_print("color: %s\n", color);
347
348 if(color)
349 {
350 markuptxt = g_strdup_printf("<span color='%s'>%s</span>", color, strbuffer);
351 gtk_label_set_markup(GTK_LABEL(label), markuptxt);
352 g_free(markuptxt);
353 return;
354 }
355 }
356
357 gtk_label_set_text(GTK_LABEL(label), strbuffer);
358
359 }
360
361
362
363
364 /*
365 ** String utility
366 */
367
368 gint hb_string_compare(gchar *s1, gchar *s2)
369 {
370 gint retval = 0;
371
372 if (s1 == NULL || s2 == NULL)
373 {
374 if (s1 == NULL && s2 == NULL)
375 goto end;
376
377 retval = (s1 == NULL) ? -1 : 1;
378 }
379 else
380 {
381 retval = strcasecmp(s1, s2);
382 }
383 end:
384 return retval;
385 }
386
387
388 /*
389 * compare 2 utf8 string
390 */
391 gint hb_string_utf8_compare(gchar *s1, gchar *s2)
392 {
393 gint retval = 0;
394 gchar *ns1, *ns2;
395
396 if (s1 == NULL || s2 == NULL)
397 {
398 if (s1 == NULL && s2 == NULL)
399 goto end;
400
401 retval = (s1 == NULL) ? -1 : 1;
402 }
403 else
404 {
405 //#1325969
406 //retval = g_utf8_collate(s1 != NULL ? s1 : "", s2 != NULL ? s2 : "");
407 ns1 = g_utf8_normalize(s1, -1, G_NORMALIZE_DEFAULT);
408 ns2 = g_utf8_normalize(s2, -1, G_NORMALIZE_DEFAULT);
409 retval = strcasecmp(ns1, ns2);
410 g_free(ns2);
411 g_free(ns1);
412 }
413 end:
414 return retval;
415 }
416
417
418 void hb_string_strip_crlf(gchar *str)
419 {
420 gchar *p = str;
421
422 if(str)
423 {
424 while( *p )
425 {
426 if( *p == '\n' || *p == '\r')
427 {
428 *p = '\0';
429 }
430 p++;
431 }
432 }
433 }
434
435
436 void hb_string_replace_char(gchar c, gchar *str)
437 {
438 gchar *s = str;
439 gchar *d = str;
440
441 if(str)
442 {
443 while( *s )
444 {
445 if( *s != c )
446 {
447 *d++ = *s;
448 }
449 s++;
450 }
451 *d = 0;
452 }
453 }
454
455
456 /*static void strip_extra_spaces(char* str) {
457 int i,x;
458 for(i=x=1; str[i]; ++i)
459 if(!isspace(str[i]) || (i>0 && !isspace(str[i-1])))
460 str[x++] = str[i];
461 str[x] = '\0';
462 }*/
463
464
465
466 gchar*
467 hb_strdup_nobrackets (const gchar *str)
468 {
469 const gchar *s;
470 gchar *new_str, *d;
471 gsize length;
472
473 if (str)
474 {
475 length = strlen (str) + 1;
476 new_str = g_new (char, length);
477 s = str;
478 d = new_str;
479 while(*s != '\0')
480 {
481 if( *s != '[' && *s != ']' )
482 *d++ = *s;
483 s++;
484 }
485 *d = '\0';
486 }
487 else
488 new_str = NULL;
489
490 return new_str;
491 }
492
493
494 static gboolean
495 hb_date_parser_get_nums(gchar *string, gint *n1, gint *n2, gint *n3)
496 {
497 gboolean retval;
498 gchar **str_array;
499
500 //DB( g_print("(qif) hb_qif_parser_get_dmy for '%s'\n", string) );
501
502 retval = FALSE;
503 str_array = g_strsplit (string, "/", 3);
504 if( g_strv_length( str_array ) != 3 )
505 {
506 g_strfreev (str_array);
507 str_array = g_strsplit (string, ".", 3);
508 // fix 371381
509 //todo test
510 if( g_strv_length( str_array ) != 3 )
511 {
512 g_strfreev (str_array);
513 str_array = g_strsplit (string, "-", 3);
514 }
515 }
516
517 if( g_strv_length( str_array ) == 3 )
518 {
519 *n1 = atoi(str_array[0]);
520 *n2 = atoi(str_array[1]);
521 *n3 = atoi(str_array[2]);
522 retval = TRUE;
523 }
524
525 g_strfreev (str_array);
526
527 return retval;
528 }
529
530
531 guint32 hb_date_get_julian(gchar *string, gint datefmt)
532 {
533 GDate *date;
534 gint n1, n2, n3, d, m, y;
535 guint32 julian = 0;
536
537 DB( g_print("\n[utils] hb_date_get_julian\n") );
538
539 DB( g_print(" - '%s' dateorder=%d\n", string, datefmt) );
540
541 if( hb_date_parser_get_nums(string, &n1, &n2, &n3) )
542 {
543 DB( g_print(" - '%d' '%d' '%d'\n", n1, n2, n3) );
544
545 switch(datefmt)
546 {
547 case PRF_DATEFMT_MDY:
548 d = n2;
549 m = n1;
550 y = n3;
551 break;
552 case PRF_DATEFMT_DMY:
553 d = n1;
554 m = n2;
555 y = n3;
556 break;
557 default:
558 case PRF_DATEFMT_YMD:
559 d = n3;
560 m = n2;
561 y = n1;
562 break;
563 }
564
565 //correct for 2 digits year
566 if(y < 1970)
567 {
568 if(y < 60)
569 y += 2000;
570 else
571 y += 1900;
572 }
573
574 if(d <= 31 && m <= 12)
575 {
576 if( g_date_valid_dmy(d, m, y) )
577 {
578 date = g_date_new_dmy(d, m, y);
579 julian = g_date_get_julian (date);
580 g_date_free(date);
581 }
582 }
583
584 DB( g_print(" > %d %d %d julian=%d\n", d, m, y, julian) );
585
586 }
587
588 return julian;
589 }
590
591
592 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
593
594
595 gchar *hb_util_filename_new_with_extension(gchar *filename, const gchar *extension)
596 {
597 gchar *lastdot, *fwe;
598 gchar *newfilename;
599
600 DB( g_print("\n[util] filename with extension\n") );
601
602 DB( g_print(" - orig: '%s' => '%s'\n", filename, extension) );
603
604 //duplicate without extensions
605 lastdot = g_strrstr(filename, ".");
606 if(lastdot != NULL)
607 {
608 fwe = g_strndup(filename, strlen(filename) - strlen(lastdot));
609 DB( g_print(" - fwe: '%s'\n", fwe) );
610 newfilename = g_strdup_printf("%s.%s", fwe, extension);
611 g_free(fwe);
612 }
613 else
614 {
615 newfilename = g_strdup_printf("%s.%s", filename, extension);
616 }
617
618 DB( g_print(" - new: '%s'\n", newfilename) );
619
620 return newfilename;
621 }
622
623
624 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
625
626
627 gboolean hb_string_isdate(gchar *str)
628 {
629 gint d, m, y;
630
631 return(hb_date_parser_get_nums(str, &d, &m, &y));
632 }
633
634
635 gboolean hb_string_isdigit(gchar *str)
636 {
637 gboolean valid = TRUE;
638 while(*str && valid)
639 valid = g_ascii_isdigit(*str++);
640 return valid;
641 }
642
643 /*
644 gboolean hb_string_isprint(gchar *str)
645 {
646 gboolean valid = TRUE;
647 while(*str && valid)
648 valid = g_ascii_isprint(*str++);
649 return valid;
650 }
651 */
652
653
654
655 gboolean hb_string_isprint(gchar *str)
656 {
657 gboolean valid = TRUE;
658 gchar *p;
659 gunichar c;
660
661 if(g_utf8_validate(str, -1, NULL))
662 {
663 p = str;
664 while(*p && valid)
665 {
666 c = g_utf8_get_char(p);
667 valid = g_unichar_isprint(c);
668 p = g_utf8_next_char(p);
669 }
670 }
671 return valid;
672 }
673
674
675 gchar *hb_sprint_date(gchar *outstr, guint32 julian)
676 {
677 GDate date;
678
679 g_date_clear(&date, 1);
680 g_date_set_julian (&date, julian);
681 switch(PREFS->dtex_datefmt)
682 {
683 case PRF_DATEFMT_MDY:
684 {
685 g_sprintf(outstr, "%02d/%02d/%04d",
686 g_date_get_month(&date),
687 g_date_get_day(&date),
688 g_date_get_year(&date)
689 );
690 }
691 break;
692 case PRF_DATEFMT_DMY:
693 {
694 g_sprintf(outstr, "%02d/%02d/%04d",
695 g_date_get_day(&date),
696 g_date_get_month(&date),
697 g_date_get_year(&date)
698 );
699 }
700 default:
701 g_sprintf(outstr, "%04d/%02d/%02d",
702 g_date_get_year(&date),
703 g_date_get_month(&date),
704 g_date_get_day(&date)
705 );
706 break;
707 }
708 return outstr;
709 }
710
711
712 //used only in DB() macro !!
713 void hb_print_date(guint32 jdate, gchar *label)
714 {
715 gchar buffer1[128];
716 GDate *date;
717
718 date = g_date_new_julian(jdate);
719 g_date_strftime (buffer1, 128-1, "%x", date);
720 g_date_free(date);
721 g_print(" - %s %s\n", label != NULL ? label:"date is", buffer1);
722 }
723
724
725
726 /*
727 ** parse a string an retrieve an iso date (dd-mm-yy(yy) or dd/mm/yy(yy))
728 **
729 */
730 /* obsolete 4.5
731 guint32 hb_date_get_julian_parse(gchar *str)
732 {
733 gchar **str_array = NULL;
734 GDate *date;
735 guint d, m, y;
736 guint32 julian = GLOBALS->today;
737
738 // try with - separator
739 if( g_strrstr(str, "-") != NULL )
740 {
741 str_array = g_strsplit (str, "-", 3);
742 }
743 else
744 {
745 if( g_strrstr(str, "/") != NULL )
746 {
747 str_array = g_strsplit (str, "/", 3);
748 }
749 }
750
751 if( g_strv_length( str_array ) == 3 )
752 {
753 d = atoi(str_array[0]);
754 m = atoi(str_array[1]);
755 y = atoi(str_array[2]);
756
757 //correct for 2 digits year
758 if(y < 1970)
759 {
760 if(y < 60)
761 y += 2000;
762 else
763 y += 1900;
764 }
765
766 //todo: here if month is > 12 then the format is probably mm/dd/yy(yy)
767 //or maybe check with g_date_valid_julian(julian)
768
769
770
771 date = g_date_new();
772 g_date_set_dmy(date, d, m, y);
773 julian = g_date_get_julian (date);
774 g_date_free(date);
775
776 DB( g_print("date: %s :: %d %d %d :: %d\n", str, d, m, y, julian ) );
777
778 }
779
780 g_strfreev (str_array);
781
782 return julian;
783 }
784 */
785
786 /* -------------------- */
787
788 #if MYDEBUG == 1
789
790 /*
791 ** hex memory dump
792 */
793 #define MAX_DUMP 16
794 void hex_dump(guchar *ptr, guint length)
795 {
796 guchar ascii[MAX_DUMP+4];
797 guint i,j;
798
799 g_print("**hex_dump - %d bytes\n", length);
800
801 for(i=0;i<length;)
802 {
803 g_print("%08x: ", (guint)ptr+i);
804
805 for(j=0;j<MAX_DUMP;j++)
806 {
807 if(i >= length) break;
808
809 //store ascii value
810 if(ptr[i] >= 32 && ptr[i] <= 126)
811 ascii[j] = ptr[i];
812 else
813 ascii[j] = '.';
814
815 g_print("%02x ", ptr[i]);
816 i++;
817 }
818 //newline
819 ascii[j] = 0;
820 g_print(" '%s'\n", ascii);
821 }
822 }
823
824 #endif
This page took 0.064118 seconds and 5 git commands to generate.