Annotation of embedaddon/lrzsz/intl/l10nflist.c, revision 1.1.1.1

1.1       misho       1: /* Handle list of needed message catalogs
                      2:    Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
                      3:    Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
                      4: 
                      5:    This program is free software; you can redistribute it and/or modify
                      6:    it under the terms of the GNU General Public License as published by
                      7:    the Free Software Foundation; either version 2, or (at your option)
                      8:    any later version.
                      9: 
                     10:    This program 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
                     13:    GNU General Public License for more details.
                     14: 
                     15:    You should have received a copy of the GNU General Public License
                     16:    along with this program; if not, write to the Free Software Foundation,
                     17:    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
                     18: 
                     19: #ifdef HAVE_CONFIG_H
                     20: # include <config.h>
                     21: #endif
                     22: 
                     23: 
                     24: #if defined HAVE_STRING_H || defined _LIBC
                     25: # ifndef _GNU_SOURCE
                     26: #  define _GNU_SOURCE  1
                     27: # endif
                     28: # include <string.h>
                     29: #else
                     30: # include <strings.h>
                     31: # ifndef memcpy
                     32: #  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
                     33: # endif
                     34: #endif
                     35: #if !HAVE_STRCHR && !defined _LIBC
                     36: # ifndef strchr
                     37: #  define strchr index
                     38: # endif
                     39: #endif
                     40: 
                     41: #if defined _LIBC || defined HAVE_ARGZ_H
                     42: # include <argz.h>
                     43: #endif
                     44: #include <ctype.h>
                     45: #include <sys/types.h>
                     46: 
                     47: #if defined STDC_HEADERS || defined _LIBC
                     48: # include <stdlib.h>
                     49: #endif
                     50: 
                     51: #include "loadinfo.h"
                     52: 
                     53: /* On some strange systems still no definition of NULL is found.  Sigh!  */
                     54: #ifndef NULL
                     55: # if defined __STDC__ && __STDC__
                     56: #  define NULL ((void *) 0)
                     57: # else
                     58: #  define NULL 0
                     59: # endif
                     60: #endif
                     61: 
                     62: /* @@ end of prolog @@ */
                     63: 
                     64: #ifdef _LIBC
                     65: /* Rename the non ANSI C functions.  This is required by the standard
                     66:    because some ANSI C functions will require linking with this object
                     67:    file and the name space must not be polluted.  */
                     68: # define stpcpy(dest, src) __stpcpy(dest, src)
                     69: #else
                     70: # ifndef HAVE_STPCPY
                     71: static char *stpcpy PARAMS ((char *dest, const char *src));
                     72: # endif
                     73: #endif
                     74: 
                     75: /* Define function which are usually not available.  */
                     76: 
                     77: #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
                     78: /* Returns the number of strings in ARGZ.  */
                     79: static size_t argz_count__ PARAMS ((const char *argz, size_t len));
                     80: 
                     81: static size_t
                     82: argz_count__ (argz, len)
                     83:      const char *argz;
                     84:      size_t len;
                     85: {
                     86:   size_t count = 0;
                     87:   while (len > 0)
                     88:     {
                     89:       size_t part_len = strlen (argz);
                     90:       argz += part_len + 1;
                     91:       len -= part_len + 1;
                     92:       count++;
                     93:     }
                     94:   return count;
                     95: }
                     96: # undef __argz_count
                     97: # define __argz_count(argz, len) argz_count__ (argz, len)
                     98: #endif /* !_LIBC && !HAVE___ARGZ_COUNT */
                     99: 
                    100: #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
                    101: /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
                    102:    except the last into the character SEP.  */
                    103: static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
                    104: 
                    105: static void
                    106: argz_stringify__ (argz, len, sep)
                    107:      char *argz;
                    108:      size_t len;
                    109:      int sep;
                    110: {
                    111:   while (len > 0)
                    112:     {
                    113:       size_t part_len = strlen (argz);
                    114:       argz += part_len;
                    115:       len -= part_len + 1;
                    116:       if (len > 0)
                    117:        *argz++ = sep;
                    118:     }
                    119: }
                    120: # undef __argz_stringify
                    121: # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
                    122: #endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
                    123: 
                    124: #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
                    125: static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
                    126:                                  const char *entry));
                    127: 
                    128: static char *
                    129: argz_next__ (argz, argz_len, entry)
                    130:      char *argz;
                    131:      size_t argz_len;
                    132:      const char *entry;
                    133: {
                    134:   if (entry)
                    135:     {
                    136:       if (entry < argz + argz_len)
                    137:         entry = strchr (entry, '\0') + 1;
                    138: 
                    139:       return entry >= argz + argz_len ? NULL : (char *) entry;
                    140:     }
                    141:   else
                    142:     if (argz_len > 0)
                    143:       return argz;
                    144:     else
                    145:       return 0;
                    146: }
                    147: # undef __argz_next
                    148: # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
                    149: #endif /* !_LIBC && !HAVE___ARGZ_NEXT */
                    150: 
                    151: 
                    152: /* Return number of bits set in X.  */
                    153: static int pop PARAMS ((int x));
                    154: 
                    155: static inline int
                    156: pop (x)
                    157:      int x;
                    158: {
                    159:   /* We assume that no more than 16 bits are used.  */
                    160:   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
                    161:   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
                    162:   x = ((x >> 4) + x) & 0x0f0f;
                    163:   x = ((x >> 8) + x) & 0xff;
                    164: 
                    165:   return x;
                    166: }
                    167: 
                    168: 
                    169: struct loaded_l10nfile *
                    170: _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
                    171:                    territory, codeset, normalized_codeset, modifier, special,
                    172:                    sponsor, revision, filename, do_allocate)
                    173:      struct loaded_l10nfile **l10nfile_list;
                    174:      const char *dirlist;
                    175:      size_t dirlist_len;
                    176:      int mask;
                    177:      const char *language;
                    178:      const char *territory;
                    179:      const char *codeset;
                    180:      const char *normalized_codeset;
                    181:      const char *modifier;
                    182:      const char *special;
                    183:      const char *sponsor;
                    184:      const char *revision;
                    185:      const char *filename;
                    186:      int do_allocate;
                    187: {
                    188:   char *abs_filename;
                    189:   struct loaded_l10nfile *last = NULL;
                    190:   struct loaded_l10nfile *retval;
                    191:   char *cp;
                    192:   size_t entries;
                    193:   int cnt;
                    194: 
                    195:   /* Allocate room for the full file name.  */
                    196:   abs_filename = (char *) malloc (dirlist_len
                    197:                                  + strlen (language)
                    198:                                  + ((mask & TERRITORY) != 0
                    199:                                     ? strlen (territory) + 1 : 0)
                    200:                                  + ((mask & XPG_CODESET) != 0
                    201:                                     ? strlen (codeset) + 1 : 0)
                    202:                                  + ((mask & XPG_NORM_CODESET) != 0
                    203:                                     ? strlen (normalized_codeset) + 1 : 0)
                    204:                                  + (((mask & XPG_MODIFIER) != 0
                    205:                                      || (mask & CEN_AUDIENCE) != 0)
                    206:                                     ? strlen (modifier) + 1 : 0)
                    207:                                  + ((mask & CEN_SPECIAL) != 0
                    208:                                     ? strlen (special) + 1 : 0)
                    209:                                  + (((mask & CEN_SPONSOR) != 0
                    210:                                      || (mask & CEN_REVISION) != 0)
                    211:                                     ? (1 + ((mask & CEN_SPONSOR) != 0
                    212:                                             ? strlen (sponsor) + 1 : 0)
                    213:                                        + ((mask & CEN_REVISION) != 0
                    214:                                           ? strlen (revision) + 1 : 0)) : 0)
                    215:                                  + 1 + strlen (filename) + 1);
                    216: 
                    217:   if (abs_filename == NULL)
                    218:     return NULL;
                    219: 
                    220:   retval = NULL;
                    221:   last = NULL;
                    222: 
                    223:   /* Construct file name.  */
                    224:   memcpy (abs_filename, dirlist, dirlist_len);
                    225:   __argz_stringify (abs_filename, dirlist_len, ':');
                    226:   cp = abs_filename + (dirlist_len - 1);
                    227:   *cp++ = '/';
                    228:   cp = stpcpy (cp, language);
                    229: 
                    230:   if ((mask & TERRITORY) != 0)
                    231:     {
                    232:       *cp++ = '_';
                    233:       cp = stpcpy (cp, territory);
                    234:     }
                    235:   if ((mask & XPG_CODESET) != 0)
                    236:     {
                    237:       *cp++ = '.';
                    238:       cp = stpcpy (cp, codeset);
                    239:     }
                    240:   if ((mask & XPG_NORM_CODESET) != 0)
                    241:     {
                    242:       *cp++ = '.';
                    243:       cp = stpcpy (cp, normalized_codeset);
                    244:     }
                    245:   if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
                    246:     {
                    247:       /* This component can be part of both syntaces but has different
                    248:         leading characters.  For CEN we use `+', else `@'.  */
                    249:       *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
                    250:       cp = stpcpy (cp, modifier);
                    251:     }
                    252:   if ((mask & CEN_SPECIAL) != 0)
                    253:     {
                    254:       *cp++ = '+';
                    255:       cp = stpcpy (cp, special);
                    256:     }
                    257:   if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
                    258:     {
                    259:       *cp++ = ',';
                    260:       if ((mask & CEN_SPONSOR) != 0)
                    261:        cp = stpcpy (cp, sponsor);
                    262:       if ((mask & CEN_REVISION) != 0)
                    263:        {
                    264:          *cp++ = '_';
                    265:          cp = stpcpy (cp, revision);
                    266:        }
                    267:     }
                    268: 
                    269:   *cp++ = '/';
                    270:   stpcpy (cp, filename);
                    271: 
                    272:   /* Look in list of already loaded domains whether it is already
                    273:      available.  */
                    274:   last = NULL;
                    275:   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
                    276:     if (retval->filename != NULL)
                    277:       {
                    278:        int compare = strcmp (retval->filename, abs_filename);
                    279:        if (compare == 0)
                    280:          /* We found it!  */
                    281:          break;
                    282:        if (compare < 0)
                    283:          {
                    284:            /* It's not in the list.  */
                    285:            retval = NULL;
                    286:            break;
                    287:          }
                    288: 
                    289:        last = retval;
                    290:       }
                    291: 
                    292:   if (retval != NULL || do_allocate == 0)
                    293:     {
                    294:       free (abs_filename);
                    295:       return retval;
                    296:     }
                    297: 
                    298:   retval = (struct loaded_l10nfile *)
                    299:     malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
                    300:                                * (1 << pop (mask))
                    301:                                * sizeof (struct loaded_l10nfile *)));
                    302:   if (retval == NULL)
                    303:     return NULL;
                    304: 
                    305:   retval->filename = abs_filename;
                    306:   retval->decided = (__argz_count (dirlist, dirlist_len) != 1
                    307:                     || ((mask & XPG_CODESET) != 0
                    308:                         && (mask & XPG_NORM_CODESET) != 0));
                    309:   retval->data = NULL;
                    310: 
                    311:   if (last == NULL)
                    312:     {
                    313:       retval->next = *l10nfile_list;
                    314:       *l10nfile_list = retval;
                    315:     }
                    316:   else
                    317:     {
                    318:       retval->next = last->next;
                    319:       last->next = retval;
                    320:     }
                    321: 
                    322:   entries = 0;
                    323:   /* If the DIRLIST is a real list the RETVAL entry corresponds not to
                    324:      a real file.  So we have to use the DIRLIST separation mechanism
                    325:      of the inner loop.  */
                    326:   cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
                    327:   for (; cnt >= 0; --cnt)
                    328:     if ((cnt & ~mask) == 0
                    329:        && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
                    330:        && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
                    331:       {
                    332:        /* Iterate over all elements of the DIRLIST.  */
                    333:        char *dir = NULL;
                    334: 
                    335:        while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
                    336:               != NULL)
                    337:          retval->successor[entries++]
                    338:            = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
                    339:                                  language, territory, codeset,
                    340:                                  normalized_codeset, modifier, special,
                    341:                                  sponsor, revision, filename, 1);
                    342:       }
                    343:   retval->successor[entries] = NULL;
                    344: 
                    345:   return retval;
                    346: }
                    347: 
                    348: /* Normalize codeset name.  There is no standard for the codeset
                    349:    names.  Normalization allows the user to use any of the common
                    350:    names.  */
                    351: const char *
                    352: _nl_normalize_codeset (codeset, name_len)
                    353:      const char *codeset;
                    354:      size_t name_len;
                    355: {
                    356:   int len = 0;
                    357:   int only_digit = 1;
                    358:   char *retval;
                    359:   char *wp;
                    360:   size_t cnt;
                    361: 
                    362:   for (cnt = 0; cnt < name_len; ++cnt)
                    363:     if (isalnum (codeset[cnt]))
                    364:       {
                    365:        ++len;
                    366: 
                    367:        if (isalpha (codeset[cnt]))
                    368:          only_digit = 0;
                    369:       }
                    370: 
                    371:   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
                    372: 
                    373:   if (retval != NULL)
                    374:     {
                    375:       if (only_digit)
                    376:        wp = stpcpy (retval, "iso");
                    377:       else
                    378:        wp = retval;
                    379: 
                    380:       for (cnt = 0; cnt < name_len; ++cnt)
                    381:        if (isalpha (codeset[cnt]))
                    382:          *wp++ = tolower (codeset[cnt]);
                    383:        else if (isdigit (codeset[cnt]))
                    384:          *wp++ = codeset[cnt];
                    385: 
                    386:       *wp = '\0';
                    387:     }
                    388: 
                    389:   return (const char *) retval;
                    390: }
                    391: 
                    392: 
                    393: /* @@ begin of epilog @@ */
                    394: 
                    395: /* We don't want libintl.a to depend on any other library.  So we
                    396:    avoid the non-standard function stpcpy.  In GNU C Library this
                    397:    function is available, though.  Also allow the symbol HAVE_STPCPY
                    398:    to be defined.  */
                    399: #if !_LIBC && !HAVE_STPCPY
                    400: static char *
                    401: stpcpy (dest, src)
                    402:      char *dest;
                    403:      const char *src;
                    404: {
                    405:   while ((*dest++ = *src++) != '\0')
                    406:     /* Do nothing. */ ;
                    407:   return dest - 1;
                    408: }
                    409: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>