diff --git a/ChangeLog b/ChangeLog index 89c6835a45..92c0c22941 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2001-01-04 H.J. Lu + + * elf/dl-support.c (DL_FIND_AUXV): New. Defined if not defined. + (_dl_clktck): Declared. + (non_dynamic_init): Take 3 arguments. + Set _dl_pagesize, _dl_platform and _dl_clktck from AUX. + +2001-01-01 Bruno Haible + + Finish implementation of plural form handling. + * intl/dcigettext.c (known_translation_t): Rename 'domain' field to + 'domainname'. Remove 'plindex' field. Add 'domain' and + 'translation_length' fields. + (transcmp): Don't compare 'plindex' fields. + (plural_lookup): New function. + (DCIGETTEXT): Change cache handing in the plural case. Don't call + plural_eval before the translation and its catalog file have been + found. Remove plindex from cache key. Add 'translation_length' and + 'domain' to cache result. + (_nl_find_msg): Remove index argument, return length of translation + to the caller instead. Weaken comparison of string lengths, to account + for plural entries. Call iconv() on the entire result string, not + only on the portion needed so far. + * intl/loadinfo.h (_nl_find_msg): Remove index argument, add lengthp + argument. + * intl/loadmsgcat.c (_nl_load_domain): Adapt to _nl_find_msg change. + 2001-01-04 Ulrich Drepper * intl/plural.y (yylex): Minimal improvement in number scanner. diff --git a/elf/dl-support.c b/elf/dl-support.c index 75d7b1926a..6d185c6373 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -1,5 +1,5 @@ /* Support for dynamic linking code in static libc. - Copyright (C) 1996,97,98,99,2000 Free Software Foundation, Inc. + Copyright (C) 1996, 97, 98, 99, 2000, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -107,15 +107,46 @@ int _dl_starting_up = 1; At this time it is not anymore a problem to modify the tables. */ __libc_lock_define_initialized_recursive (, _dl_load_lock) +#ifndef DL_FIND_AUXV +# define DL_FIND_AUXV(auxp, envp) \ + do { \ + void **_tmp; \ + for (_tmp = (void **) (envp); *_tmp; ++_tmp) \ + continue; \ + (auxp) = (void *) ++_tmp; \ + } while (0) +#endif + +extern int _dl_clktck; -static void non_dynamic_init (void) __attribute__ ((unused)); +static void non_dynamic_init (int argc, char **argv, char **envp) + __attribute__ ((unused)); static void -non_dynamic_init (void) +non_dynamic_init (int argc, char **argv, char **envp) { - _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; + ElfW(auxv_t) *av; + + DL_FIND_AUXV (av, envp); - _dl_pagesize = __getpagesize (); + for (; av->a_type != AT_NULL; ++av) + switch (av->a_type) + { + case AT_PAGESZ: + _dl_pagesize = av->a_un.a_val; + break; + case AT_PLATFORM: + _dl_platform = av->a_un.a_ptr; + break; + case AT_CLKTCK: + _dl_clktck = av->a_un.a_val; + break; + } + + if (!_dl_pagesize) + _dl_pagesize = __getpagesize (); + + _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; /* Initialize the data structures for the search paths for shared objects. */ diff --git a/intl/dcigettext.c b/intl/dcigettext.c index 8712e4ba8c..c6540b9ab0 100644 --- a/intl/dcigettext.c +++ b/intl/dcigettext.c @@ -210,10 +210,7 @@ static void *mempcpy PARAMS ((void *dest, const void *src, size_t n)); struct known_translation_t { /* Domain in which to search. */ - char *domain; - - /* Plural index. */ - unsigned long int plindex; + char *domainname; /* The category. */ int category; @@ -221,8 +218,12 @@ struct known_translation_t /* State of the catalog counter at the point the string was found. */ int counter; + /* Catalog where the string was found. */ + struct loaded_l10nfile *domain; + /* And finally the translation. */ const char *translation; + size_t translation_length; /* Pointer to the string in question. */ char msgid[ZERO]; @@ -253,16 +254,12 @@ transcmp (const void *p1, const void *p2) result = strcmp (s1->msgid, s2->msgid); if (result == 0) { - result = strcmp (s1->domain, s2->domain); + result = strcmp (s1->domainname, s2->domainname); if (result == 0) - { - result = s1->plindex - s2->plindex; - if (result == 0) - /* We compare the category last (though this is the cheapest - operation) since it is hopefully always the same (namely - LC_MESSAGES). */ - result = s1->category - s2->category; - } + /* We compare the category last (though this is the cheapest + operation) since it is hopefully always the same (namely + LC_MESSAGES). */ + result = s1->category - s2->category; } return result; @@ -284,8 +281,14 @@ const char _nl_default_dirname[] = GNULOCALEDIR; struct binding *_nl_domain_bindings; /* Prototypes for local functions. */ -static unsigned long int plural_eval (struct expression *pexp, - unsigned long int n) internal_function; +static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain, + unsigned long int n, + const char *translation, + size_t translation_len)) + internal_function; +static unsigned long int plural_eval PARAMS ((struct expression *pexp, + unsigned long int n)) + internal_function; static const char *category_to_name PARAMS ((int category)) internal_function; static const char *guess_category_value PARAMS ((int category, const char *categoryname)) @@ -328,12 +331,17 @@ struct block_list #endif /* have alloca */ +#ifdef _LIBC /* List of blocks allocated for translations. */ -static struct transmem_list +typedef struct transmem_list { struct transmem_list *next; char data[0]; -} *transmem_list; +} transmem_block_t; +static struct transmem_list *transmem_list; +#else +typedef char transmem_block_t; +#endif /* Names for the libintl functions are a problem. They must not clash @@ -389,6 +397,7 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) char *dirname, *xdomainname; char *single_locale; char *retval; + size_t retlen; int saved_errno; #if defined HAVE_TSEARCH || defined _LIBC struct known_translation_t *search; @@ -412,23 +421,26 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) #if defined HAVE_TSEARCH || defined _LIBC msgid_len = strlen (msgid1) + 1; - if (plural == 0) + /* Try to find the translation among those which we found at + some time. */ + search = + (struct known_translation_t *) alloca (sizeof (*search) + msgid_len); + memcpy (search->msgid, msgid1, msgid_len); + search->domainname = (char *) domainname; + search->category = category; + + foundp = (struct known_translation_t **) tfind (search, &root, transcmp); + if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr) { - /* Try to find the translation among those which we found at - some time. */ - search = (struct known_translation_t *) alloca (sizeof (*search) - + msgid_len); - memcpy (search->msgid, msgid1, msgid_len); - search->domain = (char *) domainname; - search->plindex = 0; - search->category = category; - - foundp = (struct known_translation_t **) tfind (search, &root, transcmp); - if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr) - { - __libc_rwlock_unlock (_nl_state_lock); - return (char *) (*foundp)->translation; - } + /* Now deal with plural. */ + if (plural) + retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation, + (*foundp)->translation_length); + else + retval = (char *) (*foundp)->translation; + + __libc_rwlock_unlock (_nl_state_lock); + return retval; } #endif @@ -563,39 +575,7 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) if (domain != NULL) { - unsigned long int index = 0; - - if (plural != 0) - { - const struct loaded_domain *domaindata = - (const struct loaded_domain *) domain->data; - index = plural_eval (domaindata->plural, n); - if (index >= domaindata->nplurals) - /* This should never happen. It means the plural expression - and the given maximum value do not match. */ - index = 0; - -#if defined HAVE_TSEARCH || defined _LIBC - /* Try to find the translation among those which we - found at some time. */ - search = (struct known_translation_t *) alloca (sizeof (*search) - + msgid_len); - memcpy (search->msgid, msgid1, msgid_len); - search->domain = (char *) domainname; - search->plindex = index; - search->category = category; - - foundp = (struct known_translation_t **) tfind (search, &root, - transcmp); - if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr) - { - __libc_rwlock_unlock (_nl_state_lock); - return (char *) (*foundp)->translation; - } -#endif - } - - retval = _nl_find_msg (domain, msgid1, index); + retval = _nl_find_msg (domain, msgid1, &retlen); if (retval == NULL) { @@ -604,15 +584,20 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) for (cnt = 0; domain->successor[cnt] != NULL; ++cnt) { retval = _nl_find_msg (domain->successor[cnt], msgid1, - index); + &retlen); if (retval != NULL) - break; + { + domain = domain->successor[cnt]; + break; + } } } if (retval != NULL) { + /* Found the translation of MSGID1 in domain DOMAIN: + starting at RETVAL, RETLEN bytes. */ FREE_BLOCKS (block_list); __set_errno (saved_errno); #if defined HAVE_TSEARCH || defined _LIBC @@ -626,12 +611,14 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) + domainname_len + 1 - ZERO); if (newp != NULL) { - newp->domain = mempcpy (newp->msgid, msgid1, msgid_len); - memcpy (newp->domain, domainname, domainname_len + 1); - newp->plindex = index; + newp->domainname = + mempcpy (newp->msgid, msgid1, msgid_len); + memcpy (newp->domainname, domainname, domainname_len + 1); newp->category = category; newp->counter = _nl_msg_cat_cntr; + newp->domain = domain; newp->translation = retval; + newp->translation_length = retlen; /* Insert the entry in the search tree. */ foundp = (struct known_translation_t **) @@ -646,9 +633,15 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) { /* We can update the existing entry. */ (*foundp)->counter = _nl_msg_cat_cntr; + (*foundp)->domain = domain; (*foundp)->translation = retval; + (*foundp)->translation_length = retlen; } #endif + /* Now deal with plural. */ + if (plural) + retval = plural_lookup (domain, n, retval, retlen); + __libc_rwlock_unlock (_nl_state_lock); return retval; } @@ -660,14 +653,15 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category) char * internal_function -_nl_find_msg (domain_file, msgid, index) +_nl_find_msg (domain_file, msgid, lengthp) struct loaded_l10nfile *domain_file; const char *msgid; - unsigned long int index; + size_t *lengthp; { const struct loaded_domain *domain; size_t act; char *result; + size_t resultlen; if (domain_file->decided == 0) _nl_load_domain (domain_file); @@ -691,17 +685,21 @@ _nl_find_msg (domain_file, msgid, index) /* Hash table entry is empty. */ return NULL; - if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len - && strcmp (msgid, - domain->data + W (domain->must_swap, - domain->orig_tab[nstr - 1].offset)) == 0) - { - act = nstr - 1; - goto found; - } - while (1) { + /* Compare msgid with the original string at index nstr-1. + We compare the lengths with >=, not ==, because plural entries + are represented by strings with an embedded NUL. */ + if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) >= len + && (strcmp (msgid, + domain->data + W (domain->must_swap, + domain->orig_tab[nstr - 1].offset)) + == 0)) + { + act = nstr - 1; + goto found; + } + if (idx >= domain->hash_size - incr) idx -= domain->hash_size - incr; else @@ -711,16 +709,6 @@ _nl_find_msg (domain_file, msgid, index) if (nstr == 0) /* Hash table entry is empty. */ return NULL; - - if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len - && (strcmp (msgid, - domain->data + W (domain->must_swap, - domain->orig_tab[nstr - 1].offset)) - == 0)) - { - act = nstr - 1; - goto found; - } } /* NOTREACHED */ } @@ -756,6 +744,7 @@ _nl_find_msg (domain_file, msgid, index) string to use a different character set, this is the time. */ result = ((char *) domain->data + W (domain->must_swap, domain->trans_tab[act].offset)); + resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1; #if defined _LIBC || HAVE_ICONV if ( @@ -772,9 +761,10 @@ _nl_find_msg (domain_file, msgid, index) appropriate table with the same structure as the table of translations in the file, where we can put the pointers to the converted strings in. - There is a slight complication with the INDEX: We don't know - a priori which entries are plural entries. Therefore at any - moment we can only translate the variants 0 .. INDEX. */ + There is a slight complication with plural entries. They + are represented by consecutive NUL terminated strings. We + handle this case by converting RESULTLEN bytes, including + NULs. */ if (domain->conv_tab == NULL && ((domain->conv_tab = (char **) calloc (domain->nstrings, @@ -787,8 +777,7 @@ _nl_find_msg (domain_file, msgid, index) /* Nothing we can do, no more memory. */ goto converted; - if (domain->conv_tab[act] == NULL - || *(nls_uint32 *) domain->conv_tab[act] < index) + if (domain->conv_tab[act] == NULL) { /* We haven't used this string so far, so it is not translated yet. Do this now. */ @@ -796,46 +785,37 @@ _nl_find_msg (domain_file, msgid, index) We allocate always larger blocks which get used over time. This is faster than many small allocations. */ __libc_lock_define_initialized (static, lock) -#define INITIAL_BLOCK_SIZE 4080 +# define INITIAL_BLOCK_SIZE 4080 static unsigned char *freemem; static size_t freemem_size; - size_t resultlen; const unsigned char *inbuf; unsigned char *outbuf; int malloc_count; - - /* Note that we translate (index + 1) consecutive strings at - once, including the final NUL byte. */ - { - unsigned long int i = index; - char *p = result; - do - p += strlen (p) + 1; - while (i-- > 0); - resultlen = p - result; - } +# ifndef _LIBC + transmem_block_t *transmem_list = NULL; +# endif __libc_lock_lock (lock); inbuf = result; - outbuf = freemem + sizeof (nls_uint32); + outbuf = freemem + sizeof (size_t); malloc_count = 0; while (1) { + transmem_block_t *newmem; # ifdef _LIBC - struct transmem_list *newmem; size_t non_reversible; int res; - if (freemem_size < 4) + if (freemem_size < sizeof (size_t)) goto resize_freemem; res = __gconv (domain->conv, &inbuf, inbuf + resultlen, &outbuf, - outbuf + freemem_size - sizeof (nls_uint32), + outbuf + freemem_size - sizeof (size_t), &non_reversible); if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT) @@ -850,16 +830,15 @@ _nl_find_msg (domain_file, msgid, index) inbuf = result; # else # if HAVE_ICONV -# define transmem freemem const char *inptr = (const char *) inbuf; size_t inleft = resultlen; char *outptr = (char *) outbuf; size_t outleft; - if (freemem_size < 4) + if (freemem_size < sizeof (size_t)) goto resize_freemem; - outleft = freemem_size - 4; + outleft = freemem_size - sizeof (size_t); if (iconv (domain->conv, &inptr, &inleft, &outptr, &outleft) != (size_t) (-1)) { @@ -871,30 +850,34 @@ _nl_find_msg (domain_file, msgid, index) __libc_lock_unlock (lock); goto converted; } -# else -# define transmem freemem # endif # endif resize_freemem: - /* We must allocate a new buffer of resize the old one. */ + /* We must allocate a new buffer or resize the old one. */ if (malloc_count > 0) { - struct transmem_list *next = transmem_list->next; - ++malloc_count; freemem_size = malloc_count * INITIAL_BLOCK_SIZE; - newmem = (struct transmem_list *) realloc (transmem_list, - freemem_size); - + newmem = (transmem_block_t *) realloc (transmem_list, + freemem_size); +# ifdef _LIBC if (newmem != NULL) - transmem_list = next; + transmem_list = transmem_list->next; + else + { + struct transmem_list *old = transmem_list; + + transmem_list = transmem_list->next; + free (old); + } +# endif } else { malloc_count = 1; freemem_size = INITIAL_BLOCK_SIZE; - newmem = (struct transmem_list *) malloc (freemem_size); + newmem = (transmem_block_t *) malloc (freemem_size); } if (__builtin_expect (newmem == NULL, 0)) { @@ -912,27 +895,31 @@ _nl_find_msg (domain_file, msgid, index) freemem = newmem->data; freemem_size -= offsetof (struct transmem_list, data); +# else + transmem_list = newmem; + freemem = newmem; # endif - outbuf = freemem + sizeof (nls_uint32); + outbuf = freemem + sizeof (size_t); } /* We have now in our buffer a converted string. Put this into the table of conversions. */ - *(nls_uint32 *) freemem = index; + *(size_t *) freemem = outbuf - freemem - sizeof (size_t); domain->conv_tab[act] = freemem; /* Shrink freemem, but keep it aligned. */ freemem_size -= outbuf - freemem; freemem = outbuf; - freemem += freemem_size & (alignof (nls_uint32) - 1); - freemem_size = freemem_size & ~ (alignof (nls_uint32) - 1); + freemem += freemem_size & (alignof (size_t) - 1); + freemem_size = freemem_size & ~ (alignof (size_t) - 1); __libc_lock_unlock (lock); } - /* Now domain->conv_tab[act] contains the translation of at least - the variants 0 .. INDEX. */ - result = domain->conv_tab[act] + sizeof (nls_uint32); + /* Now domain->conv_tab[act] contains the translation of all + the plural variants. */ + result = domain->conv_tab[act] + sizeof (size_t); + resultlen = *(size_t *) domain->conv_tab[act]; } converted: @@ -940,26 +927,58 @@ _nl_find_msg (domain_file, msgid, index) #endif /* _LIBC || HAVE_ICONV */ - /* Now skip some strings. How much depends on the index passed in. */ + *lengthp = resultlen; + return result; +} + + +/* Look up a plural variant. */ +static char * +internal_function +plural_lookup (domain, n, translation, translation_len) + struct loaded_l10nfile *domain; + unsigned long int n; + const char *translation; + size_t translation_len; +{ + struct loaded_domain *domaindata = (struct loaded_domain *) domain->data; + unsigned long int index; + const char *p; + + index = plural_eval (domaindata->plural, n); + if (index >= domaindata->nplurals) + /* This should never happen. It means the plural expression and the + given maximum value do not match. */ + index = 0; + + /* Skip INDEX strings at TRANSLATION. */ + p = translation; while (index-- > 0) { #ifdef _LIBC - result = __rawmemchr (result, '\0'); + p = __rawmemchr (p, '\0'); #else - result = strchr (result, '\0'); + p = strchr (p, '\0'); #endif /* And skip over the NUL byte. */ - ++result; - } + p++; - return result; + if (p >= translation + translation_len) + /* This should never happen. It means the plural expression + evaluated to a value larger than the number of variants + available for MSGID1. */ + return (char *) translation; + } + return (char *) p; } /* Function to evaluate the plural expression and return an index value. */ static unsigned long int internal_function -plural_eval (struct expression *pexp, unsigned long int n) +plural_eval (pexp, n) + struct expression *pexp; + unsigned long int n; { switch (pexp->operation) { diff --git a/intl/loadinfo.h b/intl/loadinfo.h index 1013470f43..a48433e4e9 100644 --- a/intl/loadinfo.h +++ b/intl/loadinfo.h @@ -101,7 +101,7 @@ extern char *_nl_find_language PARAMS ((const char *name)); extern char *_nl_find_msg PARAMS ((struct loaded_l10nfile *domain_file, - const char *msgid, unsigned long int index)) + const char *msgid, size_t *lengthp)) internal_function; #endif /* loadinfo.h */ diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c index 4e792d20cb..40d1ce673a 100644 --- a/intl/loadmsgcat.c +++ b/intl/loadmsgcat.c @@ -1,5 +1,5 @@ /* Load needed message catalogs. - Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -107,14 +107,15 @@ static struct expression germanic_plural = .operation = not_equal, .val = { - .args2 = { + .args2 = + { .left = (struct expression *) &plvar, .right = (struct expression *) &plone } } }; -#define INIT_GERMANIC_PLURAL() +# define INIT_GERMANIC_PLURAL() #else @@ -141,7 +142,7 @@ init_germanic_plural () } } -#define INIT_GERMANIC_PLURAL() init_germanic_plural () +# define INIT_GERMANIC_PLURAL() init_germanic_plural () #endif @@ -160,6 +161,7 @@ _nl_load_domain (domain_file) int use_mmap = 0; struct loaded_domain *domain; char *nullentry; + size_t nullentrylen; domain_file->decided = 1; domain_file->data = NULL; @@ -297,7 +299,7 @@ _nl_load_domain (domain_file) # endif #endif domain->conv_tab = NULL; - nullentry = _nl_find_msg (domain_file, "", 0); + nullentry = _nl_find_msg (domain_file, "", &nullentrylen); if (nullentry != NULL) { #if defined _LIBC || HAVE_ICONV