Back to index

glibc  2.9
alt_digit.c
Go to the documentation of this file.
00001 /* Helper functions used by strftime/strptime to handle alternate digits.
00002    Copyright (C) 1995-2002, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include "../locale/localeinfo.h"
00021 #include <bits/libc-lock.h>
00022 #include <stdlib.h>
00023 #include <wchar.h>
00024 #include <string.h>
00025 
00026 /* Some of the functions here must not be used while setlocale is called.  */
00027 __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
00028 
00029 #define CURRENT(item) (current->values[_NL_ITEM_INDEX (item)].string)
00030 #define CURRENT_WSTR(item) \
00031   ((wchar_t *) current->values[_NL_ITEM_INDEX (item)].wstr)
00032 
00033 static void
00034 _nl_init_alt_digit (struct locale_data *current)
00035 {
00036   struct lc_time_data *data;
00037 
00038   if (current->private.time == NULL)
00039     {
00040       current->private.time = malloc (sizeof *current->private.time);
00041       if (current->private.time == NULL)
00042        return;
00043       memset (current->private.time, 0, sizeof *current->private.time);
00044       current->private.cleanup = &_nl_cleanup_time;
00045     }
00046   data = current->private.time;
00047 
00048   if (! data->alt_digits_initialized)
00049     {
00050       const char *ptr = CURRENT (ALT_DIGITS);
00051       size_t cnt;
00052 
00053       data->alt_digits_initialized = 1;
00054 
00055       if (ptr != NULL)
00056        {
00057          data->alt_digits = malloc (100 * sizeof (const char *));
00058          if (data->alt_digits != NULL)
00059            for (cnt = 0; cnt < 100; ++cnt)
00060              {
00061               data->alt_digits[cnt] = ptr;
00062 
00063               /* Skip digit format. */
00064               ptr = strchr (ptr, '\0') + 1;
00065              }
00066        }
00067     }
00068 
00069 }
00070 
00071 const char *
00072 internal_function
00073 _nl_get_alt_digit (unsigned int number, struct locale_data *current)
00074 {
00075   const char *result;
00076 
00077   if (number >= 100 || CURRENT (ALT_DIGITS)[0] == '\0')
00078     return NULL;
00079 
00080   __libc_rwlock_wrlock (__libc_setlocale_lock);
00081 
00082   if (current->private.time == NULL
00083       || ! current->private.time->alt_digits_initialized)
00084     _nl_init_alt_digit (current);
00085 
00086   result = ((current->private.time != NULL
00087             && current->private.time->alt_digits != NULL)
00088            ? current->private.time->alt_digits[number]
00089            : NULL);
00090 
00091   __libc_rwlock_unlock (__libc_setlocale_lock);
00092 
00093   return result;
00094 }
00095 
00096 
00097 const wchar_t *
00098 internal_function
00099 _nl_get_walt_digit (unsigned int number, struct locale_data *current)
00100 {
00101   const wchar_t *result = NULL;
00102   struct lc_time_data *data;
00103 
00104   if (number >= 100 || CURRENT_WSTR (_NL_WALT_DIGITS)[0] == L'\0')
00105     return NULL;
00106 
00107   __libc_rwlock_wrlock (__libc_setlocale_lock);
00108 
00109   if (current->private.time == NULL)
00110     {
00111       current->private.time = malloc (sizeof *current->private.time);
00112       if (current->private.time == NULL)
00113        goto out;
00114       memset (current->private.time, 0, sizeof *current->private.time);
00115       current->private.cleanup = &_nl_cleanup_time;
00116     }
00117   data = current->private.time;
00118 
00119   if (! data->walt_digits_initialized)
00120     {
00121       const wchar_t *ptr = CURRENT_WSTR (_NL_WALT_DIGITS);
00122       size_t cnt;
00123 
00124       data->walt_digits_initialized = 1;
00125 
00126       if (ptr != NULL)
00127        {
00128          data->walt_digits = malloc (100 * sizeof (const uint32_t *));
00129          if (data->walt_digits != NULL)
00130            for (cnt = 0; cnt < 100; ++cnt)
00131              {
00132               data->walt_digits[cnt] = ptr;
00133 
00134               /* Skip digit format. */
00135               ptr = wcschr (ptr, L'\0') + 1;
00136              }
00137        }
00138     }
00139 
00140   if (data->walt_digits != NULL)
00141     result = data->walt_digits[number];
00142 
00143  out:
00144   __libc_rwlock_unlock (__libc_setlocale_lock);
00145 
00146   return (wchar_t *) result;
00147 }
00148 
00149 
00150 int
00151 internal_function
00152 _nl_parse_alt_digit (const char **strp, struct locale_data *current)
00153 {
00154   const char *str = *strp;
00155   int result = -1;
00156   size_t cnt;
00157   size_t maxlen = 0;
00158 
00159   if (CURRENT_WSTR (_NL_WALT_DIGITS)[0] == L'\0')
00160     return result;
00161 
00162   __libc_rwlock_wrlock (__libc_setlocale_lock);
00163 
00164   if (current->private.time == NULL
00165       || ! current->private.time->alt_digits_initialized)
00166     _nl_init_alt_digit (current);
00167 
00168   if (current->private.time != NULL &&
00169       current->private.time->alt_digits != NULL)
00170     /* Matching is not unambiguous.  The alternative digits could be like
00171        I, II, III, ... and the first one is a substring of the second
00172        and third.  Therefore we must keep on searching until we found
00173        the longest possible match.  Note that this is not specified in
00174        the standard.  */
00175     for (cnt = 0; cnt < 100; ++cnt)
00176       {
00177        const char *const dig = current->private.time->alt_digits[cnt];
00178        size_t len = strlen (dig);
00179 
00180        if (len > maxlen && strncmp (dig, str, len) == 0)
00181          {
00182            maxlen = len;
00183            result = (int) cnt;
00184          }
00185       }
00186 
00187   __libc_rwlock_unlock (__libc_setlocale_lock);
00188 
00189   if (result != -1)
00190     *strp += maxlen;
00191 
00192   return result;
00193 }