f3404c5a0a09d13d7b4200ed31c8f141e8c0c62e
[kopensolaris-gnu/glibc.git] / stdio-common / _i18n_number.h
1 /* Copyright (C) 2000, 2004 Free Software Foundation, Inc.
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 #include <wchar.h>
21 #include <wctype.h>
22
23 #include "../locale/outdigits.h"
24 #include "../locale/outdigitswc.h"
25
26 static CHAR_T *
27 _i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr)
28 {
29 #ifdef COMPILE_WPRINTF
30   wint_t wdecimal = L'\0';
31   wint_t wthousands = L'\0';
32 # define decimal NULL
33 # define thousands NULL
34 #else
35   wint_t wdecimal = L'\0';
36   wint_t wthousands = L'\0';
37   char decimal[MB_LEN_MAX];
38   char thousands[MB_LEN_MAX];
39 #endif
40
41   /* "to_outpunct" is a map from ASCII decimal point and thousands-sep
42      to their equivalent in locale. This is defined for locales which
43      use extra decimal point and thousands-sep.  */
44   wctrans_t map = __wctrans ("to_outpunct");
45   if (map != NULL)
46     {
47       wdecimal = __towctrans (L'.', map);
48       wthousands = __towctrans (L',', map);
49
50 #ifndef COMPILE_WPRINTF
51       mbstate_t state;
52       memset (&state, '\0', sizeof (state));
53
54       if (__wcrtomb (decimal, wdecimal, &state) == (size_t) -1)
55         memcpy (decimal, ".", 2);
56
57       memset (&state, '\0', sizeof (state));
58
59       if (__wcrtomb (thousands, wthousands, &state) == (size_t) -1)
60         memcpy (thousands, ",", 2);
61 #endif
62     }
63
64   /* Copy existing string so that nothing gets overwritten.  */
65   CHAR_T *src = (CHAR_T *) alloca ((rear_ptr - w) * sizeof (CHAR_T));
66   CHAR_T *s = (CHAR_T *) __mempcpy (src, w,
67                                     (rear_ptr - w) * sizeof (CHAR_T));
68   w = rear_ptr;
69
70   /* Process all characters in the string.  */
71   while (--s >= src)
72     {
73       if (*s >= '0' && *s <= '9')
74         {
75           if (sizeof (CHAR_T) == 1)
76             w = (CHAR_T *) outdigit_value ((char *) w, *s - '0');
77           else
78             *--w = (CHAR_T) outdigitwc_value (*s - '0');
79         }
80       else if (__builtin_expect (map == NULL, 1) || (*s != '.' && *s != ','))
81         *--w = *s;
82       else
83         {
84           if (sizeof (CHAR_T) == 1)
85             {
86               const char *outpunct = *s == '.' ? decimal : thousands;
87               size_t dlen = strlen (outpunct);
88
89               w -= dlen;
90               while (dlen-- > 0)
91                 w[dlen] = outpunct[dlen];
92             }
93           else
94             *--w = *s == '.' ? (CHAR_T) wdecimal : (CHAR_T) wthousands;
95         }
96     }
97
98   return w;
99 }