Home | History | Annotate | Line # | Download | only in intl
      1  1.1  mrg /* Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
      2  1.1  mrg    Contributed by Ulrich Drepper <drepper (at) gnu.ai.mit.edu>, 1995.
      3  1.1  mrg 
      4  1.1  mrg    This program is free software; you can redistribute it and/or modify it
      5  1.1  mrg    under the terms of the GNU Library General Public License as published
      6  1.1  mrg    by the Free Software Foundation; either version 2, or (at your option)
      7  1.1  mrg    any later version.
      8  1.1  mrg 
      9  1.1  mrg    This program is distributed in the hope that it will be useful,
     10  1.1  mrg    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  1.1  mrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  1.1  mrg    Library General Public License for more details.
     13  1.1  mrg 
     14  1.1  mrg    You should have received a copy of the GNU Library General Public
     15  1.1  mrg    License along with this program; if not, write to the Free Software
     16  1.1  mrg    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
     17  1.1  mrg    USA.  */
     18  1.1  mrg 
     19  1.1  mrg /* Tell glibc's <string.h> to provide a prototype for stpcpy().
     20  1.1  mrg    This must come before <config.h> because <config.h> may include
     21  1.1  mrg    <features.h>, and once <features.h> has been included, it's too late.  */
     22  1.1  mrg #ifndef _GNU_SOURCE
     23  1.1  mrg # define _GNU_SOURCE	1
     24  1.1  mrg #endif
     25  1.1  mrg 
     26  1.1  mrg #ifdef HAVE_CONFIG_H
     27  1.1  mrg # include <config.h>
     28  1.1  mrg #endif
     29  1.1  mrg 
     30  1.1  mrg #include <string.h>
     31  1.1  mrg 
     32  1.1  mrg #if defined _LIBC || defined HAVE_ARGZ_H
     33  1.1  mrg # include <argz.h>
     34  1.1  mrg #endif
     35  1.1  mrg #include <ctype.h>
     36  1.1  mrg #include <sys/types.h>
     37  1.1  mrg #include <stdlib.h>
     38  1.1  mrg 
     39  1.1  mrg #include "loadinfo.h"
     40  1.1  mrg 
     41  1.1  mrg /* On some strange systems still no definition of NULL is found.  Sigh!  */
     42  1.1  mrg #ifndef NULL
     43  1.1  mrg # if defined __STDC__ && __STDC__
     44  1.1  mrg #  define NULL ((void *) 0)
     45  1.1  mrg # else
     46  1.1  mrg #  define NULL 0
     47  1.1  mrg # endif
     48  1.1  mrg #endif
     49  1.1  mrg 
     50  1.1  mrg /* @@ end of prolog @@ */
     51  1.1  mrg 
     52  1.1  mrg #ifdef _LIBC
     53  1.1  mrg /* Rename the non ANSI C functions.  This is required by the standard
     54  1.1  mrg    because some ANSI C functions will require linking with this object
     55  1.1  mrg    file and the name space must not be polluted.  */
     56  1.1  mrg # ifndef stpcpy
     57  1.1  mrg #  define stpcpy(dest, src) __stpcpy(dest, src)
     58  1.1  mrg # endif
     59  1.1  mrg #else
     60  1.1  mrg # ifndef HAVE_STPCPY
     61  1.1  mrg static char *stpcpy PARAMS ((char *dest, const char *src));
     62  1.1  mrg # endif
     63  1.1  mrg #endif
     64  1.1  mrg 
     65  1.1  mrg /* Pathname support.
     66  1.1  mrg    ISSLASH(C)           tests whether C is a directory separator character.
     67  1.1  mrg    IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
     68  1.1  mrg                         it may be concatenated to a directory pathname.
     69  1.1  mrg  */
     70  1.1  mrg #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
     71  1.1  mrg   /* Win32, OS/2, DOS */
     72  1.1  mrg # define ISSLASH(C) ((C) == '/' || (C) == '\\')
     73  1.1  mrg # define HAS_DEVICE(P) \
     74  1.1  mrg     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
     75  1.1  mrg      && (P)[1] == ':')
     76  1.1  mrg # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
     77  1.1  mrg #else
     78  1.1  mrg   /* Unix */
     79  1.1  mrg # define ISSLASH(C) ((C) == '/')
     80  1.1  mrg # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
     81  1.1  mrg #endif
     82  1.1  mrg 
     83  1.1  mrg /* Define function which are usually not available.  */
     84  1.1  mrg 
     85  1.1  mrg #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
     86  1.1  mrg /* Returns the number of strings in ARGZ.  */
     87  1.1  mrg static size_t argz_count__ PARAMS ((const char *argz, size_t len));
     88  1.1  mrg 
     89  1.1  mrg static size_t
     90  1.1  mrg argz_count__ (argz, len)
     91  1.1  mrg      const char *argz;
     92  1.1  mrg      size_t len;
     93  1.1  mrg {
     94  1.1  mrg   size_t count = 0;
     95  1.1  mrg   while (len > 0)
     96  1.1  mrg     {
     97  1.1  mrg       size_t part_len = strlen (argz);
     98  1.1  mrg       argz += part_len + 1;
     99  1.1  mrg       len -= part_len + 1;
    100  1.1  mrg       count++;
    101  1.1  mrg     }
    102  1.1  mrg   return count;
    103  1.1  mrg }
    104  1.1  mrg # undef __argz_count
    105  1.1  mrg # define __argz_count(argz, len) argz_count__ (argz, len)
    106  1.1  mrg #else
    107  1.1  mrg # ifdef _LIBC
    108  1.1  mrg #  define __argz_count(argz, len) INTUSE(__argz_count) (argz, len)
    109  1.1  mrg # endif
    110  1.1  mrg #endif	/* !_LIBC && !HAVE___ARGZ_COUNT */
    111  1.1  mrg 
    112  1.1  mrg #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
    113  1.1  mrg /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
    114  1.1  mrg    except the last into the character SEP.  */
    115  1.1  mrg static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
    116  1.1  mrg 
    117  1.1  mrg static void
    118  1.1  mrg argz_stringify__ (argz, len, sep)
    119  1.1  mrg      char *argz;
    120  1.1  mrg      size_t len;
    121  1.1  mrg      int sep;
    122  1.1  mrg {
    123  1.1  mrg   while (len > 0)
    124  1.1  mrg     {
    125  1.1  mrg       size_t part_len = strlen (argz);
    126  1.1  mrg       argz += part_len;
    127  1.1  mrg       len -= part_len + 1;
    128  1.1  mrg       if (len > 0)
    129  1.1  mrg 	*argz++ = sep;
    130  1.1  mrg     }
    131  1.1  mrg }
    132  1.1  mrg # undef __argz_stringify
    133  1.1  mrg # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
    134  1.1  mrg #else
    135  1.1  mrg # ifdef _LIBC
    136  1.1  mrg #  define __argz_stringify(argz, len, sep) \
    137  1.1  mrg   INTUSE(__argz_stringify) (argz, len, sep)
    138  1.1  mrg # endif
    139  1.1  mrg #endif	/* !_LIBC && !HAVE___ARGZ_STRINGIFY */
    140  1.1  mrg 
    141  1.1  mrg #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
    142  1.1  mrg static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
    143  1.1  mrg 				  const char *entry));
    144  1.1  mrg 
    145  1.1  mrg static char *
    146  1.1  mrg argz_next__ (argz, argz_len, entry)
    147  1.1  mrg      char *argz;
    148  1.1  mrg      size_t argz_len;
    149  1.1  mrg      const char *entry;
    150  1.1  mrg {
    151  1.1  mrg   if (entry)
    152  1.1  mrg     {
    153  1.1  mrg       if (entry < argz + argz_len)
    154  1.1  mrg         entry = strchr (entry, '\0') + 1;
    155  1.1  mrg 
    156  1.1  mrg       return entry >= argz + argz_len ? NULL : (char *) entry;
    157  1.1  mrg     }
    158  1.1  mrg   else
    159  1.1  mrg     if (argz_len > 0)
    160  1.1  mrg       return argz;
    161  1.1  mrg     else
    162  1.1  mrg       return 0;
    163  1.1  mrg }
    164  1.1  mrg # undef __argz_next
    165  1.1  mrg # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
    166  1.1  mrg #endif	/* !_LIBC && !HAVE___ARGZ_NEXT */
    167  1.1  mrg 
    168  1.1  mrg 
    169  1.1  mrg /* Return number of bits set in X.  */
    170  1.1  mrg static int pop PARAMS ((int x));
    171  1.1  mrg 
    172  1.1  mrg static inline int
    173  1.1  mrg pop (x)
    174  1.1  mrg      int x;
    175  1.1  mrg {
    176  1.1  mrg   /* We assume that no more than 16 bits are used.  */
    177  1.1  mrg   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
    178  1.1  mrg   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
    179  1.1  mrg   x = ((x >> 4) + x) & 0x0f0f;
    180  1.1  mrg   x = ((x >> 8) + x) & 0xff;
    181  1.1  mrg 
    182  1.1  mrg   return x;
    183  1.1  mrg }
    184  1.1  mrg 
    185  1.1  mrg 
    186  1.1  mrg struct loaded_l10nfile *
    188  1.1  mrg _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
    189  1.1  mrg 		    territory, codeset, normalized_codeset, modifier, special,
    190  1.1  mrg 		    sponsor, revision, filename, do_allocate)
    191  1.1  mrg      struct loaded_l10nfile **l10nfile_list;
    192  1.1  mrg      const char *dirlist;
    193  1.1  mrg      size_t dirlist_len;
    194  1.1  mrg      int mask;
    195  1.1  mrg      const char *language;
    196  1.1  mrg      const char *territory;
    197  1.1  mrg      const char *codeset;
    198  1.1  mrg      const char *normalized_codeset;
    199  1.1  mrg      const char *modifier;
    200  1.1  mrg      const char *special;
    201  1.1  mrg      const char *sponsor;
    202  1.1  mrg      const char *revision;
    203  1.1  mrg      const char *filename;
    204  1.1  mrg      int do_allocate;
    205  1.1  mrg {
    206  1.1  mrg   char *abs_filename;
    207  1.1  mrg   struct loaded_l10nfile **lastp;
    208  1.1  mrg   struct loaded_l10nfile *retval;
    209  1.1  mrg   char *cp;
    210  1.1  mrg   size_t dirlist_count;
    211  1.1  mrg   size_t entries;
    212  1.1  mrg   int cnt;
    213  1.1  mrg 
    214  1.1  mrg   /* If LANGUAGE contains an absolute directory specification, we ignore
    215  1.1  mrg      DIRLIST.  */
    216  1.1  mrg   if (IS_ABSOLUTE_PATH (language))
    217  1.1  mrg     dirlist_len = 0;
    218  1.1  mrg 
    219  1.1  mrg   /* Allocate room for the full file name.  */
    220  1.1  mrg   abs_filename = (char *) malloc (dirlist_len
    221  1.1  mrg 				  + strlen (language)
    222  1.1  mrg 				  + ((mask & TERRITORY) != 0
    223  1.1  mrg 				     ? strlen (territory) + 1 : 0)
    224  1.1  mrg 				  + ((mask & XPG_CODESET) != 0
    225  1.1  mrg 				     ? strlen (codeset) + 1 : 0)
    226  1.1  mrg 				  + ((mask & XPG_NORM_CODESET) != 0
    227  1.1  mrg 				     ? strlen (normalized_codeset) + 1 : 0)
    228  1.1  mrg 				  + (((mask & XPG_MODIFIER) != 0
    229  1.1  mrg 				      || (mask & CEN_AUDIENCE) != 0)
    230  1.1  mrg 				     ? strlen (modifier) + 1 : 0)
    231  1.1  mrg 				  + ((mask & CEN_SPECIAL) != 0
    232  1.1  mrg 				     ? strlen (special) + 1 : 0)
    233  1.1  mrg 				  + (((mask & CEN_SPONSOR) != 0
    234  1.1  mrg 				      || (mask & CEN_REVISION) != 0)
    235  1.1  mrg 				     ? (1 + ((mask & CEN_SPONSOR) != 0
    236  1.1  mrg 					     ? strlen (sponsor) : 0)
    237  1.1  mrg 					+ ((mask & CEN_REVISION) != 0
    238  1.1  mrg 					   ? strlen (revision) + 1 : 0)) : 0)
    239  1.1  mrg 				  + 1 + strlen (filename) + 1);
    240  1.1  mrg 
    241  1.1  mrg   if (abs_filename == NULL)
    242  1.1  mrg     return NULL;
    243  1.1  mrg 
    244  1.1  mrg   /* Construct file name.  */
    245  1.1  mrg   cp = abs_filename;
    246  1.1  mrg   if (dirlist_len > 0)
    247  1.1  mrg     {
    248  1.1  mrg       memcpy (cp, dirlist, dirlist_len);
    249  1.1  mrg       __argz_stringify (cp, dirlist_len, PATH_SEPARATOR);
    250  1.1  mrg       cp += dirlist_len;
    251  1.1  mrg       cp[-1] = '/';
    252  1.1  mrg     }
    253  1.1  mrg 
    254  1.1  mrg   cp = stpcpy (cp, language);
    255  1.1  mrg 
    256  1.1  mrg   if ((mask & TERRITORY) != 0)
    257  1.1  mrg     {
    258  1.1  mrg       *cp++ = '_';
    259  1.1  mrg       cp = stpcpy (cp, territory);
    260  1.1  mrg     }
    261  1.1  mrg   if ((mask & XPG_CODESET) != 0)
    262  1.1  mrg     {
    263  1.1  mrg       *cp++ = '.';
    264  1.1  mrg       cp = stpcpy (cp, codeset);
    265  1.1  mrg     }
    266  1.1  mrg   if ((mask & XPG_NORM_CODESET) != 0)
    267  1.1  mrg     {
    268  1.1  mrg       *cp++ = '.';
    269  1.1  mrg       cp = stpcpy (cp, normalized_codeset);
    270  1.1  mrg     }
    271  1.1  mrg   if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
    272  1.1  mrg     {
    273  1.1  mrg       /* This component can be part of both syntaces but has different
    274  1.1  mrg 	 leading characters.  For CEN we use `+', else `@'.  */
    275  1.1  mrg       *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
    276  1.1  mrg       cp = stpcpy (cp, modifier);
    277  1.1  mrg     }
    278  1.1  mrg   if ((mask & CEN_SPECIAL) != 0)
    279  1.1  mrg     {
    280  1.1  mrg       *cp++ = '+';
    281  1.1  mrg       cp = stpcpy (cp, special);
    282  1.1  mrg     }
    283  1.1  mrg   if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
    284  1.1  mrg     {
    285  1.1  mrg       *cp++ = ',';
    286  1.1  mrg       if ((mask & CEN_SPONSOR) != 0)
    287  1.1  mrg 	cp = stpcpy (cp, sponsor);
    288  1.1  mrg       if ((mask & CEN_REVISION) != 0)
    289  1.1  mrg 	{
    290  1.1  mrg 	  *cp++ = '_';
    291  1.1  mrg 	  cp = stpcpy (cp, revision);
    292  1.1  mrg 	}
    293  1.1  mrg     }
    294  1.1  mrg 
    295  1.1  mrg   *cp++ = '/';
    296  1.1  mrg   stpcpy (cp, filename);
    297  1.1  mrg 
    298  1.1  mrg   /* Look in list of already loaded domains whether it is already
    299  1.1  mrg      available.  */
    300  1.1  mrg   lastp = l10nfile_list;
    301  1.1  mrg   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
    302  1.1  mrg     if (retval->filename != NULL)
    303  1.1  mrg       {
    304  1.1  mrg 	int compare = strcmp (retval->filename, abs_filename);
    305  1.1  mrg 	if (compare == 0)
    306  1.1  mrg 	  /* We found it!  */
    307  1.1  mrg 	  break;
    308  1.1  mrg 	if (compare < 0)
    309  1.1  mrg 	  {
    310  1.1  mrg 	    /* It's not in the list.  */
    311  1.1  mrg 	    retval = NULL;
    312  1.1  mrg 	    break;
    313  1.1  mrg 	  }
    314  1.1  mrg 
    315  1.1  mrg 	lastp = &retval->next;
    316  1.1  mrg       }
    317  1.1  mrg 
    318  1.1  mrg   if (retval != NULL || do_allocate == 0)
    319  1.1  mrg     {
    320  1.1  mrg       free (abs_filename);
    321  1.1  mrg       return retval;
    322  1.1  mrg     }
    323  1.1  mrg 
    324  1.1  mrg   dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1);
    325  1.1  mrg 
    326  1.1  mrg   /* Allocate a new loaded_l10nfile.  */
    327  1.1  mrg   retval =
    328  1.1  mrg     (struct loaded_l10nfile *)
    329  1.1  mrg     malloc (sizeof (*retval)
    330  1.1  mrg 	    + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0))
    331  1.1  mrg 	       * sizeof (struct loaded_l10nfile *)));
    332  1.1  mrg   if (retval == NULL)
    333  1.1  mrg     return NULL;
    334  1.1  mrg 
    335  1.1  mrg   retval->filename = abs_filename;
    336  1.1  mrg 
    337  1.1  mrg   /* We set retval->data to NULL here; it is filled in later.
    338  1.1  mrg      Setting retval->decided to 1 here means that retval does not
    339  1.1  mrg      correspond to a real file (dirlist_count > 1) or is not worth
    340  1.1  mrg      looking up (if an unnormalized codeset was specified).  */
    341  1.1  mrg   retval->decided = (dirlist_count > 1
    342  1.1  mrg 		     || ((mask & XPG_CODESET) != 0
    343  1.1  mrg 			 && (mask & XPG_NORM_CODESET) != 0));
    344  1.1  mrg   retval->data = NULL;
    345  1.1  mrg 
    346  1.1  mrg   retval->next = *lastp;
    347  1.1  mrg   *lastp = retval;
    348  1.1  mrg 
    349  1.1  mrg   entries = 0;
    350  1.1  mrg   /* Recurse to fill the inheritance list of RETVAL.
    351  1.1  mrg      If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL
    352  1.1  mrg      entry does not correspond to a real file; retval->filename contains
    353  1.1  mrg      colons.  In this case we loop across all elements of DIRLIST and
    354  1.1  mrg      across all bit patterns dominated by MASK.
    355  1.1  mrg      If the DIRLIST is a single directory or entirely redundant (i.e.
    356  1.1  mrg      DIRLIST_COUNT == 1), we loop across all bit patterns dominated by
    357  1.1  mrg      MASK, excluding MASK itself.
    358  1.1  mrg      In either case, we loop down from MASK to 0.  This has the effect
    359  1.1  mrg      that the extra bits in the locale name are dropped in this order:
    360  1.1  mrg      first the modifier, then the territory, then the codeset, then the
    361  1.1  mrg      normalized_codeset.  */
    362  1.1  mrg   for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt)
    363  1.1  mrg     if ((cnt & ~mask) == 0
    364  1.1  mrg 	&& ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
    365  1.1  mrg 	&& ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
    366  1.1  mrg       {
    367  1.1  mrg 	if (dirlist_count > 1)
    368  1.1  mrg 	  {
    369  1.1  mrg 	    /* Iterate over all elements of the DIRLIST.  */
    370  1.1  mrg 	    char *dir = NULL;
    371  1.1  mrg 
    372  1.1  mrg 	    while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
    373  1.1  mrg 		   != NULL)
    374  1.1  mrg 	      retval->successor[entries++]
    375  1.1  mrg 		= _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1,
    376  1.1  mrg 				      cnt, language, territory, codeset,
    377  1.1  mrg 				      normalized_codeset, modifier, special,
    378  1.1  mrg 				      sponsor, revision, filename, 1);
    379  1.1  mrg 	  }
    380  1.1  mrg 	else
    381  1.1  mrg 	  retval->successor[entries++]
    382  1.1  mrg 	    = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len,
    383  1.1  mrg 				  cnt, language, territory, codeset,
    384  1.1  mrg 				  normalized_codeset, modifier, special,
    385  1.1  mrg 				  sponsor, revision, filename, 1);
    386  1.1  mrg       }
    387  1.1  mrg   retval->successor[entries] = NULL;
    388  1.1  mrg 
    389  1.1  mrg   return retval;
    390  1.1  mrg }
    391  1.1  mrg 
    392  1.1  mrg /* Normalize codeset name.  There is no standard for the codeset
    394  1.1  mrg    names.  Normalization allows the user to use any of the common
    395  1.1  mrg    names.  The return value is dynamically allocated and has to be
    396  1.1  mrg    freed by the caller.  */
    397  1.1  mrg const char *
    398  1.1  mrg _nl_normalize_codeset (codeset, name_len)
    399  1.1  mrg      const char *codeset;
    400  1.1  mrg      size_t name_len;
    401  1.1  mrg {
    402  1.1  mrg   int len = 0;
    403  1.1  mrg   int only_digit = 1;
    404  1.1  mrg   char *retval;
    405  1.1  mrg   char *wp;
    406  1.1  mrg   size_t cnt;
    407  1.1  mrg 
    408  1.1  mrg   for (cnt = 0; cnt < name_len; ++cnt)
    409  1.1  mrg     if (isalnum ((unsigned char) codeset[cnt]))
    410  1.1  mrg       {
    411  1.1  mrg 	++len;
    412  1.1  mrg 
    413  1.1  mrg 	if (isalpha ((unsigned char) codeset[cnt]))
    414  1.1  mrg 	  only_digit = 0;
    415  1.1  mrg       }
    416  1.1  mrg 
    417  1.1  mrg   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
    418  1.1  mrg 
    419  1.1  mrg   if (retval != NULL)
    420  1.1  mrg     {
    421  1.1  mrg       if (only_digit)
    422  1.1  mrg 	wp = stpcpy (retval, "iso");
    423  1.1  mrg       else
    424  1.1  mrg 	wp = retval;
    425  1.1  mrg 
    426  1.1  mrg       for (cnt = 0; cnt < name_len; ++cnt)
    427  1.1  mrg 	if (isalpha ((unsigned char) codeset[cnt]))
    428  1.1  mrg 	  *wp++ = tolower ((unsigned char) codeset[cnt]);
    429  1.1  mrg 	else if (isdigit ((unsigned char) codeset[cnt]))
    430  1.1  mrg 	  *wp++ = codeset[cnt];
    431  1.1  mrg 
    432  1.1  mrg       *wp = '\0';
    433  1.1  mrg     }
    434  1.1  mrg 
    435  1.1  mrg   return (const char *) retval;
    436  1.1  mrg }
    437  1.1  mrg 
    438  1.1  mrg 
    439  1.1  mrg /* @@ begin of epilog @@ */
    440  1.1  mrg 
    441  1.1  mrg /* We don't want libintl.a to depend on any other library.  So we
    442  1.1  mrg    avoid the non-standard function stpcpy.  In GNU C Library this
    443  1.1  mrg    function is available, though.  Also allow the symbol HAVE_STPCPY
    444  1.1  mrg    to be defined.  */
    445  1.1  mrg #if !_LIBC && !HAVE_STPCPY
    446  1.1  mrg static char *
    447  1.1  mrg stpcpy (dest, src)
    448  1.1  mrg      char *dest;
    449  1.1  mrg      const char *src;
    450  1.1  mrg {
    451  1.1  mrg   while ((*dest++ = *src++) != '\0')
    452  1.1  mrg     /* Do nothing. */ ;
    453  1.1  mrg   return dest - 1;
    454           }
    455           #endif
    456