Annotation of embedaddon/lrzsz/intl/l10nflist.c, revision 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>