]> Dogcows Code - chaz/homebank/blob - src/hb-currency.c
import homebank-5.2.6
[chaz/homebank] / src / hb-currency.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 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 #include "homebank.h"
22
23 #include "hb-currency.h"
24 #include <libsoup/soup.h>
25
26 #ifdef G_OS_WIN32
27 #include <windows.h>
28 #endif
29
30 /****************************************************************************/
31 /* Debug macros */
32 /****************************************************************************/
33
34 #define MYDEBUG 0
35
36 #if MYDEBUG
37 #define DB(x) (x);
38 #else
39 #define DB(x);
40 #endif
41
42 /* our global datas */
43 extern struct HomeBank *GLOBALS;
44 extern struct Preferences *PREFS;
45
46 extern Currency4217 iso4217cur[];
47 extern guint n_iso4217cur;
48
49
50 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
51
52 void
53 da_cur_free(Currency *item)
54 {
55 DB( g_print("da_cur_free\n") );
56 if(item != NULL)
57 {
58 DB( g_print(" => %d, %s\n", item->key, item->iso_code) );
59
60 g_free(item->name);
61 g_free(item->iso_code);
62 g_free(item->symbol);
63 g_free(item->decimal_char);
64 g_free(item->grouping_char);
65
66 g_free(item);
67 }
68 }
69
70
71 Currency *
72 da_cur_malloc(void)
73 {
74 DB( g_print("da_cur_malloc\n") );
75 return g_malloc0(sizeof(Currency));
76 }
77
78
79 void
80 da_cur_destroy(void)
81 {
82 DB( g_print("da_cur_destroy\n") );
83 g_hash_table_destroy(GLOBALS->h_cur);
84 }
85
86 void
87 da_cur_new(void)
88 {
89 Currency4217 *curfmt;
90
91 DB( g_print("da_cur_new\n") );
92 GLOBALS->h_cur = g_hash_table_new_full(g_int_hash, g_int_equal, (GDestroyNotify)g_free, (GDestroyNotify)da_cur_free);
93
94 // insert default base currency
95 curfmt = iso4217format_get(PREFS->IntCurrSymbol);
96 if(curfmt == NULL)
97 curfmt = iso4217format_get("USD");
98
99 if(curfmt)
100 {
101 DB( g_printf("curfmt %p\n", curfmt) );
102
103 currency_add_from_user(curfmt);
104 }
105 }
106
107
108 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
109 static void da_cur_max_key_ghfunc(gpointer key, Currency *item, guint32 *max_key)
110 {
111 *max_key = MAX(*max_key, item->key);
112 }
113
114 static gboolean da_cur_name_grfunc(gpointer key, Currency *item, gchar *name)
115 {
116 if( name && item->name )
117 {
118 if(!strcasecmp(name, item->name))
119 return TRUE;
120 }
121 return FALSE;
122 }
123
124 static gboolean da_cur_iso_grfunc(gpointer key, Currency *item, gchar *iso)
125 {
126 if( iso && item->iso_code )
127 {
128 if(!strcasecmp(iso, item->iso_code))
129 return TRUE;
130 }
131 return FALSE;
132 }
133
134 guint
135 da_cur_length(void)
136 {
137 return g_hash_table_size(GLOBALS->h_cur);
138 }
139
140 gboolean
141 da_cur_remove(guint32 key)
142 {
143 DB( g_print("da_cur_remove %d\n", key) );
144
145 return g_hash_table_remove(GLOBALS->h_cur, &key);
146 }
147
148
149 void
150 da_cur_init_from4217(Currency *cur, Currency4217 *curfmt)
151 {
152 cur->symbol = g_strdup(curfmt->curr_symbol);
153 cur->sym_prefix = curfmt->curr_is_prefix;
154 cur->decimal_char = g_strdup(curfmt->curr_dec_char);
155 cur->grouping_char = g_strdup(curfmt->curr_grp_char);
156 cur->frac_digits = curfmt->curr_frac_digit;
157 da_cur_initformat(cur);
158 }
159
160
161 void
162 da_cur_initformat(Currency *item)
163 {
164 DB( g_print("init currency %s, %d \n", item->symbol, item->frac_digits) );
165
166 // for formatd
167 g_snprintf(item->format , 8-1, "%%.%df", item->frac_digits);
168
169 if(item->sym_prefix == TRUE)
170 g_snprintf(item->monfmt , 32-1, "%s %%s", item->symbol);
171 else
172 g_snprintf(item->monfmt , 32-1, "%%s %s", item->symbol);
173
174 DB( g_print("fmt '%s'\n", item->format) );
175 DB( g_print("monfmt '%s'\n", item->monfmt) );
176 }
177
178
179 gboolean
180 da_cur_insert(Currency *item)
181 {
182 guint32 *new_key;
183
184 DB( g_print("da_cur_insert\n") );
185
186 new_key = g_new0(guint32, 1);
187 *new_key = item->key;
188 g_hash_table_insert(GLOBALS->h_cur, new_key, item);
189
190 da_cur_initformat(item);
191
192 return TRUE;
193 }
194
195
196 gboolean
197 da_cur_append(Currency *item)
198 {
199 Currency *existitem;
200 guint32 *new_key;
201
202 DB( g_print("da_cur_append\n") );
203
204 /* ensure no duplicate */
205 existitem = da_cur_get_by_name( item->name );
206 if( existitem == NULL )
207 {
208 new_key = g_new0(guint32, 1);
209 *new_key = da_cur_get_max_key() + 1;
210 item->key = *new_key;
211 //item->pos = da_cur_length() + 1;
212
213 DB( g_print(" -> insert id: %d\n", *new_key) );
214
215 g_hash_table_insert(GLOBALS->h_cur, new_key, item);
216
217 da_cur_initformat(item);
218
219 return TRUE;
220 }
221
222 DB( g_print(" -> %s already exist: %d\n", item->iso_code, item->key) );
223
224 return FALSE;
225 }
226
227
228 guint32
229 da_cur_get_max_key(void)
230 {
231 guint32 max_key = 0;
232
233 g_hash_table_foreach(GLOBALS->h_cur, (GHFunc)da_cur_max_key_ghfunc, &max_key);
234 return max_key;
235 }
236
237
238 Currency *
239 da_cur_get_by_name(gchar *name)
240 {
241 DB( g_print("da_cur_get_by_name\n") );
242
243 return g_hash_table_find(GLOBALS->h_cur, (GHRFunc)da_cur_name_grfunc, name);
244 }
245
246
247 Currency *
248 da_cur_get_by_iso_code(gchar *iso_code)
249 {
250 DB( g_print("da_cur_get_by_iso_code\n") );
251
252 return g_hash_table_find(GLOBALS->h_cur, (GHRFunc)da_cur_iso_grfunc, iso_code);
253 }
254
255 Currency *
256 da_cur_get(guint32 key)
257 {
258 //DB( g_print("da_cur_get\n") );
259
260 return g_hash_table_lookup(GLOBALS->h_cur, &key);
261 }
262
263
264
265
266
267 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
268
269
270 gboolean
271 currency_is_euro(guint32 key)
272 {
273 Currency *item;
274 gboolean retval = FALSE;
275
276 item = da_cur_get(key);
277 if( item && item->iso_code )
278 {
279 if(!strcasecmp("EUR", item->iso_code))
280 retval = TRUE;
281 }
282 return retval;
283 }
284
285
286 /**
287 * currency_is_used:
288 *
289 * controls if a currency is used [base or account]
290 *
291 * Return value: TRUE if used, FALSE, otherwise
292 */
293 gboolean
294 currency_is_used(guint32 key)
295 {
296 GList *list;
297 gboolean retval;
298
299 if(GLOBALS->kcur == key)
300 return TRUE;
301
302 retval = FALSE;
303
304 list = g_hash_table_get_values(GLOBALS->h_acc);
305 while (list != NULL)
306 {
307 Account *item = list->data;
308
309 if(item->kcur == key)
310 {
311 retval = TRUE;
312 goto end;
313 }
314 list = g_list_next(list);
315 }
316
317 end:
318 g_list_free(list);
319
320 return retval;
321 }
322
323
324
325 Currency4217 *iso4217format_get(gchar *code)
326 {
327 Currency4217 *cur;
328 guint i;
329
330 for (i = 0; i< n_iso4217cur; i++)
331 {
332 cur = &iso4217cur[i];
333 if(g_strcmp0(cur->curr_iso_code, code) == 0)
334 {
335 return cur;
336 }
337 }
338 return NULL;
339 }
340
341
342 static void currency_get_system_format(Currency *item)
343 {
344 DB( g_printf("\n[(currency] get format from system '%s'\n", item->iso_code) );
345
346
347 #ifdef G_OS_UNIX
348
349 struct lconv *lc = localeconv();
350
351 DB( g_print("int_curr_symbol '%s'\n", lc->int_curr_symbol) );
352
353 DB( g_print("mon_decimal_point is utf8: %d\n", g_utf8_validate(lc->mon_decimal_point, -1, NULL)) );
354 DB( g_print("mon_decimal_point '%s'\n", lc->mon_decimal_point) );
355 DB( g_print("mon_decimal_point %x %x %x %x\n", lc->mon_decimal_point[0], lc->mon_decimal_point[1], lc->mon_decimal_point[2], lc->mon_decimal_point[3]) );
356
357 DB( g_print("mon_thousands_sep is utf8: %d\n", g_utf8_validate(lc->mon_thousands_sep, -1, NULL)) );
358 DB( g_print("mon_thousands_sep '%s'\n", lc->mon_thousands_sep) );
359 DB( g_print("mon_thousands_sep %x %x %x %x\n", lc->mon_thousands_sep[0], lc->mon_thousands_sep[1], lc->mon_thousands_sep[2], lc->mon_thousands_sep[3]) );
360
361
362 DB( g_print("frac_digits '%d'\n", (gint)lc->frac_digits) );
363
364 DB( g_print("currency_symbol '%s'\n", lc->currency_symbol) );
365
366 DB( g_print("p_cs_precedes '%d'\n", lc->p_cs_precedes) );
367
368 DB( g_print("n_cs_precedes '%d'\n", lc->n_cs_precedes) );
369
370 /* ok assign */
371 item->symbol = g_strdup(lc->currency_symbol);
372
373 if( lc->p_cs_precedes || lc->n_cs_precedes )
374 {
375 item->sym_prefix = TRUE;
376 DB( g_print("locale mon cs is a prefix\n") );
377 }
378 else
379 {
380 item->sym_prefix = FALSE;
381 }
382
383 item->decimal_char = g_strdup(lc->mon_decimal_point);
384
385 item->grouping_char = g_strdup(lc->mon_thousands_sep);
386
387 //todo:fix
388 //PREFS->base_cur.grouping_char = g_locale_to_utf8(lc->mon_thousands_sep, -1, NULL, NULL, NULL);
389 //PREFS->base_cur.grouping_char = g_convert (lc->mon_thousands_sep, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
390
391 DB( g_print(" -> grouping_char: '%s'\n", item->grouping_char) );
392
393 item->frac_digits = lc->frac_digits;
394
395 //fix 378992/421228
396 if( item->frac_digits > MAX_FRAC_DIGIT )
397 {
398 item->frac_digits = 2;
399 g_free(item->decimal_char);
400 item->decimal_char = g_strdup(".");
401 }
402
403 #else
404 #ifdef G_OS_WIN32
405 #define BUFFER_SIZE 512
406 char buffer[BUFFER_SIZE];
407 //LPWSTR wcBuffer = buffer;
408 LPSTR wcBuffer = buffer;
409 int iResult;
410
411 //https://msdn.microsoft.com/en-us/library/windows/desktop/dd464799%28v=vs.85%29.aspx
412
413 //see g_locale_to_utf8 here
414 iResult = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SCURRENCY, wcBuffer, BUFFER_SIZE);
415 if(iResult > 0)
416 {
417 DB( g_print("LOCALE_SCURRENCY='%s'\n", buffer) );
418 item->symbol = g_locale_to_utf8(buffer, -1, NULL, NULL, NULL);
419 }
420
421 item->sym_prefix = FALSE;
422 iResult = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IPOSSYMPRECEDES, wcBuffer, BUFFER_SIZE);
423 if(iResult > 0)
424 {
425 DB( g_print("LOCALE_IPOSSYMPRECEDES='%s'\n", buffer) );
426 //todo item->sym_prefix
427
428 }
429
430 iResult = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, wcBuffer, BUFFER_SIZE);
431 if(iResult > 0)
432 {
433 DB( g_print("LOCALE_SDECIMAL='%s'\n", buffer) );
434 item->decimal_char = g_locale_to_utf8(buffer, -1, NULL, NULL, NULL);
435 }
436
437 iResult = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, wcBuffer, BUFFER_SIZE);
438 if(iResult > 0)
439 {
440 DB( g_print("LOCALE_STHOUSAND='%s'\n", buffer) );
441 item->grouping_char = g_locale_to_utf8(buffer, -1, NULL, NULL, NULL);
442 }
443
444 iResult = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ICURRDIGITS, wcBuffer, BUFFER_SIZE);
445 if(iResult > 0)
446 {
447 DB( g_print("LOCALE_ICURRDIGITS='%s'\n", buffer) );
448 item->frac_digits = atoi(buffer);
449 }
450 else
451 item->frac_digits = 2;
452
453 #endif
454 #endif
455
456
457 }
458
459
460 Currency *currency_add_from_user(Currency4217 *curfmt)
461 {
462 Currency *item;
463
464 DB( g_printf("\n[(currency] found adding %s\n", curfmt->curr_iso_code) );
465
466 item = da_cur_malloc();
467 //no mem alloc here
468 //item->key = i;
469 if(curfmt != NULL)
470 {
471 item->name = g_strdup(curfmt->name);
472 //item->country = cur.country_name;
473 item->iso_code = g_strdup(curfmt->curr_iso_code);
474
475 //1634615 if the currency match the system, fill with it
476 if(!strcmp(item->iso_code, PREFS->IntCurrSymbol))
477 {
478 currency_get_system_format(item);
479 }
480 else
481 {
482 item->frac_digits = curfmt->curr_frac_digit;
483 item->symbol = g_strdup(curfmt->curr_symbol);
484 item->sym_prefix = curfmt->curr_is_prefix;
485 item->decimal_char = g_strdup(curfmt->curr_dec_char);
486 item->grouping_char = g_strdup(curfmt->curr_grp_char);
487 }
488 }
489 else
490 {
491 item->name = g_strdup("unknown");
492 //item->country = cur.country_name;
493 item->iso_code = g_strdup("XXX");
494 item->frac_digits = 2;
495 item->symbol = g_strdup("XXX");
496 item->sym_prefix = FALSE;
497 item->decimal_char = g_strdup(".");
498 item->grouping_char = NULL;
499 }
500
501 da_cur_append(item);
502
503 return item;
504 }
505
506
507 static gboolean currency_rate_update(gchar *isocode, gdouble rate, guint32 date)
508 {
509 gboolean retval = FALSE;
510 Currency *cur;
511
512 cur = da_cur_get_by_iso_code (isocode);
513 if(cur)
514 {
515 DB( g_print(" found cur='%s'\n", cur->iso_code) );
516 cur->rate = rate;
517 cur->mdate = date;
518 GLOBALS->changes_count++;
519 retval = TRUE;
520 }
521
522 return retval;
523 }
524
525
526 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
527 /* currency API
528 * discontinued see #1730527, #1785210
529 */
530
531 /* real open source fixer API */
532 /* DNS should be: https://frankfurter.app
533 * see https://github.com/fixerAPI/fixer/issues/107
534 */
535
536 /* old
537 ** api.fixer.io deprecated since 30/04/2019
538 ** QS: https://api.fixer.io/latest?base=EUR&symbols=USD,CHF,AUD,CAD,JPY,CNY,GBP
539 **
540 ** test API
541 ** gchar fixeriojson[] =
542 ** "{    }";
543 ** " { \r \"base\" : \"EUR\", \
544 ** \"date\": \n\r \"2017-12-04\", \
545 ** \"rates\" \n\n :{\"AUD\":1.5585,\"CAD\":1.5034,\"CHF\":1.1665,\"CNY\":7.8532,\"GBP\":0.87725,\"JPY\":133.91,\"USD\":1.1865 \
546 ** } }";
547 */
548
549
550 static gboolean api_fixerio_parse(const gchar *body, GError **error)
551 {
552 gchar *rawjson;
553 gchar *p;
554 gchar strbuf[48];
555 gchar isocode[8];
556 gdouble rate;
557 guint32 date = GLOBALS->today;
558 guint count = 0;
559
560 if(body)
561 {
562 //there is no need of a complex JSON parser here, so let's hack !
563 rawjson = g_strdup(body);
564 hb_string_inline(rawjson);
565
566 DB( g_printf("\nbody: '%s'\n", rawjson ) );
567
568 //get date
569 p = g_strstr_len(rawjson, -1, "\"date\"");
570 if(p)
571 {
572 strncpy(strbuf, p+8, 10);
573 strbuf[10]='\0';
574 date = hb_date_get_julian(strbuf, PRF_DATEFMT_YMD);
575 DB( g_printf("\n-date: %.10s %d\n", strbuf, date) );
576 }
577
578 //get rates
579 p = g_strstr_len(rawjson, -1, "\"rates\"");
580 if(p)
581 {
582 p = p+8;
583 do
584 {
585 p = hb_string_copy_jsonpair(strbuf, p);
586 strncpy(isocode, strbuf, 3);
587 isocode[3]='\0';
588 rate = g_ascii_strtod(strbuf+4, NULL);
589 DB( g_printf("\npair: '%s' '%s' %f\n", strbuf, isocode, rate ) );
590
591 if( currency_rate_update(isocode, rate, date) )
592 count++;
593 }
594 while( p != NULL );
595 }
596
597 g_free(rawjson);
598
599 }
600
601 return( (count > 0) ? TRUE : FALSE);
602 }
603
604
605 static gchar *api_fixerio_query_build(void)
606 {
607 GList *list;
608 GString *node;
609 Currency *base;
610 Currency *item;
611 gint i;
612
613 base = da_cur_get (GLOBALS->kcur);
614
615 node = g_string_sized_new(512);
616 //todo: think about encapsulate the API call ourself
617 //todo: let the user choose http / https
618 g_string_append_printf(node, "https://frankfurter.app/latest?base=%s&symbols=", base->iso_code);
619 //g_string_append_printf(node, "https://api.fixer.io/latest?base=%s&symbols=", base->iso_code);
620
621 list = g_hash_table_get_values(GLOBALS->h_cur);
622 i = g_list_length (list);
623 while (list != NULL)
624 {
625 item = list->data;
626
627 if( (item->key != GLOBALS->kcur) && (strlen(item->iso_code) == 3) )
628 {
629 g_string_append_printf(node, "%s", item->iso_code);
630 if(i > 1)
631 {
632 g_string_append(node, ",");
633 }
634 }
635 i--;
636 list = g_list_next(list);
637 }
638 g_list_free(list);
639
640 return g_string_free(node, FALSE);
641 }
642
643
644 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
645
646
647 gboolean currency_online_sync(GError **error)
648 {
649 SoupSession *session;
650 SoupMessage *msg;
651 gchar *query;
652 gboolean retval = TRUE;
653
654 DB( g_printf("\n[currency] sync online\n") );
655
656 query = api_fixerio_query_build();
657 DB( g_printf("query: '%s'\n", query) );
658
659 /*
660 //test API
661 retval = api_fixerio_parse(fixeriojson, error);
662 */
663
664 session = soup_session_new ();
665 msg = soup_message_new ("GET", query);
666 if(msg != NULL)
667 {
668 soup_session_send_message (session, msg);
669
670 DB( g_print("status_code: %d %d\n", msg->status_code, SOUP_STATUS_IS_SUCCESSFUL(msg->status_code) ) );
671 DB( g_print("reason: %s\n", msg->reason_phrase) );
672 DB( g_print("datas: %s\n", msg->response_body->data) );
673
674 if( SOUP_STATUS_IS_SUCCESSFUL(msg->status_code) == TRUE )
675 {
676 //#1750426 ignore the retval here (false when no rate was found, as we don't care)
677 api_fixerio_parse(msg->response_body->data, error);
678 }
679 else
680 {
681 *error = g_error_new_literal(1, msg->status_code, msg->reason_phrase);
682 retval = FALSE;
683 }
684
685 g_object_unref(msg);
686 }
687 else
688 {
689 *error = g_error_new_literal(1, 0, "cannot parse URI");
690 retval = FALSE;
691 }
692
693 g_free(query);
694
695 soup_session_abort (session);
696
697 g_object_unref(session);
698
699 return retval;
700 }
701
702
703 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
704
705
706 //struct iso_4217_currency iso_4217_currencies[];
707
708 /*debug testing
709 static void fill_currency(void)
710 {
711 gint i;
712 struct iso_4217_currency cur;
713 Currency *item;
714
715 for (i = 0; i< 500; i++)
716 {
717 cur = iso_4217_currencies[i];
718
719 if(cur.iso_code == NULL)
720 break;
721
722 item = da_cur_malloc();
723 //no mem alloc here
724 item->key = i;
725 item->name = cur.currency;
726 item->country = cur.country;
727 item->iso_code = cur.iso_code;
728
729 da_cur_insert(item);
730
731 }
732
733
734
735 }*/
736
737 Currency4217 iso4217cur[] =
738 {
739 { "AED", 2, ".", ",", TRUE, "د.إ.‏", "UAE Dirham" },
740 { "AFN", 0, ",", ",", TRUE, "؋", "Afghani" },
741 { "ALL", 0, ",", " ", FALSE, "Lekë", "Lek" },
742 { "AMD", 2, ".", ",", FALSE, "֏", "Armenian Dram" },
743 { "ANG", 2, ",", ",", TRUE, "NAf.", "Netherlands Antillian Guilder" },
744 { "AOA", 2, ",", " ", FALSE, "Kz", "Kwanza" },
745 { "ARS", 2, ",", ".", TRUE, "$", "Argentine Peso" },
746 { "AUD", 2, ".", ",", TRUE, "$", "Australian Dollar" },
747 { "AWG", 2, ",", ".", TRUE, "Afl.", "Aruban Guilder" },
748 { "AZN", 2, ",", " ", TRUE, "₼", "Azerbaijanian Manat" },
749 { "BAM", 2, ",", ".", FALSE, "KM", "Convertible Marks" },
750 { "BBD", 2, ".", ",", TRUE, "$", "Barbados Dollar" },
751 { "BDT", 2, ".", ",", TRUE, "৳", "Taka" },
752 { "BGN", 2, ",", " ", FALSE, "лв.", "Bulgarian Lev" },
753 { "BHD", 3, ".", ",", TRUE, "د.ب.‏", "Bahraini Dinar" },
754 { "BIF", 0, ",", " ", FALSE, "FBu", "Burundi Franc" },
755 { "BMD", 2, ".", ",", TRUE, "$", "Bermudian Dollar" },
756 { "BND", 2, ",", ".", TRUE, "$", "Brunei Dollar" },
757 { "BOB", 2, ",", ".", TRUE, "Bs", "Boliviano" },
758 { "BOV", 2, ".", "", FALSE, "BOV", "Mvdol" },
759 { "BRL", 2, ",", ".", TRUE, "R$", "Brazilian Real" },
760 { "BSD", 2, ".", ",", TRUE, "$", "Bahamian Dollar" },
761 { "BTN", 2, ".", ",", TRUE, "Nu.", "Ngultrum" },
762 { "BWP", 2, ".", " ", TRUE, "P", "Pula" },
763 { "BYN", 0, ",", " ", FALSE, "Br", "Belarussian Ruble" },
764 { "BYR", 0, ",", " ", FALSE, "Br", "Old Belarussian Ruble" },
765 { "BZD", 2, ".", ",", TRUE, "$", "Belize Dollar" },
766 { "CAD", 2, ",", " ", TRUE, "$", "Canadian Dollar" },
767 { "CDF", 2, ",", " ", TRUE, "FC", "Congolese Franc" },
768 { "CHE", 2, ".", "", FALSE, "CHE", "WIR Euro" },
769 { "CHF", 2, ",", "'", TRUE, "CHF", "Swiss Franc" },
770 { "CHW", 2, ".", "", FALSE, "CHW", "WIR Franc" },
771 { "CLF", 2, ".", "", FALSE, "CLF", "Unidades de fomento" },
772 { "CLP", 0, ",", ".", TRUE, "$", "Chilean Peso" },
773 { "CNY", 2, ".", ",", TRUE, "¥", "Yuan Renminbi" },
774 { "COP", 0, ",", ".", TRUE, "$", "Colombian Peso" },
775 { "COU", 2, ".", "", FALSE, "COU", "Unidad de Valor Real" },
776 { "CRC", 0, ",", ".", TRUE, "₡", "Costa Rican Colon" },
777 { "CUP", 2, ".", ",", TRUE, "$", "Cuban Peso" },
778 { "CVE", 2, "$", " ", FALSE, "​", "Cape Verde Escudo" },
779 { "CYP", 2, ".", "", FALSE, "CYP", "Cyprus Pound" },
780 { "CZK", 2, ",", " ", FALSE, "Kč", "Czech Koruna" },
781 { "DJF", 0, ",", " ", TRUE, "Fdj", "Djibouti Franc" },
782 { "DKK", 2, ",", ".", TRUE, "kr", "Danish Krone" },
783 { "DOP", 2, ".", ",", TRUE, "$", "Dominican Peso" },
784 { "DZD", 2, ",", " ", FALSE, "DA", "Algerian Dinar" },
785 { "EEK", 2, ".", "", FALSE, "EEK", "Kroon" },
786 { "EGP", 2, ".", ",", TRUE, "ج.م.‏", "Egyptian Pound" },
787 { "ERN", 2, ".", ",", TRUE, "Nfk", "Nakfa" },
788 { "ETB", 2, ".", ",", TRUE, "Br", "Ethiopian Birr" },
789 { "EUR", 2, ",", " ", TRUE, "€", "Euro" },
790 { "FJD", 2, ".", ",", TRUE, "$", "Fiji Dollar" },
791 { "FKP", 2, ".", ",", TRUE, "£", "Falkland Islands Pound" },
792 { "GBP", 2, ".", ",", TRUE, "£", "Pound Sterling" },
793 { "GEL", 2, ",", " ", TRUE, "₾", "Lari" },
794 { "GHS", 2, ".", ",", TRUE, "GH₵", "Ghana Cedi" },
795 { "GIP", 2, ".", ",", TRUE, "£", "Gibraltar Pound" },
796 { "GMD", 2, ".", ",", TRUE, "D", "Dalasi" },
797 { "GNF", 0, ",", " ", TRUE, "FG", "Guinea Franc" },
798 { "GTQ", 2, ".", ",", TRUE, "Q", "Quetzal" },
799 { "GYD", 0, ".", ",", TRUE, "$", "Guyana Dollar" },
800 { "HKD", 2, ".", ",", TRUE, "$", "Hong Kong Dollar" },
801 { "HNL", 2, ".", ",", TRUE, "L", "Lempira" },
802 { "HRK", 2, ",", ".", FALSE, "kn", "Croatian Kuna" },
803 { "HTG", 2, ",", " ", FALSE, "G", "Gourde" },
804 { "HUF", 2, ",", " ", FALSE, "HUF", "Forint" },
805 { "IDR", 0, ",", ".", TRUE, "Rp", "Rupiah" },
806 { "ILS", 2, ".", ",", TRUE, "₪", "New Israeli Sheqel" },
807 { "INR", 2, ".", ",", TRUE, "₹", "Indian Rupee" },
808 { "IQD", 2, ".", ",", TRUE, "د.ع.‏", "Iraqi Dinar" },
809 { "IRR", 2, "/", ",", TRUE, "ريال", "Iranian Rial" },
810 { "ISK", 0, ",", ".", FALSE, "ISK", "Iceland Krona" },
811 { "JMD", 2, ".", ",", TRUE, "$", "Jamaican Dollar" },
812 { "JOD", 3, ".", ",", TRUE, "د.ا.‏", "Jordanian Dinar" },
813 { "JPY", 0, ".", ",", TRUE, "¥", "Yen" },
814 { "KES", 2, ".", ",", TRUE, "Ksh", "Kenyan Shilling" },
815 { "KGS", 2, ",", " ", FALSE, "сом", "Som" },
816 { "KHR", 2, ".", ",", FALSE, "៛", "Riel" },
817 { "KMF", 0, ",", " ", TRUE, "CF", "Comoro Franc" },
818 { "KPW", 2, ".", "", FALSE, "KPW", "North Korean Won" },
819 { "KRW", 0, ".", ",", TRUE, "₩", "Won" },
820 { "KWD", 3, ".", ",", TRUE, "د.ك.‏", "Kuwaiti Dinar" },
821 { "KYD", 2, ".", ",", TRUE, "$", "Cayman Islands Dollar" },
822 { "KZT", 2, ",", " ", FALSE, "₸", "Tenge" },
823 { "LAK", 0, ",", ".", TRUE, "₭", "Kip" },
824 { "LBP", 2, ".", ",", TRUE, "ل.ل.‏", "Lebanese Pound" },
825 { "LKR", 2, ".", ",", TRUE, "Rs.", "Sri Lanka Rupee" },
826 { "LRD", 2, ".", ",", TRUE, "$", "Liberian Dollar" },
827 { "LSL", 2, ".", "", FALSE, "LSL", "Loti" },
828 { "LTL", 2, ".", "", FALSE, "LTL", "Lithuanian Litas" },
829 { "LVL", 2, ".", "", FALSE, "LVL", "Latvian Lats" },
830 { "LYD", 3, ".", ",", TRUE, "د.ل.‏", "Libyan Dinar" },
831 { "MAD", 2, ",", " ", FALSE, "DH", "Moroccan Dirham" },
832 { "MDL", 2, ",", " ", FALSE, "L", "Moldovan Leu" },
833 { "MGA", 0, ",", " ", TRUE, "Ar", "Malagasy Ariary" },
834 { "MKD", 2, ",", " ", TRUE, "den", "Denar" },
835 { "MMK", 0, ".", ",", TRUE, "K", "Kyat" },
836 { "MNT", 0, ".", ",", TRUE, "₮", "Tugrik" },
837 { "MOP", 2, ",", " ", TRUE, "MOP", "Pataca" },
838 { "MRO", 0, ",", " ", TRUE, "UM", "Ouguiya" },
839 { "MTL", 2, ".", "", FALSE, "MTL", "Maltese Lira" },
840 { "MUR", 0, ",", " ", TRUE, "Rs", "Mauritius Rupee" },
841 { "MVR", 2, ".", ",", FALSE, "ރ.", "Rufiyaa" },
842 { "MWK", 2, ".", ",", TRUE, "MK", "Kwacha" },
843 { "MXN", 2, ".", ",", TRUE, "$", "Mexican Peso" },
844 { "MXV", 2, ".", "", FALSE, "MXV", "Mexican Unidad de Inversion (UDI)" },
845 { "MYR", 2, ".", ",", TRUE, "RM", "Malaysian Ringgit" },
846 { "MZN", 2, ",", " ", FALSE, "MTn", "Metical" },
847 { "NAD", 2, ",", " ", TRUE, "$", "Namibia Dollar" },
848 { "NGN", 2, ".", ",", TRUE, "₦", "Naira" },
849 { "NIO", 2, ".", ",", TRUE, "C$", "Cordoba Oro" },
850 { "NOK", 2, ",", " ", TRUE, "kr", "Norwegian Krone" },
851 { "NPR", 2, ".", ",", TRUE, "रु", "Nepalese Rupee" },
852 { "NZD", 2, ".", ",", TRUE, "$", "New Zealand Dollar" },
853 { "OMR", 3, ".", ",", TRUE, "ر.ع.‏", "Rial Omani" },
854 { "PAB", 2, ".", ",", TRUE, "B/.", "Balboa" },
855 { "PEN", 2, ".", ",", TRUE, "S/.", "Nuevo Sol" },
856 { "PGK", 2, ".", ",", TRUE, "K", "Kina" },
857 { "PHP", 2, ",", ",", TRUE, "₱", "Philippine Peso" },
858 { "PKR", 0, ".", ",", TRUE, "Rs", "Pakistan Rupee" },
859 { "PLN", 2, ",", " ", FALSE, "zł", "Zloty" },
860 { "PYG", 0, ",", ".", TRUE, "₲", "Guarani" },
861 { "QAR", 2, ".", ",", TRUE, "ر.ق.‏", "Qatari Rial" },
862 { "RON", 2, ",", ".", FALSE, "RON", "New Leu" },
863 { "RSD", 0, ",", ".", FALSE, "RSD", "Serbian Dinar" },
864 { "RUB", 2, ",", " ", TRUE, "₽", "Russian Ruble" },
865 { "RWF", 0, ",", " ", TRUE, "RF", "Rwanda Franc" },
866 { "SAR", 2, ".", ",", TRUE, "ر.س.‏", "Saudi Riyal" },
867 { "SBD", 2, ".", ",", TRUE, "$", "Solomon Islands Dollar" },
868 { "SCR", 2, ",", " ", TRUE, "SR", "Seychelles Rupee" },
869 { "SDG", 2, ".", ",", TRUE, "SDG", "Sudanese Pound" },
870 { "SEK", 2, ",", ".", FALSE, "kr", "Swedish Krona" },
871 { "SGD", 2, ".", ",", TRUE, "$", "Singapore Dollar" },
872 { "SHP", 2, ".", ",", TRUE, "£", "Saint Helena Pound" },
873 { "SLL", 0, ".", ",", TRUE, "Le", "Leone" },
874 { "SOS", 0, ".", ",", TRUE, "S", "Somali Shilling" },
875 { "SRD", 2, ",", ".", TRUE, "$", "Surinam Dollar" },
876 { "STD", 0, ",", " ", FALSE, "Db", "Dobra" },
877 { "SVC", 2, ".", "", FALSE, "SVC", "El Salvador Colon" },
878 { "SYP", 0, ",", " ", TRUE, "LS", "Syrian Pound" },
879 { "SZL", 2, ",", " ", TRUE, "E", "Lilangeni" },
880 { "THB", 2, ".", ",", TRUE, "฿", "Baht" },
881 { "TJS", 2, ",", " ", FALSE, "смн", "Somoni" },
882 { "TMM", 2, ".", "", FALSE, "TMM", "Manat" },
883 { "TND", 3, ",", " ", TRUE, "DT", "Tunisian Dinar" },
884 { "TOP", 2, ".", ",", TRUE, "T$", "Pa'anga" },
885 { "TRY", 2, ",", ".", FALSE, "₺", "New Turkish Lira" },
886 { "TTD", 2, ".", ",", TRUE, "$", "Trinidad and Tobago Dollar" },
887 { "TWD", 2, ".", ",", TRUE, "NT$", "New Taiwan Dollar" },
888 { "TZS", 0, ".", ",", TRUE, "TSh", "Tanzanian Shilling" },
889 { "UAH", 2, ",", " ", FALSE, "₴", "Hryvnia" },
890 { "UGX", 0, ".", ",", TRUE, "USh", "Uganda Shilling" },
891 { "USD", 2, ",", " ", TRUE, "$", "US Dollar" },
892 { "USN", 2, ".", "", FALSE, "USN", "US Dollar (Next day)" },
893 { "USS", 2, ".", "", FALSE, "USS", "US Dollar (Same day)" },
894 { "UYI", 2, ".", "", FALSE, "UYI", "Uruguay Peso en Unidades Indexadas" },
895 { "UYU", 2, ",", ".", TRUE, "$", "Peso Uruguayo" },
896 { "UZS", 0, ",", " ", TRUE, "soʻm", "Uzbekistan Sum" },
897 { "VEF", 2, ",", ".", TRUE, "Bs.", "Bolivar Fuerte" },
898 { "VND", 2, ",", ".", FALSE, "₫", "Dong" },
899 { "VUV", 0, ",", " ", TRUE, "VT", "Vatu" },
900 { "WST", 2, ".", ",", TRUE, "WS$", "Tala" },
901 { "XAF", 0, ",", " ", TRUE, "FCFA", "CFA Franc BEAC" },
902 { "XAG", 2, ".", "", FALSE, "XAG", "Silver" },
903 { "XAU", 2, ".", "", FALSE, "XAU", "Gold" },
904 { "XBA", 2, ".", "", FALSE, "XBA", "European Composite Unit (EURCO)" },
905 { "XBB", 2, ".", "", FALSE, "XBB", "European Monetary Unit (E.M.U.-6)" },
906 { "XBC", 2, ".", "", FALSE, "XBC", "European Unit of Account 9 (E.U.A.-9)" },
907 { "XBD", 2, ".", "", FALSE, "XBD", "European Unit of Account 17 (E.U.A.-17)" },
908 { "XCD", 2, ",", " ", TRUE, "$", "East Caribbean Dollar" },
909 { "XDR", 2, ",", " ", TRUE, "XDR", "Special Drawing Rights" },
910 { "XFO", 2, ".", "", FALSE, "XFO", "Gold-Franc" },
911 { "XFU", 2, ".", "", FALSE, "XFU", "UIC-Franc" },
912 { "XOF", 0, ",", " ", TRUE, "CFA", "CFA Franc BCEAO" },
913 { "XPD", 2, ".", "", FALSE, "XPD", "Palladium" },
914 { "XPF", 0, ",", " ", FALSE, "FCFP", "CFP Franc" },
915 { "XPT", 2, ".", "", FALSE, "XPT", "Platinum" },
916 { "XTS", 2, ".", "", FALSE, "XTS", "Code for testing purposes" },
917 { "XXX", 2, ".", "", FALSE, "XXX", "No currency" },
918 { "YER", 2, ".", ",", TRUE, "ر.ي.‏", "Yemeni Rial" },
919 { "ZAR", 2, ",", " ", TRUE, "R", "Rand" },
920 { "ZMK", 2, ".", "", FALSE, "ZMK", "Zambian Kwacha" },
921 { "ZWD", 2, ".", "", FALSE, "ZWD", "Zimbabwe Dollar" }
922 };
923 guint n_iso4217cur = G_N_ELEMENTS (iso4217cur);
924
This page took 0.080795 seconds and 4 git commands to generate.