]>
Commit | Line | Data |
---|---|---|
1a41c323 | 1 | /* Copyright (C) 2000-2013 Free Software Foundation, Inc. |
1d92226b JJ |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper <drepper@gnu.org>, 2000. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, write to the Free | |
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | 02111-1307 USA. */ | |
19 | ||
20 | /* Look up the value of the next multibyte character and return its numerical | |
21 | value if it is one of the digits known in the locale. If *DECIDED is | |
22 | -1 this means it is not yet decided which form it is and we have to | |
23 | search through all available digits. Otherwise we know which script | |
24 | the digits are from. */ | |
25 | static inline char * | |
26 | outdigit_value (char *s, int n) | |
27 | { | |
28 | const char *outdigit; | |
29 | size_t dlen; | |
30 | ||
31 | assert (0 <= n && n <= 9); | |
32 | outdigit = nl_langinfo (_NL_CTYPE_OUTDIGIT0_MB + n); | |
33 | dlen = strlen (outdigit); | |
34 | ||
35 | s -= dlen; | |
36 | while (dlen-- > 0) | |
37 | s[dlen] = outdigit[dlen]; | |
38 | ||
39 | return s; | |
40 | } | |
41 | ||
42 | /* Look up the value of the next multibyte character and return its numerical | |
43 | value if it is one of the digits known in the locale. If *DECIDED is | |
44 | -1 this means it is not yet decided which form it is and we have to | |
45 | search through all available digits. Otherwise we know which script | |
46 | the digits are from. */ | |
47 | static inline wchar_t | |
48 | outdigitwc_value (int n) | |
49 | { | |
50 | assert (0 <= n && n <= 9); | |
51 | ||
52 | return nl_langinfo_wc (_NL_CTYPE_OUTDIGIT0_WC + n); | |
53 | } | |
54 | ||
55 | static char * | |
56 | _i18n_number_rewrite (char *w, char *rear_ptr, char *end) | |
57 | { | |
58 | char decimal[MB_LEN_MAX + 1]; | |
59 | char thousands[MB_LEN_MAX + 1]; | |
60 | ||
61 | /* "to_outpunct" is a map from ASCII decimal point and thousands-sep | |
62 | to their equivalent in locale. This is defined for locales which | |
63 | use extra decimal point and thousands-sep. */ | |
64 | wctrans_t map = wctrans ("to_outpunct"); | |
65 | wint_t wdecimal = towctrans (L_('.'), map); | |
66 | wint_t wthousands = towctrans (L_(','), map); | |
67 | ||
68 | if (__builtin_expect (map != NULL, 0)) | |
69 | { | |
70 | mbstate_t state; | |
71 | memset (&state, '\0', sizeof (state)); | |
72 | ||
73 | size_t n = wcrtomb (decimal, wdecimal, &state); | |
74 | if (n == (size_t) -1) | |
75 | memcpy (decimal, ".", 2); | |
76 | else | |
77 | decimal[n] = '\0'; | |
78 | ||
79 | memset (&state, '\0', sizeof (state)); | |
80 | ||
81 | n = wcrtomb (thousands, wthousands, &state); | |
82 | if (n == (size_t) -1) | |
83 | memcpy (thousands, ",", 2); | |
84 | else | |
85 | thousands[n] = '\0'; | |
86 | } | |
87 | ||
88 | /* Copy existing string so that nothing gets overwritten. */ | |
89 | char *src; | |
90 | int use_alloca = (rear_ptr - w) < 4096; | |
91 | if (__builtin_expect (use_alloca, 1)) | |
92 | src = (char *) alloca (rear_ptr - w); | |
93 | else | |
94 | { | |
95 | src = (char *) malloc (rear_ptr - w); | |
96 | if (src == NULL) | |
97 | /* If we cannot allocate the memory don't rewrite the string. | |
98 | It is better than nothing. */ | |
99 | return w; | |
100 | } | |
101 | ||
102 | memcpy (src, w, rear_ptr - w); | |
103 | char *s = src + (rear_ptr - w); | |
104 | ||
105 | w = end; | |
106 | ||
107 | /* Process all characters in the string. */ | |
108 | while (--s >= src) | |
109 | { | |
110 | if (*s >= '0' && *s <= '9') | |
111 | { | |
112 | if (sizeof (char) == 1) | |
113 | w = (char *) outdigit_value ((char *) w, *s - '0'); | |
114 | else | |
115 | *--w = (char) outdigitwc_value (*s - '0'); | |
116 | } | |
117 | else if (__builtin_expect (map == NULL, 1) || (*s != '.' && *s != ',')) | |
118 | *--w = *s; | |
119 | else | |
120 | { | |
121 | if (sizeof (char) == 1) | |
122 | { | |
123 | const char *outpunct = *s == '.' ? decimal : thousands; | |
124 | size_t dlen = strlen (outpunct); | |
125 | ||
126 | w -= dlen; | |
127 | while (dlen-- > 0) | |
128 | w[dlen] = outpunct[dlen]; | |
129 | } | |
130 | else | |
131 | *--w = *s == '.' ? (char) wdecimal : (char) wthousands; | |
132 | } | |
133 | } | |
134 | ||
135 | if (! use_alloca) | |
136 | free (src); | |
137 | ||
138 | return w; | |
139 | } |