From: Bruno Haible Date: Fri, 14 Jun 2002 12:03:49 +0000 (+0000) Subject: Make absolute pathnames inside $LANGUAGE work. X-Git-Tag: v0.11.3~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=279b57fc367251666f00e8e2b599b83703451afb;p=thirdparty%2Fgettext.git Make absolute pathnames inside $LANGUAGE work. --- diff --git a/intl/ChangeLog b/intl/ChangeLog index be0ba2809..0a39222a5 100644 --- a/intl/ChangeLog +++ b/intl/ChangeLog @@ -1,3 +1,10 @@ +2002-06-13 Bruno Haible + + Make absolute pathnames inside $LANGUAGE work. + * l10nflist.c (_nl_make_l10nflist): Ignore dirlist if language is an + absolute path. Fix sizes passed to malloc. Simplify linked list + handling. + 2002-06-13 Bruno Haible * localename.c [WIN32] (LANG_DIVEHI, LANG_GALICIAN, LANG_KYRGYZ, diff --git a/intl/l10nflist.c b/intl/l10nflist.c index d861912df..ec8713f8e 100644 --- a/intl/l10nflist.c +++ b/intl/l10nflist.c @@ -62,6 +62,24 @@ static char *stpcpy PARAMS ((char *dest, const char *src)); # endif #endif +/* Pathname support. + ISSLASH(C) tests whether C is a directory separator character. + IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not, + it may be concatenated to a directory pathname. + */ +#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__ + /* Win32, OS/2, DOS */ +# define ISSLASH(C) ((C) == '/' || (C) == '\\') +# define HAS_DEVICE(P) \ + ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ + && (P)[1] == ':') +# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P)) +#else + /* Unix */ +# define ISSLASH(C) ((C) == '/') +# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0]) +#endif + /* Define function which are usually not available. */ #if !defined _LIBC && !defined HAVE___ARGZ_COUNT @@ -185,12 +203,18 @@ _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, int do_allocate; { char *abs_filename; - struct loaded_l10nfile *last = NULL; + struct loaded_l10nfile **lastp; struct loaded_l10nfile *retval; char *cp; + size_t dirlist_count; size_t entries; int cnt; + /* If LANGUAGE contains an absolute directory specification, we ignore + DIRLIST. */ + if (IS_ABSOLUTE_PATH (language)) + dirlist_len = 0; + /* Allocate room for the full file name. */ abs_filename = (char *) malloc (dirlist_len + strlen (language) @@ -208,7 +232,7 @@ _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, + (((mask & CEN_SPONSOR) != 0 || (mask & CEN_REVISION) != 0) ? (1 + ((mask & CEN_SPONSOR) != 0 - ? strlen (sponsor) + 1 : 0) + ? strlen (sponsor) : 0) + ((mask & CEN_REVISION) != 0 ? strlen (revision) + 1 : 0)) : 0) + 1 + strlen (filename) + 1); @@ -216,14 +240,16 @@ _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, if (abs_filename == NULL) return NULL; - retval = NULL; - last = NULL; - /* Construct file name. */ - memcpy (abs_filename, dirlist, dirlist_len); - __argz_stringify (abs_filename, dirlist_len, PATH_SEPARATOR); - cp = abs_filename + (dirlist_len - 1); - *cp++ = '/'; + cp = abs_filename; + if (dirlist_len > 0) + { + memcpy (cp, dirlist, dirlist_len); + __argz_stringify (cp, dirlist_len, PATH_SEPARATOR); + cp += dirlist_len; + cp[-1] = '/'; + } + cp = stpcpy (cp, language); if ((mask & TERRITORY) != 0) @@ -270,7 +296,7 @@ _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, /* Look in list of already loaded domains whether it is already available. */ - last = NULL; + lastp = l10nfile_list; for (retval = *l10nfile_list; retval != NULL; retval = retval->next) if (retval->filename != NULL) { @@ -285,7 +311,7 @@ _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, break; } - last = retval; + lastp = &retval->next; } if (retval != NULL || do_allocate == 0) @@ -294,48 +320,66 @@ _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language, return retval; } - retval = (struct loaded_l10nfile *) - malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len) - * (1 << pop (mask)) - * sizeof (struct loaded_l10nfile *))); + dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1); + + /* Allocate a new loaded_l10nfile. */ + retval = + (struct loaded_l10nfile *) + malloc (sizeof (*retval) + + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0)) + * sizeof (struct loaded_l10nfile *))); if (retval == NULL) return NULL; retval->filename = abs_filename; - retval->decided = (__argz_count (dirlist, dirlist_len) != 1 + + /* We set retval->data to NULL here; it is filled in later. + Setting retval->decided to 1 here means that retval does not + correspond to a real file (dirlist_count > 1) or is not worth + looking up (if an unnormalized codeset was specified). */ + retval->decided = (dirlist_count > 1 || ((mask & XPG_CODESET) != 0 && (mask & XPG_NORM_CODESET) != 0)); retval->data = NULL; - if (last == NULL) - { - retval->next = *l10nfile_list; - *l10nfile_list = retval; - } - else - { - retval->next = last->next; - last->next = retval; - } + retval->next = *lastp; + *lastp = retval; entries = 0; - /* If the DIRLIST is a real list the RETVAL entry corresponds not to - a real file. So we have to use the DIRLIST separation mechanism - of the inner loop. */ - cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask; - for (; cnt >= 0; --cnt) + /* Recurse to fill the inheritance list of RETVAL. + If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL + entry does not correspond to a real file; retval->filename contains + colons. In this case we loop across all elements of DIRLIST and + across all bit patterns dominated by MASK. + If the DIRLIST is a single directory or entirely redundant (i.e. + DIRLIST_COUNT == 1), we loop across all bit patterns dominated by + MASK, excluding MASK itself. + In either case, we loop down from MASK to 0. This has the effect + that the extra bits in the locale name are dropped in this order: + first the modifier, then the territory, then the codeset, then the + normalized_codeset. */ + for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt) if ((cnt & ~mask) == 0 && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0) && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0)) { - /* Iterate over all elements of the DIRLIST. */ - char *dir = NULL; - - while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir)) - != NULL) + if (dirlist_count > 1) + { + /* Iterate over all elements of the DIRLIST. */ + char *dir = NULL; + + while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir)) + != NULL) + retval->successor[entries++] + = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, + cnt, language, territory, codeset, + normalized_codeset, modifier, special, + sponsor, revision, filename, 1); + } + else retval->successor[entries++] - = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt, - language, territory, codeset, + = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, + cnt, language, territory, codeset, normalized_codeset, modifier, special, sponsor, revision, filename, 1); } diff --git a/intl/loadinfo.h b/intl/loadinfo.h index d180962f5..1d3ba6162 100644 --- a/intl/loadinfo.h +++ b/intl/loadinfo.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999, 2000, 2001 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999, 2000-2002 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1996. @@ -92,6 +92,20 @@ struct loaded_l10nfile extern const char *_nl_normalize_codeset PARAMS ((const char *codeset, size_t name_len)); +/* Lookup a locale dependent file. + *L10NFILE_LIST denotes a pool of lookup results of locale dependent + files of the same kind, sorted in decreasing order of ->filename. + DIRLIST and DIRLIST_LEN are an argz list of directories in which to + look, containing at least one directory (i.e. DIRLIST_LEN > 0). + MASK, LANGUAGE, TERRITORY, CODESET, NORMALIZED_CODESET, MODIFIER, + SPECIAL, SPONSOR, REVISION are the pieces of the locale name, as + produced by _nl_explode_name(). FILENAME is the filename suffix. + The return value is the lookup result, either found in *L10NFILE_LIST, + or - if DO_ALLOCATE is nonzero - freshly allocated, or possibly NULL. + If the return value is non-NULL, it is added to *L10NFILE_LIST, and + its ->next field denotes the chaining inside *L10NFILE_LIST, and + furthermore its ->successor[] field contains a list of other lookup + results from which this lookup result inherits. */ extern struct loaded_l10nfile * _nl_make_l10nflist PARAMS ((struct loaded_l10nfile **l10nfile_list, const char *dirlist, size_t dirlist_len, int mask, @@ -102,11 +116,29 @@ _nl_make_l10nflist PARAMS ((struct loaded_l10nfile **l10nfile_list, const char *sponsor, const char *revision, const char *filename, int do_allocate)); - +/* Lookup the real locale name for a locale alias NAME, or NULL if + NAME is not a locale alias (but possibly a real locale name). + The return value is statically allocated and must not be freed. */ extern const char *_nl_expand_alias PARAMS ((const char *name)); -/* normalized_codeset is dynamically allocated and has to be freed by - the caller. */ +/* Split a locale name NAME into its pieces: language, modifier, + territory, codeset, special, sponsor, revision. + NAME gets destructively modified: NUL bytes are inserted here and + there. *LANGUAGE gets assigned NAME. Each of *MODIFIER, *TERRITORY, + *CODESET, *SPECIAL, *SPONSOR, *REVISION gets assigned either a + pointer into the old NAME string, or NULL. *NORMALIZED_CODESET + gets assigned the expanded *CODESET, if it is different from *CODESET; + this one is dynamically allocated and has to be freed by the caller. + The return value is a bitmask, where each bit corresponds to one + filled-in value: + XPG_MODIFIER, CEN_AUDIENCE for *MODIFIER, + TERRITORY for *TERRITORY, + XPG_CODESET for *CODESET, + XPG_NORM_CODESET for *NORMALIZED_CODESET, + CEN_SPECIAL for *SPECIAL, + CEN_SPONSOR for *SPONSOR, + CEN_REVISION for *REVISION. + */ extern int _nl_explode_name PARAMS ((char *name, const char **language, const char **modifier, const char **territory, @@ -116,6 +148,9 @@ extern int _nl_explode_name PARAMS ((char *name, const char **language, const char **sponsor, const char **revision)); +/* Split a locale name NAME into a leading language part and all the + rest. Return a pointer to the first character after the language, + i.e. to the first byte of the rest. */ extern char *_nl_find_language PARAMS ((const char *name)); #endif /* loadinfo.h */