14297a3b0SGarrett D'Amore /* 22d08521bSGarrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org> 36b5e5868SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 44297a3b0SGarrett D'Amore * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org> 54297a3b0SGarrett D'Amore * All rights reserved. 64297a3b0SGarrett D'Amore * 74297a3b0SGarrett D'Amore * Redistribution and use in source and binary forms, with or without 84297a3b0SGarrett D'Amore * modification, are permitted provided that the following conditions 94297a3b0SGarrett D'Amore * are met: 104297a3b0SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 114297a3b0SGarrett D'Amore * notice, this list of conditions and the following disclaimer. 124297a3b0SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 134297a3b0SGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 144297a3b0SGarrett D'Amore * documentation and/or other materials provided with the distribution. 154297a3b0SGarrett D'Amore * 164297a3b0SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 174297a3b0SGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184297a3b0SGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194297a3b0SGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 204297a3b0SGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214297a3b0SGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224297a3b0SGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234297a3b0SGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244297a3b0SGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 254297a3b0SGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264297a3b0SGarrett D'Amore * SUCH DAMAGE. 274297a3b0SGarrett D'Amore */ 284297a3b0SGarrett D'Amore 294297a3b0SGarrett D'Amore #include "lint.h" 304297a3b0SGarrett D'Amore #include <limits.h> 314297a3b0SGarrett D'Amore #include <stddef.h> 324297a3b0SGarrett D'Amore #include <stdlib.h> 332d08521bSGarrett D'Amore #include <stdio.h> 342d08521bSGarrett D'Amore #include <string.h> 352d08521bSGarrett D'Amore #include <errno.h> 362d08521bSGarrett D'Amore #include "libc.h" 374297a3b0SGarrett D'Amore #include "ldpart.h" 384297a3b0SGarrett D'Amore #include "lmonetary.h" 392d08521bSGarrett D'Amore #include "localeimpl.h" 404297a3b0SGarrett D'Amore 414297a3b0SGarrett D'Amore extern const char *__fix_locale_grouping_str(const char *); 424297a3b0SGarrett D'Amore 432d08521bSGarrett D'Amore #define LCMONETARY_SIZE_FULL (sizeof (struct lc_monetary) / sizeof (char *)) 444297a3b0SGarrett D'Amore #define LCMONETARY_SIZE_MIN \ 452d08521bSGarrett D'Amore (offsetof(struct lc_monetary, int_p_cs_precedes) / sizeof (char *)) 464297a3b0SGarrett D'Amore 474297a3b0SGarrett D'Amore static char empty[] = ""; 484297a3b0SGarrett D'Amore static char numempty[] = { CHAR_MAX, '\0' }; 494297a3b0SGarrett D'Amore 502d08521bSGarrett D'Amore struct lc_monetary lc_monetary_posix = { 514297a3b0SGarrett D'Amore empty, /* int_curr_symbol */ 524297a3b0SGarrett D'Amore empty, /* currency_symbol */ 534297a3b0SGarrett D'Amore empty, /* mon_decimal_point */ 544297a3b0SGarrett D'Amore empty, /* mon_thousands_sep */ 554297a3b0SGarrett D'Amore numempty, /* mon_grouping */ 564297a3b0SGarrett D'Amore empty, /* positive_sign */ 574297a3b0SGarrett D'Amore empty, /* negative_sign */ 584297a3b0SGarrett D'Amore numempty, /* int_frac_digits */ 594297a3b0SGarrett D'Amore numempty, /* frac_digits */ 604297a3b0SGarrett D'Amore numempty, /* p_cs_precedes */ 614297a3b0SGarrett D'Amore numempty, /* p_sep_by_space */ 624297a3b0SGarrett D'Amore numempty, /* n_cs_precedes */ 634297a3b0SGarrett D'Amore numempty, /* n_sep_by_space */ 644297a3b0SGarrett D'Amore numempty, /* p_sign_posn */ 654297a3b0SGarrett D'Amore numempty, /* n_sign_posn */ 664297a3b0SGarrett D'Amore numempty, /* int_p_cs_precedes */ 674297a3b0SGarrett D'Amore numempty, /* int_n_cs_precedes */ 684297a3b0SGarrett D'Amore numempty, /* int_p_sep_by_space */ 694297a3b0SGarrett D'Amore numempty, /* int_n_sep_by_space */ 704297a3b0SGarrett D'Amore numempty, /* int_p_sign_posn */ 712d08521bSGarrett D'Amore numempty, /* int_n_sign_posn */ 722d08521bSGarrett D'Amore empty /* crncystr */ 734297a3b0SGarrett D'Amore }; 744297a3b0SGarrett D'Amore 752d08521bSGarrett D'Amore struct locdata __posix_monetary_locdata = { 762d08521bSGarrett D'Amore .l_lname = "C", 772d08521bSGarrett D'Amore .l_data = { &lc_monetary_posix } 782d08521bSGarrett D'Amore }; 794297a3b0SGarrett D'Amore 804297a3b0SGarrett D'Amore static char 814297a3b0SGarrett D'Amore cnv(const char *str) 824297a3b0SGarrett D'Amore { 834297a3b0SGarrett D'Amore int i = strtol(str, NULL, 10); 844297a3b0SGarrett D'Amore 854297a3b0SGarrett D'Amore if (i == -1) 864297a3b0SGarrett D'Amore i = CHAR_MAX; 874297a3b0SGarrett D'Amore return ((char)i); 884297a3b0SGarrett D'Amore } 894297a3b0SGarrett D'Amore 902d08521bSGarrett D'Amore struct locdata * 912d08521bSGarrett D'Amore __lc_monetary_load(const char *name) 924297a3b0SGarrett D'Amore { 934297a3b0SGarrett D'Amore int ret; 942d08521bSGarrett D'Amore int clen; 952d08521bSGarrett D'Amore struct lc_monetary *lmon; 962d08521bSGarrett D'Amore struct locdata *ldata; 974297a3b0SGarrett D'Amore 982d08521bSGarrett D'Amore if ((ldata = __locdata_alloc(name, sizeof (*lmon))) == NULL) { 992d08521bSGarrett D'Amore return (NULL); 1002d08521bSGarrett D'Amore } 1012d08521bSGarrett D'Amore lmon = ldata->l_data[0]; 1022d08521bSGarrett D'Amore 1032d08521bSGarrett D'Amore ret = __part_load_locale(name, (char **)&ldata->l_data[1], 1042d08521bSGarrett D'Amore "LC_MONETARY", LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN, 1052d08521bSGarrett D'Amore (const char **)lmon); 1062d08521bSGarrett D'Amore 1072d08521bSGarrett D'Amore if (ret != _LDP_LOADED) { 1082d08521bSGarrett D'Amore __locdata_free(ldata); 1092d08521bSGarrett D'Amore errno = EINVAL; 1102d08521bSGarrett D'Amore return (NULL); 1112d08521bSGarrett D'Amore } 1122d08521bSGarrett D'Amore 1132d08521bSGarrett D'Amore /* special storage for currency string */ 1142d08521bSGarrett D'Amore clen = strlen(lmon->currency_symbol) + 2; 1152d08521bSGarrett D'Amore ldata->l_data[2] = libc_malloc(clen); 1162d08521bSGarrett D'Amore lmon->crncystr = ldata->l_data[2]; 1172d08521bSGarrett D'Amore 1182d08521bSGarrett D'Amore lmon->mon_grouping = __fix_locale_grouping_str(lmon->mon_grouping); 1194297a3b0SGarrett D'Amore 1204297a3b0SGarrett D'Amore #define M_ASSIGN_CHAR(NAME) \ 1212d08521bSGarrett D'Amore (((char *)lmon->NAME)[0] = cnv(lmon->NAME)) 1224297a3b0SGarrett D'Amore 1234297a3b0SGarrett D'Amore M_ASSIGN_CHAR(int_frac_digits); 1244297a3b0SGarrett D'Amore M_ASSIGN_CHAR(frac_digits); 1254297a3b0SGarrett D'Amore M_ASSIGN_CHAR(p_cs_precedes); 1264297a3b0SGarrett D'Amore M_ASSIGN_CHAR(p_sep_by_space); 1274297a3b0SGarrett D'Amore M_ASSIGN_CHAR(n_cs_precedes); 1284297a3b0SGarrett D'Amore M_ASSIGN_CHAR(n_sep_by_space); 1294297a3b0SGarrett D'Amore M_ASSIGN_CHAR(p_sign_posn); 1304297a3b0SGarrett D'Amore M_ASSIGN_CHAR(n_sign_posn); 1314297a3b0SGarrett D'Amore 1324297a3b0SGarrett D'Amore /* 1334297a3b0SGarrett D'Amore * The six additional C99 international monetary formatting 1344297a3b0SGarrett D'Amore * parameters default to the national parameters when 1354297a3b0SGarrett D'Amore * reading FreeBSD LC_MONETARY data files. 1364297a3b0SGarrett D'Amore */ 1374297a3b0SGarrett D'Amore #define M_ASSIGN_ICHAR(NAME) \ 1382d08521bSGarrett D'Amore if (lmon->int_##NAME == NULL) \ 1392d08521bSGarrett D'Amore lmon->int_##NAME = lmon->NAME; \ 1404297a3b0SGarrett D'Amore else \ 1414297a3b0SGarrett D'Amore M_ASSIGN_CHAR(int_##NAME); 1424297a3b0SGarrett D'Amore 1434297a3b0SGarrett D'Amore M_ASSIGN_ICHAR(p_cs_precedes); 1444297a3b0SGarrett D'Amore M_ASSIGN_ICHAR(n_cs_precedes); 1454297a3b0SGarrett D'Amore M_ASSIGN_ICHAR(p_sep_by_space); 1464297a3b0SGarrett D'Amore M_ASSIGN_ICHAR(n_sep_by_space); 1474297a3b0SGarrett D'Amore M_ASSIGN_ICHAR(p_sign_posn); 1484297a3b0SGarrett D'Amore M_ASSIGN_ICHAR(n_sign_posn); 1492d08521bSGarrett D'Amore 1502d08521bSGarrett D'Amore /* 1512d08521bSGarrett D'Amore * Now calculate the currency string (CRNCYSTR) for nl_langinfo. 1522d08521bSGarrett D'Amore * This is a legacy SUSv2 interface. 1532d08521bSGarrett D'Amore */ 1542d08521bSGarrett D'Amore if ((lmon->p_cs_precedes[0] == lmon->n_cs_precedes[0]) && 1552d08521bSGarrett D'Amore (lmon->currency_symbol[0] != '\0')) { 1562d08521bSGarrett D'Amore char sign = '\0'; 1572d08521bSGarrett D'Amore switch (lmon->p_cs_precedes[0]) { 1582d08521bSGarrett D'Amore case 0: 159*538aa54dSGarrett D'Amore sign = '+'; 1602d08521bSGarrett D'Amore break; 1612d08521bSGarrett D'Amore case 1: 162*538aa54dSGarrett D'Amore sign = '-'; 1632d08521bSGarrett D'Amore break; 1642d08521bSGarrett D'Amore case CHAR_MAX: 1652d08521bSGarrett D'Amore /* 1662d08521bSGarrett D'Amore * Substitute currency string for radix character. 1672d08521bSGarrett D'Amore * To the best of my knowledge, no locale uses this. 1682d08521bSGarrett D'Amore */ 1692d08521bSGarrett D'Amore if (strcmp(lmon->mon_decimal_point, 1702d08521bSGarrett D'Amore lmon->currency_symbol) == 0) 1712d08521bSGarrett D'Amore sign = '.'; 1722d08521bSGarrett D'Amore break; 1734297a3b0SGarrett D'Amore } 1742d08521bSGarrett D'Amore (void) snprintf(lmon->crncystr, clen, "%c%s", sign, 1752d08521bSGarrett D'Amore lmon->currency_symbol); 1764297a3b0SGarrett D'Amore } 1774297a3b0SGarrett D'Amore 1782d08521bSGarrett D'Amore return (ldata); 1794297a3b0SGarrett D'Amore } 180