* locale/loadarchive.c (_nl_load_locale_from_archive): Parse locale

name to find codeset name (if any) and normalize it.  If the
	normalized name differs, look up only that in the archive.
	* locale/programs/locarchive.c (add_locale_to_archive): If the name
	contains a codeset, normalize the codeset store only the normalized
	name in the archive.  If not, add an alias containing the locale's
	normalized codeset name.  Apply codeset name normalization when
	matching entries in the alias file.

	* locale/programs/locarchive.c (delete_locales_from_archive): Don't
	decrement HEAD->namehash_used here.
	(add_locale): Only need to insert name string when name_offset != 0.

	* locale/programs/localedef.c (options): Add -A/--alias-file.
	(alias_file): New variable.
	(parse_opt): Grok -A, set that.
	* locale/programs/localedef.h: Declare it.

	* locale/programs/locarchive.c (insert_name): New function, broken out
	of ...
	(add_locale_to_archive): ... here.  Call that.
	(add_alias): New function.
	(add_locale): New static function, add_locale_to_archive renamed.
	(add_locale_to_archive): Call that and use add_alias to add an alias
	for the name with codeset if the given name lacks it.
	(enlarge_archive): Call add_locale instead of add_locale_to_archive.

	* locale/Makefile (routines): Add loadarchive.
	* locale/loadarchive.c: New file, started from code by Ulrich Drepper.
	(_nl_load_locale_from_archive): New function.
	* locale/localeinfo.h: Declare it.
	* locale/findlocale.c (_nl_find_locale): If using default locale path,
	try _nl_load_locale_from_archive first.

	* locale/loadlocale.c (_nl_intern_locale_data): New function,
	broken out of _nl_load_locale.
	(_nl_load_locale): Call that.
	* locale/localeinfo.h: Declare it.
	(struct locale_data): Replace member `mmaped' with `alloc', an enum.
	(struct locale_data): Remove unused member `options'.
	* locale/findlocale.c (_nl_remove_locale): Update uses.
	* locale/loadlocale.c (_nl_load_locale, _nl_unload_locale): Likewise.
	* locale/C-collate.c: Update initializer.
	* locale/C-identification.c: Likewise.
	* locale/C-measurement.c: Likewise.
	* locale/C-telephone.c: Likewise.
	* locale/C-address.c: Likewise.
	* locale/C-name.c: Likewise.
	* locale/C-paper.c: Likewise.
	* locale/C-time.c: Likewise.
	* locale/C-numeric.c: Likewise.
	* locale/C-monetary.c: Likewise.
	* locale/C-messages.c : Likewise.
	* locale/C-ctype.c: Likewise.

	* locale/hashval.h [! LONGBITS]: Include <limits.h> here and
	use CHAR_BIT instead of BITSPERBYTE.

	* locale/localeinfo.h (_nl_find_locale, _nl_load_locale,
	_nl_unload_locale): Add `internal_function attribute_hidden' to decls.
	* locale/findlocale.c (_nl_find_locale): Add internal_function to defn.
	(_nl_remove_locale): Likewise.
	* locale/loadlocale.c (_nl_load_locale, _nl_unload_locale): Likewise.

	* locale/findlocale.c (_nl_default_locale_path): New variable.
	(_nl_find_locale): If LOCALE_PATH is null, default to that.
	* locale/localeinfo.h: Declare it.
	* locale/setlocale.c (setlocale): Use _nl_default_locale_path
	in place of LOCALEDIR.  If no LOCPATH, pass null to _nl_find_locale.
	* locale/newlocale.c (__newlocale): Likewise.

	* misc/err.c (vwarnx, vwarn): Fix typos in libc_hidden_def uses.
	* inet/rexec.c (rexec_af): Add libc_hidden_def.
	* sysdeps/generic/morecore.c: Likewise.
	* signal/allocrtsig.c (__libc_current_sigrtmin): Likewise.
	(__libc_current_sigrtmax): Likewise.

2002-08-08  Roland McGrath  <roland@redhat.com>

	* locale/loadlocale.c (_nl_load_locale): Don't use MAP_INHERIT.
	* catgets/open_catalog.c (__open_catalog): Likewise.

	* locale/programs/locarchive.c (INITIAL_NUM_NAMES): Renamed
	from typo INITIAL_NUM_NANES.
	(create_archive): Update use.
This commit is contained in:
Roland McGrath 2002-08-10 06:22:37 +00:00
parent 946860b1cb
commit cb09a2cda2
28 changed files with 1085 additions and 198 deletions

View File

@ -1,3 +1,91 @@
2002-08-09 Roland McGrath <roland@redhat.com>
* locale/loadarchive.c (_nl_load_locale_from_archive): Parse locale
name to find codeset name (if any) and normalize it. If the
normalized name differs, look up only that in the archive.
* locale/programs/locarchive.c (add_locale_to_archive): If the name
contains a codeset, normalize the codeset store only the normalized
name in the archive. If not, add an alias containing the locale's
normalized codeset name. Apply codeset name normalization when
matching entries in the alias file.
* locale/programs/locarchive.c (delete_locales_from_archive): Don't
decrement HEAD->namehash_used here.
(add_locale): Only need to insert name string when name_offset != 0.
* locale/programs/localedef.c (options): Add -A/--alias-file.
(alias_file): New variable.
(parse_opt): Grok -A, set that.
* locale/programs/localedef.h: Declare it.
* locale/programs/locarchive.c (insert_name): New function, broken out
of ...
(add_locale_to_archive): ... here. Call that.
(add_alias): New function.
(add_locale): New static function, add_locale_to_archive renamed.
(add_locale_to_archive): Call that and use add_alias to add an alias
for the name with codeset if the given name lacks it.
(enlarge_archive): Call add_locale instead of add_locale_to_archive.
* locale/Makefile (routines): Add loadarchive.
* locale/loadarchive.c: New file, started from code by Ulrich Drepper.
(_nl_load_locale_from_archive): New function.
* locale/localeinfo.h: Declare it.
* locale/findlocale.c (_nl_find_locale): If using default locale path,
try _nl_load_locale_from_archive first.
* locale/loadlocale.c (_nl_intern_locale_data): New function,
broken out of _nl_load_locale.
(_nl_load_locale): Call that.
* locale/localeinfo.h: Declare it.
(struct locale_data): Replace member `mmaped' with `alloc', an enum.
(struct locale_data): Remove unused member `options'.
* locale/findlocale.c (_nl_remove_locale): Update uses.
* locale/loadlocale.c (_nl_load_locale, _nl_unload_locale): Likewise.
* locale/C-collate.c: Update initializer.
* locale/C-identification.c: Likewise.
* locale/C-measurement.c: Likewise.
* locale/C-telephone.c: Likewise.
* locale/C-address.c: Likewise.
* locale/C-name.c: Likewise.
* locale/C-paper.c: Likewise.
* locale/C-time.c: Likewise.
* locale/C-numeric.c: Likewise.
* locale/C-monetary.c: Likewise.
* locale/C-messages.c : Likewise.
* locale/C-ctype.c: Likewise.
* locale/hashval.h [! LONGBITS]: Include <limits.h> here and
use CHAR_BIT instead of BITSPERBYTE.
* locale/localeinfo.h (_nl_find_locale, _nl_load_locale,
_nl_unload_locale): Add `internal_function attribute_hidden' to decls.
* locale/findlocale.c (_nl_find_locale): Add internal_function to defn.
(_nl_remove_locale): Likewise.
* locale/loadlocale.c (_nl_load_locale, _nl_unload_locale): Likewise.
* locale/findlocale.c (_nl_default_locale_path): New variable.
(_nl_find_locale): If LOCALE_PATH is null, default to that.
* locale/localeinfo.h: Declare it.
* locale/setlocale.c (setlocale): Use _nl_default_locale_path
in place of LOCALEDIR. If no LOCPATH, pass null to _nl_find_locale.
* locale/newlocale.c (__newlocale): Likewise.
* misc/err.c (vwarnx, vwarn): Fix typos in libc_hidden_def uses.
* inet/rexec.c (rexec_af): Add libc_hidden_def.
* sysdeps/generic/morecore.c: Likewise.
* signal/allocrtsig.c (__libc_current_sigrtmin): Likewise.
(__libc_current_sigrtmax): Likewise.
2002-08-08 Roland McGrath <roland@redhat.com>
* locale/loadlocale.c (_nl_load_locale): Don't use MAP_INHERIT.
* catgets/open_catalog.c (__open_catalog): Likewise.
* locale/programs/locarchive.c (INITIAL_NUM_NAMES): Renamed
from typo INITIAL_NUM_NANES.
(create_archive): Update use.
2002-08-08 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/sigwait.c: New file.

View File

@ -177,6 +177,7 @@ bad:
freeaddrinfo(res0);
return (-1);
}
libc_hidden_def (rexec_af)
int
rexec(ahost, rport, name, pass, cmd, fd2p)

View File

@ -30,7 +30,6 @@ const struct locale_data _nl_C_LC_ADDRESS attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
13,
{
{ string: "%a%N%f%N%d%N%b%N%s %h %e %r%N%C-%z %T%N%c%N" },

View File

@ -104,7 +104,6 @@ const struct locale_data _nl_C_LC_COLLATE attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
19,
{
/* _NL_COLLATE_NRULES */

View File

@ -544,7 +544,6 @@ const struct locale_data _nl_C_LC_CTYPE attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
1, /* Enable transliteration by default. */
NULL,
NR_FIXED + NR_CLASSES + NR_MAPS,
{
/* _NL_CTYPE_CLASS */

View File

@ -30,7 +30,6 @@ const struct locale_data _nl_C_LC_IDENTIFICATION attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
16,
{
{ string: "ISO/IEC 14652 i18n FDCC-set" },

View File

@ -30,7 +30,6 @@ const struct locale_data _nl_C_LC_MEASUREMENT attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
2,
{
{ string: "\1" },

View File

@ -30,7 +30,6 @@ const struct locale_data _nl_C_LC_MESSAGES attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
5,
{
{ string: "^[yY]" },

View File

@ -34,7 +34,6 @@ const struct locale_data _nl_C_LC_MONETARY attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
46,
{
{ string: "" },

View File

@ -30,7 +30,6 @@ const struct locale_data _nl_C_LC_NAME attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
7,
{
{ string: "%p%t%g%t%m%t%f" },

View File

@ -27,7 +27,6 @@ const struct locale_data _nl_C_LC_NUMERIC attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
6,
{
{ string: "." },

View File

@ -30,7 +30,6 @@ const struct locale_data _nl_C_LC_PAPER attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
3,
{
{ word: 297 },

View File

@ -30,7 +30,6 @@ const struct locale_data _nl_C_LC_TELEPHONE attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
5,
{
{ string: "+%c %a %l" },

View File

@ -29,7 +29,6 @@ const struct locale_data _nl_C_LC_TIME attribute_hidden =
NULL, 0, 0, /* no file mapped */
UNDELETABLE,
0,
NULL,
111,
{
{ string: "Sun" },

View File

@ -35,8 +35,8 @@ distribute = localeinfo.h categories.def iso-639.def iso-3166.def \
locfile-kw.gperf locfile-kw.h linereader.h \
locfile.h charmap.h repertoire.h localedef.h \
3level.h charmap-dir.h locarchive.c)
routines = setlocale findlocale loadlocale localeconv nl_langinfo \
nl_langinfo_l mb_cur_max \
routines = setlocale findlocale loadlocale loadarchive \
localeconv nl_langinfo nl_langinfo_l mb_cur_max \
newlocale duplocale freelocale uselocale
tests = tst-C-locale
categories = ctype messages monetary numeric time paper name \

View File

@ -42,8 +42,11 @@ extern struct locale_data *const _nl_C[] attribute_hidden;
which are somehow addressed. */
struct loaded_l10nfile *_nl_locale_file_list[__LC_LAST];
const char _nl_default_locale_path[] attribute_hidden = LOCALEDIR;
struct locale_data *
internal_function
_nl_find_locale (const char *locale_path, size_t locale_path_len,
int category, const char **name)
{
@ -82,6 +85,19 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
return _nl_C[category];
}
/* We really have to load some data. First we try the archive,
but only if there was no LOCPATH environment variable specified. */
if (__builtin_expect (locale_path == NULL, 1))
{
struct locale_data *data = _nl_load_locale_from_archive (category, name);
if (__builtin_expect (data != NULL, 1))
return data;
/* Nothing in the archive. Set the default path to search below. */
locale_path = _nl_default_locale_path;
locale_path_len = sizeof _nl_default_locale_path;
}
/* We really have to load some data. First see whether the name is
an alias. Please note that this makes it impossible to have "C"
or "POSIX" as aliases. */
@ -99,7 +115,7 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
Beside the first all of them are allowed to be missing. If the
full specified locale is not found, the less specific one are
looked for. The various part will be stripped of according to
looked for. The various part will be stripped off according to
the following order:
(1) codeset
(2) normalized codeset
@ -236,6 +252,7 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
/* Calling this function assumes the lock for handling global locale data
is acquired. */
void
internal_function
_nl_remove_locale (int locale, struct locale_data *data)
{
if (--data->usage_count == 0)
@ -258,7 +275,7 @@ _nl_remove_locale (int locale, struct locale_data *data)
#ifdef _POSIX_MAPPED_FILES
/* Really delete the data. First delete the real data. */
if (__builtin_expect (data->mmaped, 1))
if (__builtin_expect (data->alloc == ld_mapped, 1))
{
/* Try to unmap the area. If this fails we mark the area as
permanent. */

View File

@ -19,7 +19,8 @@
02111-1307 USA. */
#ifndef LONGBITS
# define LONGBITS (sizeof (long int) * BITSPERBYTE)
# include <limits.h>
# define LONGBITS (sizeof (long int) * CHAR_BIT)
#endif
unsigned long int compute_hashval (const void *key, size_t keylen);

447
locale/loadarchive.c Normal file
View File

@ -0,0 +1,447 @@
/* Code to load locale data from the locale archive file.
Copyright (C) 2002 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
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <locale.h>
#include <stddef.h>
#include <stdbool.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/param.h>
#include "localeinfo.h"
#include "locarchive.h"
/* Define the hash function. We define the function as static inline. */
#define compute_hashval static inline compute_hashval
#include "hashval.h"
#undef compute_hashval
#undef LOCALEDIR
#define LOCALEDIR "/spare/roland/tmp/usr/lib/locale/"
/* Name of the locale archive file. */
static const char archfname[] = LOCALEDIR "locale-archive";
/* Record of contiguous pages already mapped from the locale archive. */
struct archmapped
{
void *ptr;
uint32_t from;
uint32_t len;
struct archmapped *next;
};
static struct archmapped *archmapped;
/* This describes the mapping at the beginning of the file that contains
the header data. There could be data in the following partial page,
so this is searched like any other. Once the archive has been used,
ARCHMAPPED points to this; if mapping the archive header failed,
then headmap.ptr is null. */
static struct archmapped headmap;
static struct stat64 archive_stat; /* stat of archive when header mapped. */
/* Record of locales that we have already loaded from the archive. */
struct locale_in_archive
{
struct locale_in_archive *next;
const char *name;
struct locale_data *data[__LC_LAST];
};
static struct locale_in_archive *archloaded;
/* Local structure and subroutine of _nl_load_archive, see below. */
struct range
{
uint32_t from;
uint32_t len;
int category;
void *result;
};
static int
rangecmp (const void *p1, const void *p2)
{
return ((struct range *) p1)->from - ((struct range *) p2)->from;
}
/* Calculate the amount of space needed for all the tables described
by the given header. Note we do not include the empty table space
that has been preallocated in the file, so our mapping may not be
large enough if localedef adds data to the file in place. However,
doing that would permute the header fields while we are accessing
them and thus not be safe anyway, so we don't allow for that. */
static inline off_t
calculate_head_size (const struct locarhead *h)
{
off_t namehash_end = (h->namehash_offset
+ h->namehash_size * sizeof (struct namehashent));
off_t string_end = h->string_offset + h->string_used;
off_t locrectab_end = (h->locrectab_offset
+ h->locrectab_used * sizeof (struct locrecent));
return MAX (namehash_end, MAX (string_end, locrectab_end));
}
/* Find the locale *NAMEP in the locale archive, and return the
internalized data structure for its CATEGORY data. If this locale has
already been loaded from the archive, just returns the existing data
structure. If successful, sets *NAMEP to point directly into the mapped
archive string table; that way, the next call can short-circuit strcmp. */
struct locale_data *
internal_function
_nl_load_locale_from_archive (int category, const char **namep)
{
const char *name = *namep;
struct
{
void *addr;
size_t len;
} results[__LC_LAST];
struct locale_in_archive *lia;
struct locarhead *head;
struct namehashent *namehashtab;
struct locrecent *locrec;
struct archmapped *mapped;
struct archmapped *last;
unsigned long int hval;
size_t idx;
size_t incr;
struct range ranges[__LC_LAST - 1];
int nranges;
int cnt;
size_t ps = __sysconf (_SC_PAGE_SIZE);
int fd = -1;
/* Check if we have already loaded this locale from the archive.
If we previously loaded the locale but found bogons in the data,
then we will have stored a null pointer to return here. */
for (lia = archloaded; lia != NULL; lia = lia->next)
if (name == lia->name || !strcmp (name, lia->name))
{
*namep = lia->name;
return lia->data[category];
}
{
/* If the name contains a codeset, then we normalize the name before
doing the lookup. */
const char *p = strchr (name, '.');
if (p != NULL && p[1] != '@' && p[1] != '\0')
{
const char *rest = __strchrnul (++p, '@');
const char *normalized_codeset = _nl_normalize_codeset (p, rest - p);
if (normalized_codeset == NULL) /* malloc failure */
return NULL;
if (strncmp (normalized_codeset, p, rest - p) != 0
|| normalized_codeset[rest - p] != '\0')
{
/* There is a normalized codeset name that is different from
what was specified; reconstruct a new locale name using it. */
size_t normlen = strlen (normalized_codeset);
size_t restlen = strlen (rest) + 1;
char *newname = alloca (p - name + normlen + restlen);
memcpy (__mempcpy (__mempcpy (newname, name, p - name),
normalized_codeset, normlen),
rest, restlen);
free ((char *) normalized_codeset);
name = newname;
}
}
}
/* Make sure the archive is loaded. */
if (archmapped == NULL)
{
/* We do this early as a sign that we have tried to open the archive.
If headmap.ptr remains null, that's an indication that we tried
and failed, so we won't try again. */
archmapped = &headmap;
/* The archive has never been opened. */
fd = __open64 (archfname, O_RDONLY);
if (fd < 0)
/* Cannot open the archive, for whatever reason. */
return NULL;
if (__fxstat64 (_STAT_VER, fd, &archive_stat) == -1)
{
/* stat failed, very strange. */
close_and_out:
__close (fd);
return NULL;
}
if (sizeof (void *) > 4)
{
/* We will just map the whole file, what the hell. */
void *result = __mmap64 (NULL, archive_stat.st_size,
PROT_READ, MAP_SHARED, fd, 0);
if (result == MAP_FAILED)
goto close_and_out;
/* Check whether the file is large enough for the sizes given in the
header. */
if (calculate_head_size ((const struct locarhead *) result)
> archive_stat.st_size)
{
(void) munmap (result, archive_stat.st_size);
goto close_and_out;
}
__close (fd);
fd = -1;
headmap.ptr = result;
/* headmap.from already initialized to zero. */
headmap.len = archive_stat.st_size;
}
else
{
struct locarhead head;
off_t head_size;
void *result;
if (TEMP_FAILURE_RETRY (__read (fd, &head, sizeof (head)))
!= sizeof (head))
goto close_and_out;
head_size = calculate_head_size (&head);
if (head_size > archive_stat.st_size)
goto close_and_out;
result = __mmap64 (NULL, head_size, PROT_READ, MAP_SHARED, fd, 0);
if (result == MAP_FAILED)
goto close_and_out;
/* Record that we have mapped the initial pages of the file. */
headmap.ptr = result;
headmap.len = MIN ((head_size + ps - 1) & ~(ps - 1),
archive_stat.st_size);
}
}
/* If there is no archive or it cannot be loaded for some reason fail. */
if (__builtin_expect (headmap.ptr == NULL, 0))
return NULL;
/* We have the archive available. To find the name we first have to
determine its hash value. */
hval = compute_hashval (name, strlen (name));
head = headmap.ptr;
namehashtab = (struct namehashent *) ((char *) head
+ head->namehash_offset);
idx = hval % head->namehash_size;
incr = 1 + hval % (head->namehash_size - 2);
/* If the name_offset field is zero this means this is a
deleted entry and therefore no entry can be found. */
while (1)
{
if (namehashtab[idx].name_offset == 0)
/* Not found. */
return NULL;
if (namehashtab[idx].hashval == hval
&& strcmp (name, headmap.ptr + namehashtab[idx].name_offset) == 0)
/* Found the entry. */
break;
idx += incr;
if (idx >= head->namehash_size)
idx -= head->namehash_size;
}
/* We found an entry. It might be a placeholder for a removed one. */
if (namehashtab[idx].locrec_offset == 0)
return NULL;
locrec = (struct locrecent *) (headmap.ptr + namehashtab[idx].locrec_offset);
if (sizeof (void *) > 4 /* || headmap.len == archive_stat.st_size */)
{
/* We already have the whole locale archive mapped in. */
assert (headmap.len == archive_stat.st_size);
for (cnt = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL)
{
if (locrec->record[cnt].offset + locrec->record[cnt].len
> headmap.len)
/* The archive locrectab contains bogus offsets. */
return NULL;
results[cnt].addr = headmap.ptr + locrec->record[cnt].offset;
results[cnt].len = locrec->record[cnt].len;
}
}
else
{
/* Get the offsets of the data files and sort them. */
for (cnt = nranges = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL)
{
ranges[nranges].from = locrec->record[cnt].offset;
ranges[nranges].len = locrec->record[cnt].len;
ranges[nranges].category = cnt;
ranges[nranges].result = NULL;
++nranges;
}
qsort (ranges, nranges, sizeof (ranges[0]), rangecmp);
/* The information about mmap'd blocks is kept in a list.
Skip over the blocks which are before the data we need. */
last = mapped = archmapped;
for (cnt = 0; cnt < nranges; ++cnt)
{
int upper;
size_t from;
size_t to;
void *addr;
struct archmapped *newp;
/* Determine whether the appropriate page is already mapped. */
while (mapped != NULL
&& mapped->from + mapped->len <= ranges[cnt].from)
{
last = mapped;
mapped = mapped->next;
}
/* Do we have a match? */
if (mapped != NULL
&& mapped->from <= ranges[cnt].from
&& ((char *) ranges[cnt].from + ranges[cnt].len
<= (char *) mapped->from + mapped->len))
{
/* Yep, already loaded. */
results[ranges[cnt].category].addr = ((char *) mapped->ptr
+ ranges[cnt].from
- mapped->from);
results[ranges[cnt].category].len = ranges[cnt].len;
continue;
}
/* Map the range with the locale data from the file. We will
try to cover as much of the locale as possible. I.e., if the
next category (next as in "next offset") is on the current or
immediately following page we use it as well. */
assert (powerof2 (ps));
from = ranges[cnt].from & ~(ps - 1);
upper = cnt;
do
{
to = ((ranges[upper].from + ranges[upper].len + ps - 1)
& ~(ps - 1));
++upper;
}
/* Loop while still in contiguous pages. */
while (upper < nranges && ranges[upper].from < to + ps);
if (to > archive_stat.st_size)
/* The archive locrectab contains bogus offsets. */
return NULL;
/* Open the file if it hasn't happened yet. */
if (fd == -1)
{
struct stat64 st;
fd = __open64 (archfname, O_RDONLY);
if (fd == -1)
/* Cannot open the archive, for whatever reason. */
return NULL;
/* Now verify we think this is really the same archive file
we opened before. If it has been changed we cannot trust
the header we read previously. */
if (__fxstat64 (_STAT_VER, fd, &st) < 0
|| st.st_size != archive_stat.st_size
|| st.st_mtime != archive_stat.st_mtime
|| st.st_dev != archive_stat.st_dev
|| st.st_ino != archive_stat.st_ino)
return NULL;
}
/* Map the range from the archive. */
addr = __mmap64 (NULL, to - from, PROT_READ, MAP_SHARED, fd, from);
if (addr == MAP_FAILED)
return NULL;
/* Allocate a record for this mapping. */
newp = (struct archmapped *) malloc (sizeof (struct archmapped));
if (newp == NULL)
{
(void) munmap (addr, to - from);
return NULL;
}
/* And queue it. */
newp->ptr = addr;
newp->from = from;
newp->len = to - from;
assert (last->next == mapped);
newp->next = mapped;
last->next = newp;
last = newp;
/* Determine the load addresses for the category data. */
do
{
assert (ranges[cnt].from >= from);
results[ranges[cnt].category].addr = ((char *) addr
+ ranges[cnt].from - from);
results[ranges[cnt].category].len = ranges[cnt].len;
}
while (++cnt < upper);
--cnt; /* The 'for' will increase 'cnt' again. */
}
}
/* We succeeded in mapping all the necessary regions of the archive.
Now we need the expected data structures to point into the data. */
lia = malloc (sizeof *lia);
if (__builtin_expect (lia == NULL, 0))
return NULL;
lia->name = headmap.ptr + namehashtab[idx].name_offset;
lia->next = archloaded;
archloaded = lia;
for (cnt = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL)
{
lia->data[cnt] = _nl_intern_locale_data (cnt,
results[cnt].addr,
results[cnt].len);
if (__builtin_expect (lia->data[cnt] != NULL, 1))
{
/* _nl_intern_locale_data leaves us these fields to initialize. */
lia->data[cnt]->alloc = ld_archive;
lia->data[cnt]->name = lia->name;
}
}
*namep = lia->name;
return lia->data[category];
}

View File

@ -60,21 +60,82 @@ static const enum value_type *_nl_value_types[] =
};
void
_nl_load_locale (struct loaded_l10nfile *file, int category)
struct locale_data *
internal_function
_nl_intern_locale_data (int category, const void *data, size_t datasize)
{
int fd;
struct
const struct
{
unsigned int magic;
unsigned int nstrings;
unsigned int strindex[0];
} *filedata;
} *const filedata = data;
struct locale_data *newdata;
size_t cnt;
if (__builtin_expect (datasize < sizeof *filedata, 0)
|| __builtin_expect (filedata->magic != LIMAGIC (category), 0))
{
/* Bad data file. */
__set_errno (EINVAL);
return NULL;
}
if (__builtin_expect (filedata->nstrings < _nl_category_num_items[category],
0)
|| (__builtin_expect (sizeof *filedata
+ filedata->nstrings * sizeof (unsigned int)
>= datasize, 0)))
{
/* Insufficient data. */
__set_errno (EINVAL);
return NULL;
}
newdata = malloc (sizeof *newdata
+ filedata->nstrings * sizeof (union locale_data_value));
if (newdata == NULL)
return NULL;
newdata->filedata = (void *) filedata;
newdata->filesize = datasize;
newdata->usage_count = 0;
newdata->use_translit = 0;
newdata->nstrings = filedata->nstrings;
for (cnt = 0; cnt < newdata->nstrings; ++cnt)
{
size_t idx = filedata->strindex[cnt];
if (__builtin_expect (idx > newdata->filesize, 0))
{
puntdata:
free (newdata);
__set_errno (EINVAL);
return NULL;
}
if (__builtin_expect (_nl_value_types[category][cnt] == word, 0))
{
if (idx % __alignof__ (u_int32_t) != 0)
goto puntdata;
newdata->values[cnt].word =
*((const u_int32_t *) (newdata->filedata + idx));
}
else
newdata->values[cnt].string = newdata->filedata + idx;
}
return newdata;
}
void
internal_function
_nl_load_locale (struct loaded_l10nfile *file, int category)
{
int fd;
void *filedata;
struct stat64 st;
struct locale_data *newdata;
int save_err;
int mmaped = 1;
size_t cnt;
int alloc = ld_mapped;
file->decided = 1;
file->data = NULL;
@ -85,7 +146,11 @@ _nl_load_locale (struct loaded_l10nfile *file, int category)
return;
if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
goto puntfd;
{
puntfd:
__close (fd);
return;
}
if (__builtin_expect (S_ISDIR (st.st_mode), 0))
{
/* LOCALE/LC_foo is a directory; open LOCALE/LC_foo/SYS_LC_foo
@ -122,25 +187,15 @@ _nl_load_locale (struct loaded_l10nfile *file, int category)
/* Some systems do not have this flag; it is superfluous. */
# define MAP_FILE 0
# endif
# ifndef MAP_INHERIT
/* Some systems might lack this; they lose. */
# define MAP_INHERIT 0
# endif
filedata = (void *) __mmap ((caddr_t) 0, st.st_size, PROT_READ,
MAP_FILE|MAP_COPY|MAP_INHERIT, fd, 0);
if (__builtin_expect ((void *) filedata != MAP_FAILED, 1))
{
if (__builtin_expect (st.st_size < sizeof (*filedata), 0))
/* This cannot be a locale data file since it's too small. */
goto puntfd;
}
else
filedata = __mmap ((caddr_t) 0, st.st_size,
PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
if (__builtin_expect (filedata == MAP_FAILED, 0))
{
if (__builtin_expect (errno, ENOSYS) == ENOSYS)
{
#endif /* _POSIX_MAPPED_FILES */
/* No mmap; allocate a buffer and read from the file. */
mmaped = 0;
alloc = ld_malloced;
filedata = malloc (st.st_size);
if (filedata != NULL)
{
@ -160,87 +215,58 @@ _nl_load_locale (struct loaded_l10nfile *file, int category)
p += nread;
to_read -= nread;
}
__set_errno (save_err);
}
else
goto puntfd;
__set_errno (save_err);
#ifdef _POSIX_MAPPED_FILES
}
else
goto puntfd;
}
#endif /* _POSIX_MAPPED_FILES */
if (__builtin_expect (filedata->magic != LIMAGIC (category), 0))
/* Bad data file in either byte order. */
/* We have mapped the data, so we no longer need the descriptor. */
__close (fd);
if (__builtin_expect (filedata == NULL, 0))
/* We failed to map or read the data. */
return;
newdata = _nl_intern_locale_data (category, filedata, st.st_size);
if (__builtin_expect (newdata == NULL, 0))
/* Bad data. */
{
puntmap:
#ifdef _POSIX_MAPPED_FILES
__munmap ((caddr_t) filedata, st.st_size);
if (alloc == ld_mapped)
__munmap ((caddr_t) filedata, st.st_size);
#endif
puntfd:
__close (fd);
return;
}
if (__builtin_expect (filedata->nstrings < _nl_category_num_items[category],
0)
|| (__builtin_expect (sizeof *filedata
+ filedata->nstrings * sizeof (unsigned int)
>= (size_t) st.st_size, 0)))
{
/* Insufficient data. */
__set_errno (EINVAL);
goto puntmap;
}
newdata = malloc (sizeof *newdata
+ filedata->nstrings * sizeof (union locale_data_value));
if (newdata == NULL)
goto puntmap;
/* _nl_intern_locale_data leaves us these fields to initialize. */
newdata->name = NULL; /* This will be filled if necessary in findlocale.c. */
newdata->filedata = (void *) filedata;
newdata->filesize = st.st_size;
newdata->mmaped = mmaped;
newdata->usage_count = 0;
newdata->use_translit = 0;
newdata->options = NULL;
newdata->nstrings = filedata->nstrings;
for (cnt = 0; cnt < newdata->nstrings; ++cnt)
{
off_t idx = filedata->strindex[cnt];
if (__builtin_expect (idx > newdata->filesize, 0))
{
free (newdata);
__set_errno (EINVAL);
goto puntmap;
}
if (__builtin_expect (_nl_value_types[category][cnt] == word, 0))
{
assert (idx % __alignof__ (u_int32_t) == 0);
newdata->values[cnt].word =
*((u_int32_t *) (newdata->filedata + idx));
}
else
newdata->values[cnt].string = newdata->filedata + idx;
}
newdata->alloc = alloc;
__close (fd);
file->data = newdata;
}
void
internal_function
_nl_unload_locale (struct locale_data *locale)
{
switch (__builtin_expect (locale->alloc, ld_mapped))
{
case ld_malloced:
free ((void *) locale->filedata);
break;
case ld_mapped:
#ifdef _POSIX_MAPPED_FILES
if (__builtin_expect (locale->mmaped, 1))
__munmap ((caddr_t) locale->filedata, locale->filesize);
else
__munmap ((caddr_t) locale->filedata, locale->filesize);
break;
#endif
free ((void *) locale->filedata);
case ld_archive: /* Nothing to do. */
break;
}
if (__builtin_expect (locale->alloc, ld_mapped) != ld_archive)
free ((char *) locale->name);
free ((char *) locale->options);
free ((char *) locale->name);
free (locale);
}

View File

@ -47,14 +47,17 @@ struct locale_data
const char *name;
const char *filedata; /* Region mapping the file data. */
off_t filesize; /* Size of the file (and the region). */
int mmaped; /* If nonzero the data is mmaped. */
enum /* Flavor of storage used for those. */
{
ld_malloced, /* Both are malloc'd. */
ld_mapped, /* name is malloc'd, filedata mmap'd */
ld_archive /* Both point into mmap'd archive regions. */
} alloc;
unsigned int usage_count; /* Counter for users. */
int use_translit; /* Nonzero if the mb*towv*() and wc*tomb()
functions should use transliteration. */
const char *options; /* Extra options from the locale name,
not used in the path to the locale data. */
unsigned int nstrings; /* Number of strings below. */
union locale_data_value
@ -152,6 +155,7 @@ extern const char _nl_C_codeset[] attribute_hidden;
Each is malloc'd unless it is _nl_C_name. */
extern const char *_nl_current_names[] attribute_hidden;
#ifndef SHARED
/* For each category declare the variable for the current locale data. */
@ -222,22 +226,50 @@ extern struct __locale_struct _nl_global_locale attribute_hidden;
#endif
/* Default search path if no LOCPATH environment variable. */
extern const char _nl_default_locale_path[] attribute_hidden;
/* Load the locale data for CATEGORY from the file specified by *NAME.
If *NAME is "", use environment variables as specified by POSIX,
and fill in *NAME with the actual name used. The directories
listed in LOCALE_PATH are searched for the locale files. */
If *NAME is "", use environment variables as specified by POSIX, and
fill in *NAME with the actual name used. If LOCALE_PATH is not null,
those directories are searched for the locale files. If it's null,
the locale archive is checked first and then _nl_default_locale_path
is searched for locale files. */
extern struct locale_data *_nl_find_locale (const char *locale_path,
size_t locale_path_len,
int category, const char **name);
int category, const char **name)
internal_function attribute_hidden;
/* Try to load the file described by FILE. */
extern void _nl_load_locale (struct loaded_l10nfile *file, int category);
extern void _nl_load_locale (struct loaded_l10nfile *file, int category)
internal_function attribute_hidden;
/* Free all resource. */
extern void _nl_unload_locale (struct locale_data *locale);
extern void _nl_unload_locale (struct locale_data *locale)
internal_function attribute_hidden;
/* Free the locale and give back all memory if the usage count is one. */
extern void _nl_remove_locale (int locale, struct locale_data *data);
extern void _nl_remove_locale (int locale, struct locale_data *data)
internal_function attribute_hidden;
/* Find the locale *NAMEP in the locale archive, and return the
internalized data structure for its CATEGORY data. If this locale has
already been loaded from the archive, just returns the existing data
structure. If successful, sets *NAMEP to point directly into the mapped
archive string table; that way, the next call can short-circuit strcmp. */
extern struct locale_data *_nl_load_locale_from_archive (int category,
const char **namep)
internal_function attribute_hidden;
/* Validate the contents of a locale file and set up the in-core
data structure to point into the data. This leaves the `alloc'
and `name' fields uninitialized, for the caller to fill in.
If any bogons are detected in the data, this will refuse to
intern it, and return a null pointer instead. */
extern struct locale_data *_nl_intern_locale_data (int category,
const void *data,
size_t datasize)
internal_function attribute_hidden;
/* Return `era' entry which corresponds to TP. Used in strftime. */

View File

@ -80,19 +80,22 @@ __newlocale (int category_mask, const char *locale, __locale_t base)
/* We perhaps really have to load some data. So we determine the
path in which to look for the data now. The environment variable
`LOCPATH' must only be used when the binary has no SUID or SGID
bit set. */
bit set. If using the default path, we tell _nl_find_locale
by passing null and it can check the canonical locale archive. */
locale_path = NULL;
locale_path_len = 0;
locpath_var = getenv ("LOCPATH");
if (locpath_var != NULL && locpath_var[0] != '\0')
if (__argz_create_sep (locpath_var, ':',
&locale_path, &locale_path_len) != 0)
return NULL;
{
if (__argz_create_sep (locpath_var, ':',
&locale_path, &locale_path_len) != 0)
return NULL;
if (__argz_append (&locale_path, &locale_path_len,
LOCALEDIR, sizeof (LOCALEDIR)) != 0)
return NULL;
if (__argz_add_sep (&locale_path, &locale_path_len,
_nl_default_locale_path, ':') != 0)
return NULL;
}
/* Get the names for the locales we are interested in. We either
allow a composite name or a single name. */

View File

@ -76,6 +76,9 @@ static const char *input_file;
/* Name of the repertoire map file. */
const char *repertoire_global;
/* Name of the locale.alias file. */
const char *alias_file;
/* List of all locales. */
static struct localedef_t *locales;
@ -140,6 +143,8 @@ static const struct argp_option options[] =
{ "delete-from-archive", OPT_DELETE_FROM_ARCHIVE, NULL, 0,
N_("Remove locales named by parameters from archive") },
{ "list-archive", OPT_LIST_ARCHIVE, NULL, 0, N_("List content of archive") },
{ "alias-file", 'A', "FILE", 0,
N_("locale.alias file to consult when making archive")},
{ NULL, 0, NULL, 0, NULL }
};
@ -331,6 +336,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
case 'f':
charmap_file = arg;
break;
case 'A':
alias_file = arg;
break;
case 'i':
input_file = arg;
break;

View File

@ -118,6 +118,7 @@ extern int oldstyle_tables;
extern const char *repertoire_global;
extern int max_locarchive_open_retry;
extern bool no_archive;
extern const char *alias_file;
/* Prototypes for a few program-wide used functions. */

View File

@ -31,6 +31,7 @@
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@ -59,7 +60,7 @@ static const char *locnames[] =
/* Size of the initial archive header. */
#define INITIAL_NUM_NANES 450
#define INITIAL_NUM_NAMES 450
#define INITIAL_SIZE_STRINGS 3500
#define INITIAL_NUM_LOCREC 350
#define INITIAL_NUM_SUMS 2000
@ -85,7 +86,7 @@ create_archive (const char *archivefname, struct locarhandle *ah)
head.magic = AR_MAGIC;
head.namehash_offset = sizeof (struct locarhead);
head.namehash_used = 0;
head.namehash_size = next_prime (INITIAL_NUM_NANES);
head.namehash_size = next_prime (INITIAL_NUM_NAMES);
head.string_offset = (head.namehash_offset
+ head.namehash_size * sizeof (struct namehashent));
@ -166,6 +167,9 @@ create_archive (const char *archivefname, struct locarhandle *ah)
ah->len = total;
}
/* forward decl for below */
static uint32_t add_locale (struct locarhandle *ah, const char *name,
locale_data_t data, bool replace);
static void
enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
@ -300,10 +304,9 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
old_data[idx].sum);
}
if (add_locale_to_archive (&new_ah,
((char *) ah->addr
+ oldnamehashtab[cnt].name_offset),
old_data, 0) != 0)
if (add_locale (&new_ah,
((char *) ah->addr + oldnamehashtab[cnt].name_offset),
old_data, 0) == 0)
error (EXIT_FAILURE, 0, _("cannot extend locale archive file"));
}
@ -446,16 +449,123 @@ close_archive (struct locarhandle *ah)
}
}
#include "../../intl/explodename.c"
#include "../../intl/l10nflist.c"
static struct namehashent *
insert_name (struct locarhandle *ah,
const char *name, size_t name_len, bool replace)
{
const struct locarhead *const head = ah->addr;
struct namehashent *namehashtab
= (struct namehashent *) ((char *) ah->addr + head->namehash_offset);
unsigned int insert_idx, idx, incr;
/* Hash value of the locale name. */
uint32_t hval = compute_hashval (name, name_len);
insert_idx = -1;
idx = hval % head->namehash_size;
incr = 1 + hval % (head->namehash_size - 2);
/* If the name_offset field is zero this means this is a
deleted entry and therefore no entry can be found. */
while (namehashtab[idx].name_offset != 0)
{
if (namehashtab[idx].hashval == hval
&& strcmp (name,
(char *) ah->addr + namehashtab[idx].name_offset) == 0)
{
/* Found the entry. */
if (namehashtab[idx].locrec_offset != 0 && ! replace)
{
if (! be_quiet)
error (0, 0, _("locale '%s' already exists"), name);
return NULL;
}
break;
}
/* Remember the first place we can insert the new entry. */
if (namehashtab[idx].locrec_offset == 0 && insert_idx == -1)
insert_idx = idx;
idx += incr;
if (idx >= head->namehash_size)
idx -= head->namehash_size;
}
/* Add as early as possible. */
if (insert_idx != -1)
idx = insert_idx;
namehashtab[idx].hashval = hval; /* no-op if replacing an old entry. */
return &namehashtab[idx];
}
static void
add_alias (struct locarhandle *ah, const char *alias, bool replace,
const char *oldname, uint32_t locrec_offset)
{
struct locarhead *head = ah->addr;
const size_t name_len = strlen (alias);
struct namehashent *namehashent = insert_name (ah, alias, strlen (alias),
replace);
if (namehashent == NULL && ! replace)
return;
if (namehashent->name_offset == 0)
{
/* We are adding a new hash entry for this alias.
Determine whether we have to resize the file. */
if (head->string_used + name_len + 1 > head->string_size
|| 100 * head->namehash_used > 75 * head->namehash_size)
{
/* The current archive is not large enough. */
enlarge_archive (ah, head);
/* The locrecent might have moved, so we have to look up
the old name afresh. */
namehashent = insert_name (ah, oldname, strlen (oldname), true);
assert (namehashent->name_offset != 0);
assert (namehashent->locrec_offset != 0);
locrec_offset = namehashent->locrec_offset;
/* Tail call to try the whole thing again. */
add_alias (ah, alias, replace, oldname, locrec_offset);
return;
}
/* Add the name string. */
memcpy (ah->addr + head->string_offset + head->string_used,
alias, name_len + 1);
namehashent->name_offset = head->string_offset + head->string_used;
head->string_used += name_len + 1;
++head->namehash_used;
}
if (namehashent->locrec_offset != 0)
{
/* Replacing an existing entry.
Mark that we are no longer using the old locrecent. */
struct locrecent *locrecent
= (struct locrecent *) ((char *) ah->addr
+ namehashent->locrec_offset);
--locrecent->refs;
}
/* Point this entry at the locrecent installed for the main name. */
namehashent->locrec_offset = locrec_offset;
}
/* Check the content of the archive for duplicates. Add the content
of the files if necessary. Add all the names, possibly overwriting
old files. */
int
add_locale_to_archive (ah, name, data, replace)
struct locarhandle *ah;
const char *name;
locale_data_t data;
bool replace;
of the files if necessary. Returns the locrec_offset. */
static uint32_t
add_locale (struct locarhandle *ah,
const char *name, locale_data_t data, bool replace)
{
/* First look for the name. If it already exists and we are not
supposed to replace it don't do anything. If it does not exist
@ -467,9 +577,7 @@ add_locale_to_archive (ah, name, data, replace)
uint32_t hval;
unsigned int cnt;
unsigned int idx;
unsigned int insert_idx;
struct locarhead *head;
struct namehashent *namehashtab;
struct namehashent *namehashent;
unsigned int incr;
struct locrecent *locrecent;
@ -477,8 +585,6 @@ add_locale_to_archive (ah, name, data, replace)
head = ah->addr;
sumhashtab = (struct sumhashent *) ((char *) ah->addr
+ head->sumhash_offset);
namehashtab = (struct namehashent *) ((char *) ah->addr
+ head->namehash_offset);
/* For each locale category data set determine whether the same data
@ -514,47 +620,10 @@ add_locale_to_archive (ah, name, data, replace)
}
}
/* Hash value of the locale name. */
hval = compute_hashval (name, name_len);
insert_idx = -1;
idx = hval % head->namehash_size;
incr = 1 + hval % (head->namehash_size - 2);
/* If the name_offset field is zero this means this is no
deleted entry and therefore no entry can be found. */
while (namehashtab[idx].name_offset != 0)
{
if (namehashtab[idx].hashval == hval
&& strcmp (name,
(char *) ah->addr + namehashtab[idx].name_offset) == 0)
{
/* Found the entry. */
if (namehashtab[idx].locrec_offset != 0 && ! replace)
{
if (! be_quiet)
error (0, 0, _("locale '%s' already exists"), name);
return 1;
}
break;
}
/* Remember the first place we can insert the new entry. */
if (namehashtab[idx].locrec_offset == 0 && insert_idx == -1)
insert_idx = idx;
idx += incr;
if (idx >= head->namehash_size)
idx -= head->namehash_size;
}
/* Add as early as possible. */
if (insert_idx != -1)
idx = insert_idx;
namehashent = &namehashtab[idx];
/* Find a slot for the locale name in the hash table. */
namehashent = insert_name (ah, name, name_len, replace);
if (namehashent == NULL) /* Already exists and !REPLACE. */
return 0;
/* Determine whether we have to resize the file. */
if (100 * (head->sumhash_used + num_new_offsets) > 75 * head->sumhash_size
@ -565,7 +634,7 @@ add_locale_to_archive (ah, name, data, replace)
{
/* The current archive is not large enough. */
enlarge_archive (ah, head);
return add_locale_to_archive (ah, name, data, replace);
return add_locale (ah, name, data, replace);
}
/* Add the locale data which is not yet in the archive. */
@ -620,29 +689,46 @@ add_locale_to_archive (ah, name, data, replace)
++head->sumhash_used;
}
if (namehashent->locrec_offset == 0)
if (namehashent->name_offset == 0)
{
/* Add the name string. */
memcpy ((char *) ah->addr + head->string_offset + head->string_used,
name, name_len + 1);
namehashent->name_offset = head->string_offset + head->string_used;
head->string_used += name_len + 1;
++head->namehash_used;
}
if (namehashent->locrec_offset == 0)
{
/* Allocate a name location record. */
namehashent->locrec_offset = (head->locrectab_offset
+ (head->locrectab_used++
* sizeof (struct locrecent)));
locrecent = (struct locrecent *) ((char *) ah->addr
+ namehashent->locrec_offset);
locrecent->refs = 1;
}
else
{
/* If there are other aliases pointing to this locrecent,
we still need a new one. If not, reuse the old one. */
namehashent->hashval = hval;
++head->namehash_used;
locrecent = (struct locrecent *) ((char *) ah->addr
+ namehashent->locrec_offset);
if (locrecent->refs > 1)
{
--locrecent->refs;
namehashent->locrec_offset = (head->locrectab_offset
+ (head->locrectab_used++
* sizeof (struct locrecent)));
locrecent = (struct locrecent *) ((char *) ah->addr
+ namehashent->locrec_offset);
locrecent->refs = 1;
}
}
/* Fill in the table with the locations of the locale data. */
locrecent = (struct locrecent *) ((char *) ah->addr
+ namehashent->locrec_offset);
for (cnt = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL)
{
@ -650,13 +736,196 @@ add_locale_to_archive (ah, name, data, replace)
locrecent->record[cnt].len = data[cnt].size;
}
return namehashent->locrec_offset;
}
/* Read the locale.alias file to see whether any matching record is
found. If an entry is available check whether it is already in
the archive. If this is the case check whether the new locale's
name is more specific than the one currently referred to by the
alias. */
/* Check the content of the archive for duplicates. Add the content
of the files if necessary. Add all the names, possibly overwriting
old files. */
int
add_locale_to_archive (ah, name, data, replace)
struct locarhandle *ah;
const char *name;
locale_data_t data;
bool replace;
{
char *normalized_name = NULL;
uint32_t locrec_offset;
/* First analyze the name to decide how to archive it. */
const char *language;
const char *modifier;
const char *territory;
const char *codeset;
const char *normalized_codeset;
int mask = _nl_explode_name (strdupa (name),
&language, &modifier, &territory,
&codeset, &normalized_codeset);
if (mask & XPG_NORM_CODESET)
/* This name contains a codeset in unnormalized form.
We will store it in the archive with a normalized name. */
asprintf (&normalized_name, "%s%s%s.%s%s%s",
language, territory == NULL ? "" : "_", territory ?: "",
(mask & XPG_NORM_CODESET) ? normalized_codeset : codeset,
modifier == NULL ? "" : "@", modifier ?: "");
/* This call does the main work. */
locrec_offset = add_locale (ah, normalized_name ?: name, data, replace);
free (normalized_name);
if (locrec_offset == 0)
{
if (mask & XPG_NORM_CODESET)
free ((char *) normalized_codeset);
return -1;
}
if ((mask & XPG_CODESET) == 0)
{
/* This name lacks a codeset, so determine the locale's codeset and
add an alias for its name with normalized codeset appended. */
const struct
{
unsigned int magic;
unsigned int nstrings;
unsigned int strindex[0];
} *filedata = data[LC_CTYPE].addr;
codeset = (char *) filedata
+ filedata->strindex[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME)];
normalized_codeset = _nl_normalize_codeset (codeset, strlen (codeset));
mask |= XPG_NORM_CODESET;
asprintf (&normalized_name, "%s%s%s.%s%s%s",
language, territory == NULL ? "" : "_", territory ?: "",
normalized_codeset,
modifier == NULL ? "" : "@", modifier ?: "");
add_alias (ah, normalized_name, replace, name, locrec_offset);
free (normalized_name);
}
/* Now read the locale.alias files looking for lines whose
right hand side matches our name after normalization. */
if (alias_file != NULL)
{
FILE *fp;
fp = fopen (alias_file, "r");
if (fp == NULL)
error (1, errno, _("locale alias file `%s' not found"),
alias_file);
/* No threads present. */
__fsetlocking (fp, FSETLOCKING_BYCALLER);
while (! feof_unlocked (fp))
{
/* It is a reasonable approach to use a fix buffer here
because
a) we are only interested in the first two fields
b) these fields must be usable as file names and so must
not be that long */
char buf[BUFSIZ];
char *alias;
char *value;
char *cp;
if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)
/* EOF reached. */
break;
cp = buf;
/* Ignore leading white space. */
while (isspace (cp[0]) && cp[0] != '\n')
++cp;
/* A leading '#' signals a comment line. */
if (cp[0] != '\0' && cp[0] != '#' && cp[0] != '\n')
{
alias = cp++;
while (cp[0] != '\0' && !isspace (cp[0]))
++cp;
/* Terminate alias name. */
if (cp[0] != '\0')
*cp++ = '\0';
/* Now look for the beginning of the value. */
while (isspace (cp[0]))
++cp;
if (cp[0] != '\0')
{
value = cp++;
while (cp[0] != '\0' && !isspace (cp[0]))
++cp;
/* Terminate value. */
if (cp[0] == '\n')
{
/* This has to be done to make the following
test for the end of line possible. We are
looking for the terminating '\n' which do not
overwrite here. */
*cp++ = '\0';
*cp = '\n';
}
else if (cp[0] != '\0')
*cp++ = '\0';
/* Does this alias refer to our locale? We will
normalize the right hand side and compare the
elements of the normalized form. */
{
const char *rhs_language;
const char *rhs_modifier;
const char *rhs_territory;
const char *rhs_codeset;
const char *rhs_normalized_codeset;
int rhs_mask = _nl_explode_name (value,
&rhs_language,
&rhs_modifier,
&rhs_territory,
&rhs_codeset,
&rhs_normalized_codeset);
if (!strcmp (language, rhs_language)
&& ((rhs_mask & XPG_CODESET)
/* He has a codeset, it must match normalized. */
? !strcmp ((mask & XPG_NORM_CODESET)
? normalized_codeset : codeset,
(rhs_mask & XPG_NORM_CODESET)
? rhs_normalized_codeset : rhs_codeset)
/* He has no codeset, we must also have none. */
: (mask & XPG_CODESET) == 0)
/* Codeset (or lack thereof) matches. */
&& !strcmp (territory ?: "", rhs_territory ?: "")
&& !strcmp (modifier ?: "", rhs_modifier ?: ""))
/* We have a winner. */
add_alias (ah, alias, replace,
normalized_name ?: name, locrec_offset);
if (rhs_mask & XPG_NORM_CODESET)
free ((char *) rhs_normalized_codeset);
}
}
}
/* Possibly not the whole line fits into the buffer.
Ignore the rest of the line. */
while (strchr (cp, '\n') == NULL)
{
cp = buf;
if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)
/* Make sure the inner loop will be left. The outer
loop will exit at the `feof' test. */
*cp = '\n';
}
}
fclose (fp);
}
if (mask & XPG_NORM_CODESET)
free ((char *) normalized_codeset);
return 0;
}
@ -903,7 +1172,6 @@ delete_locales_from_archive (nlist, list)
/* Found the entry. Now mark it as removed by zero-ing
the reference to the locale record. */
namehashtab[idx].locrec_offset = 0;
--head->namehash_used;
break;
}

View File

@ -247,18 +247,22 @@ setlocale (int category, const char *locale)
/* We perhaps really have to load some data. So we determine the
path in which to look for the data now. The environment variable
`LOCPATH' must only be used when the binary has no SUID or SGID
bit set. */
bit set. If using the default path, we tell _nl_find_locale
by passing null and it can check the canonical locale archive. */
locale_path = NULL;
locale_path_len = 0;
locpath_var = getenv ("LOCPATH");
if (locpath_var != NULL && locpath_var[0] != '\0')
if (__argz_create_sep (locpath_var, ':',
&locale_path, &locale_path_len) != 0)
return NULL;
{
if (__argz_create_sep (locpath_var, ':',
&locale_path, &locale_path_len) != 0)
return NULL;
if (__argz_add_sep (&locale_path, &locale_path_len, LOCALEDIR, ':') != 0)
return NULL;
if (__argz_add_sep (&locale_path, &locale_path_len,
_nl_default_locale_path, ':') != 0)
return NULL;
}
if (category == LC_ALL)
{

View File

@ -108,7 +108,7 @@ vwarnx (const char *format, __gnuc_va_list ap)
}
funlockfile (stderr);
}
libc_hidden_def (warnx)
libc_hidden_def (vwarnx)
void
vwarn (const char *format, __gnuc_va_list ap)
@ -142,7 +142,7 @@ vwarn (const char *format, __gnuc_va_list ap)
}
funlockfile (stderr);
}
libc_hidden_def (warnx)
libc_hidden_def (vwarnx)
void

View File

@ -1,5 +1,5 @@
/* Handle real-time signal allocation.
Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
Copyright (C) 1997,98,99,2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@ -62,6 +62,7 @@ __libc_current_sigrtmin (void)
#endif
return current_rtmin;
}
libc_hidden_def (__libc_current_sigrtmin)
/* Return number of available real-time signal with lowest priority. */
int
@ -73,6 +74,7 @@ __libc_current_sigrtmax (void)
#endif
return current_rtmax;
}
libc_hidden_def (__libc_current_sigrtmax)
/* Allocate real-time signal with highest/lowest available
priority. Please note that we don't use a lock since we assume

View File

@ -51,3 +51,4 @@ __default_morecore (increment)
return NULL;
return result;
}
libc_hidden_def (__default_morecore)