Home | History | Annotate | Line # | Download | only in printf
      1 /* Copyright (C) 2000, 2004, 2008 Free Software Foundation, Inc.
      2    This file is part of the GNU C Library.
      3    Contributed by Ulrich Drepper <drepper (at) 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 }
    140