2002-04-18  Ulrich Drepper  <drepper@redhat.com>

	* locale/programs/locfile.c (to_archive): New variable.  To collect
	data which has to be added to the locale archive.
	(write_all_categories): Take new third parameter with locale name.
	Unless no_archive flag set add new locale data to the archive
	(write_locale_data): Unless no-archive flag set store generated data
	in to_archive data structure instead of generation output file.
	Add new parameter with locale category index.
	* locale/programs/locfile.h: Add new parameters in declaractions of
	write_all_categories and write_locale_data.
	* locale/programs/localedef.c: Recognize --no-archive, --list-archive,
	--add-to-archive, and --delete-from-archive options.  Pass extra
	parameter to write_all_categories.
	* locale/programs/localedef.h: Add prototypes for functions in
	locarchive.c.
	* locale/locarchive.h: New file.
	* locale/programs/locarchive.c: New file.
	* locale/Makefile (distribute): Add programs/locarchive.c and
	locarchive.h.
	(localedef-modules): Add md5 and locarchive.
	Add vpath to crypt subdir for md5.c.

	* locale/programs/ld-address.c: Pass locale category ID as new second
	parameter to write_locale_data.
	* locale/programs/ld-collate.c: Likewise.
	* locale/programs/ld-ctype.c: Likewise.
	* locale/programs/ld-identification.c: Likewise.
	* locale/programs/ld-measurement.c: Likewise.
	* locale/programs/ld-messages.c: Likewise.
	* locale/programs/ld-monetary.c: Likewise.
	* locale/programs/ld-name.c: Likewise.
	* locale/programs/ld-numeric.c: Likewise.
	* locale/programs/ld-paper.c: Likewise.
	* locale/programs/ld-telephone.c: Likewise.
	* locale/programs/ld-time.c: Likewise.

	* locale/simple-hash.c: Move compute_hashval function from here...
	* locale/hashval.h: ...to here.  New file.
	* locale/simple-hash.h: Add prototype for compute_hashval.

	* include/libintl.h: Minor cleanups.

	* elf/reldep7.c: New file.
	* elf/reldep7mod1.c: New file.
	* elf/reldep7mod2.c: New file.
	* elf/Makefile: Add rules to build and run reldep7.
This commit is contained in:
Ulrich Drepper 2002-04-18 08:08:23 +00:00
parent c77694049a
commit a7b65cdc9a
24 changed files with 1318 additions and 71 deletions

View File

@ -1,3 +1,46 @@
2002-04-18 Ulrich Drepper <drepper@redhat.com>
* locale/programs/locfile.c (to_archive): New variable. To collect
data which has to be added to the locale archive.
(write_all_categories): Take new third parameter with locale name.
Unless no_archive flag set add new locale data to the archive
(write_locale_data): Unless no-archive flag set store generated data
in to_archive data structure instead of generation output file.
Add new parameter with locale category index.
* locale/programs/locfile.h: Add new parameters in declaractions of
write_all_categories and write_locale_data.
* locale/programs/localedef.c: Recognize --no-archive, --list-archive,
--add-to-archive, and --delete-from-archive options. Pass extra
parameter to write_all_categories.
* locale/programs/localedef.h: Add prototypes for functions in
locarchive.c.
* locale/locarchive.h: New file.
* locale/programs/locarchive.c: New file.
* locale/Makefile (distribute): Add programs/locarchive.c and
locarchive.h.
(localedef-modules): Add md5 and locarchive.
Add vpath to crypt subdir for md5.c.
* locale/programs/ld-address.c: Pass locale category ID as new second
parameter to write_locale_data.
* locale/programs/ld-collate.c: Likewise.
* locale/programs/ld-ctype.c: Likewise.
* locale/programs/ld-identification.c: Likewise.
* locale/programs/ld-measurement.c: Likewise.
* locale/programs/ld-messages.c: Likewise.
* locale/programs/ld-monetary.c: Likewise.
* locale/programs/ld-name.c: Likewise.
* locale/programs/ld-numeric.c: Likewise.
* locale/programs/ld-paper.c: Likewise.
* locale/programs/ld-telephone.c: Likewise.
* locale/programs/ld-time.c: Likewise.
* locale/simple-hash.c: Move compute_hashval function from here...
* locale/hashval.h: ...to here. New file.
* locale/simple-hash.h: Add prototype for compute_hashval.
* include/libintl.h: Minor cleanups.
2002-04-16 Ulrich Drepper <drepper@redhat.com>
* posix/regcomp.c (gettext): Use INTUSE for _libc_intl_domainname.
@ -13,10 +56,10 @@
2002-02-17 Andreas Schwab <schwab@suse.de>
* reldep7.c: New file.
* reldep7mod1.c: New file.
* reldep7mod2.c: New file.
* Makefile: Add rules to build and run reldep7.
* elf/reldep7.c: New file.
* elf/reldep7mod1.c: New file.
* elf/reldep7mod2.c: New file.
* elf/Makefile: Add rules to build and run reldep7.
2002-04-14 Jakub Jelinek <jakub@redhat.com>

View File

@ -30,10 +30,10 @@ extern const char _libc_intl_domainname_internal[] attribute_hidden;
/* This is defined as an optimizing macro, so use it. */
# if !defined NOT_IN_libc && defined SHARED
# define _(msgid) \
__dcgettext_internal (_libc_intl_domainname_internal, (msgid), LC_MESSAGES)
__dcgettext_internal (_libc_intl_domainname_internal, msgid, LC_MESSAGES)
# else
# define _(msgid) \
__dcgettext (_libc_intl_domainname, (msgid), LC_MESSAGES)
__dcgettext (_libc_intl_domainname, msgid, LC_MESSAGES)
#endif
#endif

View File

@ -1,4 +1,4 @@
# Copyright (C) 1991, 92, 1995-1999, 2000, 2001 Free Software Foundation, Inc.
# Copyright (C) 1991,92,1995-1999,2000,2001,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
@ -26,6 +26,7 @@ distribute = localeinfo.h categories.def iso-639.def iso-3166.def \
iso-4217.def weight.h weightwc.h strlen-hash.h elem-hash.h \
indigits.h indigitswc.h outdigits.h outdigitswc.h \
coll-lookup.h C-translit.h.in C-translit.h gen-translit.pl \
locarchive.h \
$(addprefix programs/, \
locale.c localedef.c \
$(localedef-modules:=.c) $(locale-modules:=.c) \
@ -33,7 +34,7 @@ distribute = localeinfo.h categories.def iso-639.def iso-3166.def \
charmap-kw.gperf charmap-kw.h locfile-token.h \
locfile-kw.gperf locfile-kw.h linereader.h \
locfile.h charmap.h repertoire.h localedef.h \
3level.h charmap-dir.h)
3level.h charmap-dir.h locarchive.c)
routines = setlocale findlocale loadlocale localeconv nl_langinfo \
nl_langinfo_l mb_cur_max \
newlocale duplocale freelocale
@ -54,12 +55,12 @@ extra-libs-others = $(extra-libs)
libBrokenLocale-routines = broken_cur_max
subdir-dirs = programs
vpath %.c programs
vpath %.c programs ../crypt
vpath %.h programs
vpath %.gperf programs
localedef-modules := $(categories:%=ld-%) charmap linereader locfile \
repertoire
repertoire md5 locarchive
locale-modules := locale-spec
lib-modules := charmap-dir simple-hash xmalloc xstrdup

41
locale/hashval.h Normal file
View File

@ -0,0 +1,41 @@
/* Implement simple hashing table with string based keys.
Copyright (C) 1994-1997, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, October 1994.
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. */
unsigned long
compute_hashval (key, keylen)
const void *key;
size_t keylen;
{
size_t cnt;
unsigned long int hval;
/* Compute the hash value for the given string. The algorithm
is taken from [Aho,Sethi,Ullman], modified to reduce the number of
collisions for short strings with very varied bit patterns.
See http://www.clisp.org/haible/hashfunc.html. */
cnt = 0;
hval = keylen;
while (cnt < keylen)
{
hval = (hval << 9) | (hval >> (LONGBITS - 9));
hval += (unsigned long int) *(((char *) key) + cnt++);
}
return hval != 0 ? hval : ~((unsigned long) 0);
}

97
locale/locarchive.h Normal file
View File

@ -0,0 +1,97 @@
/* Definitions for locale archive handling.
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. */
#ifndef _LOCARCHIVE_H
#define _LOCARCHIVE_H 1
#include <stdint.h>
#define AR_MAGIC 0xde020109
struct locarhead
{
uint32_t magic;
/* Serial number. */
uint32_t serial;
/* Name hash table. */
uint32_t namehash_offset;
uint32_t namehash_used;
uint32_t namehash_size;
/* String table. */
uint32_t string_offset;
uint32_t string_used;
uint32_t string_size;
/* Table with locale records. */
uint32_t locrectab_offset;
uint32_t locrectab_used;
uint32_t locrectab_size;
/* MD5 sum hash table. */
uint32_t sumhash_offset;
uint32_t sumhash_used;
uint32_t sumhash_size;
};
struct namehashent
{
/* Hash value of the name. */
uint32_t hashval;
/* Offset of the name in the string table. */
uint32_t name_offset;
/* Offset of the locale record. */
uint32_t locrec_offset;
};
struct sumhashent
{
/* MD5 sum. */
char sum[16];
/* Offset of the file in the archive. */
uint32_t file_offset;
};
struct locrecent
{
struct
{
uint32_t offset;
uint32_t len;
} record[__LC_LAST];
};
struct locarhandle
{
int fd;
void *addr;
size_t len;
};
/* In memory data for the locales with their checksums. */
typedef struct
{
off64_t size;
void *addr;
char sum[16];
} locale_data_t[__LC_LAST];
#endif /* locarchive.h */

View File

@ -422,7 +422,7 @@ address_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS));
write_locale_data (output_path, "LC_ADDRESS",
write_locale_data (output_path, LC_ADDRESS, "LC_ADDRESS",
3 + _NL_ITEM_INDEX (_NL_NUM_LC_ADDRESS), iov);
}

View File

@ -1987,7 +1987,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE));
write_locale_data (output_path, "LC_COLLATE", 2 + cnt, iov);
write_locale_data (output_path, LC_COLLATE, "LC_COLLATE", 2 + cnt, iov);
return;
}
@ -2571,7 +2571,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == _NL_ITEM_INDEX (_NL_NUM_LC_COLLATE));
write_locale_data (output_path, "LC_COLLATE", 2 + cnt, iov);
write_locale_data (output_path, LC_COLLATE, "LC_COLLATE", 2 + cnt, iov);
obstack_free (&weightpool, NULL);
obstack_free (&extrapool, NULL);

View File

@ -1214,7 +1214,8 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (2 + elem + offset == (nelems + 2 * ctype->nr_charclass
+ ctype->map_collection_nr + 4 + 2));
write_locale_data (output_path, "LC_CTYPE", 2 + elem + offset, iov);
write_locale_data (output_path, LC_CTYPE, "LC_CTYPE", 2 + elem + offset,
iov);
}

View File

@ -291,7 +291,8 @@ identification_output (struct localedef_t *locale,
assert (cnt == (2 + _NL_ITEM_INDEX (_NL_NUM_LC_IDENTIFICATION)
+ (__LC_LAST - 2)));
write_locale_data (output_path, "LC_IDENTIFICATION", cnt, iov);
write_locale_data (output_path, LC_IDENTIFICATION, "LC_IDENTIFICATION", cnt,
iov);
}

View File

@ -150,7 +150,7 @@ measurement_output (struct localedef_t *locale,
assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT));
write_locale_data (output_path, "LC_MEASUREMENT",
write_locale_data (output_path, LC_MEASUREMENT, "LC_MEASUREMENT",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_MEASUREMENT), iov);
}

View File

@ -226,7 +226,7 @@ messages_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt + 1 == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES));
write_locale_data (output_path, "LC_MESSAGES",
write_locale_data (output_path, LC_MESSAGES, "LC_MESSAGES",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_MESSAGES), iov);
}

View File

@ -612,7 +612,7 @@ monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
write_locale_data (output_path, "LC_MONETARY",
write_locale_data (output_path, LC_MONETARY, "LC_MONETARY",
3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
}

View File

@ -210,7 +210,7 @@ name_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_NAME));
write_locale_data (output_path, "LC_NAME",
write_locale_data (output_path, LC_NAME, "LC_NAME",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_NAME), iov);
}

View File

@ -187,7 +187,7 @@ numeric_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt + 1 == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC));
write_locale_data (output_path, "LC_NUMERIC",
write_locale_data (output_path, LC_NUMERIC, "LC_NUMERIC",
3 + _NL_ITEM_INDEX (_NL_NUM_LC_NUMERIC), iov);
}

View File

@ -154,7 +154,7 @@ paper_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_PAPER));
write_locale_data (output_path, "LC_PAPER",
write_locale_data (output_path, LC_PAPER, "LC_PAPER",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_PAPER), iov);
}

View File

@ -218,7 +218,7 @@ telephone_output (struct localedef_t *locale, const struct charmap_t *charmap,
assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE));
write_locale_data (output_path, "LC_TELEPHONE",
write_locale_data (output_path, LC_TELEPHONE, "LC_TELEPHONE",
2 + _NL_ITEM_INDEX (_NL_NUM_LC_TELEPHONE), iov);
}

View File

@ -906,7 +906,7 @@ time_output (struct localedef_t *locale, const struct charmap_t *charmap,
+ 2 + time->num_era * 10 - 1));
assert (last_idx == _NL_ITEM_INDEX (_NL_NUM_LC_TIME));
write_locale_data (output_path, "LC_TIME", 2 + cnt, iov);
write_locale_data (output_path, LC_TIME, "LC_TIME", 2 + cnt, iov);
}

View File

@ -27,6 +27,7 @@
#include <libintl.h>
#include <locale.h>
#include <mcheck.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -56,7 +57,8 @@ int verbose;
/* If not zero suppress warnings and information messages. */
int be_quiet;
/* If not zero, produce old-style hash table instead of 3-level access tables. */
/* If not zero, produce old-style hash table instead of 3-level access
tables. */
int oldstyle_tables;
/* If not zero force output even if warning were issued. */
@ -77,15 +79,38 @@ const char *repertoire_global;
/* List of all locales. */
static struct localedef_t *locales;
/* If true don't add locale data to archive. */
bool no_archive;
/* If true add named locales to archive. */
static bool add_to_archive;
/* If true delete named locales from archive. */
static bool delete_from_archive;
/* If true replace archive content when adding. */
static bool replace_archive;
/* If true list archive content. */
static bool list_archive;
/* Maximum number of retries when opening the locale archive. */
int max_locarchive_open_retry = 10;
/* Name and version of program. */
static void print_version (FILE *stream, struct argp_state *state);
void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
#define OPT_POSIX 1
#define OPT_QUIET 2
#define OPT_OLDSTYLE 3
#define OPT_PREFIX 4
#define OPT_POSIX 301
#define OPT_QUIET 302
#define OPT_OLDSTYLE 303
#define OPT_PREFIX 304
#define OPT_NO_ARCHIVE 305
#define OPT_ADD_TO_ARCHIVE 306
#define OPT_REPLACE 307
#define OPT_DELETE_FROM_ARCHIVE 308
#define OPT_LIST_ARCHIVE 309
/* Definitions of arguments for argp functions. */
static const struct argp_option options[] =
@ -106,6 +131,15 @@ static const struct argp_option options[] =
{ "quiet", OPT_QUIET, NULL, 0,
N_("Suppress warnings and information messages") },
{ "verbose", 'v', NULL, 0, N_("Print more messages") },
{ NULL, 0, NULL, 0, N_("Archive control:") },
{ "no-archive", OPT_NO_ARCHIVE, NULL, 0,
N_("Don't add new data to archive") },
{ "add-to-archive", OPT_ADD_TO_ARCHIVE, NULL, 0,
N_("Add locales named by parameters to archive") },
{ "replace", OPT_REPLACE, NULL, 0, N_("Replace existing archive content") },
{ "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") },
{ NULL, 0, NULL, 0, NULL }
};
@ -113,7 +147,10 @@ static const struct argp_option options[] =
static const char doc[] = N_("Compile locale specification");
/* Strings for arguments in help texts. */
static const char args_doc[] = N_("NAME");
static const char args_doc[] = N_("\
NAME\n\
[--add-to-archive|--delete-from-archive] FILE...\n\
--list-archive [FILE]");
/* Prototype for option handler. */
static error_t parse_opt (int key, char *arg, struct argp_state *state);
@ -163,6 +200,15 @@ main (int argc, char *argv[])
argp_err_exit_status = 4;
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
/* Handle a few special cases. */
if (list_archive)
show_archive_content ();
if (add_to_archive)
return add_locales_to_archive (argc - remaining, &argv[remaining],
replace_archive);
if (delete_from_archive)
return delete_locales_from_archive (argc - remaining, &argv[remaining]);
/* POSIX.2 requires to be verbose about missing characters in the
character map. */
verbose |= posix_conformance;
@ -177,10 +223,18 @@ main (int argc, char *argv[])
/* The parameter describes the output path of the constructed files.
If the described files cannot be written return a NULL pointer. */
output_path = construct_output_path (argv[remaining]);
if (output_path == NULL)
error (4, errno, _("cannot create directory for output files"));
cannot_write_why = errno;
if (no_archive)
{
output_path = construct_output_path (argv[remaining]);
if (output_path == NULL)
error (4, errno, _("cannot create directory for output files"));
cannot_write_why = errno;
}
else
{
output_path = NULL;
cannot_write_why = 0; /* Just to shut the compiler up. */
}
/* Now that the parameters are processed we have to reset the local
ctype locale. (P1003.2 4.35.5.2) */
@ -235,7 +289,7 @@ cannot open locale definition file `%s'"), runp->name));
WITH_CUR_LOCALE (error (4, cannot_write_why, _("\
cannot write output files to `%s'"), output_path));
else
write_all_categories (locales, charmap, output_path);
write_all_categories (locales, charmap, argv[remaining], output_path);
}
else
WITH_CUR_LOCALE (error (4, 0, _("\
@ -264,6 +318,21 @@ parse_opt (int key, char *arg, struct argp_state *state)
case OPT_PREFIX:
output_prefix = arg;
break;
case OPT_NO_ARCHIVE:
no_archive = true;
break;
case OPT_ADD_TO_ARCHIVE:
add_to_archive = true;
break;
case OPT_REPLACE:
replace_archive = true;
break;
case OPT_DELETE_FROM_ARCHIVE:
delete_from_archive = true;
break;
case OPT_LIST_ARCHIVE:
list_archive = true;
break;
case 'c':
force_output = 1;
break;
@ -392,6 +461,10 @@ construct_output_path (char *path)
size_t len = strlen (path) + 1;
result = xmalloc (len + 1);
endp = mempcpy (result, path, len) - 1;
/* If the user specified an output path we cannot add the output
to the archive. */
no_archive = true;
}
errno = 0;

View File

@ -1,5 +1,5 @@
/* General definitions for localedef(1).
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@ -22,11 +22,13 @@
#define _LOCALEDEF_H 1
/* Get the basic locale definitions. */
#include <locale.h>
#include <stddef.h>
#include <errno.h>
#include <locale.h>
#include <stdbool.h>
#include <stddef.h>
#include "repertoire.h"
#include "../locarchive.h"
/* We need a bitmask for the locales. */
@ -114,6 +116,8 @@ extern int verbose;
extern int be_quiet;
extern int oldstyle_tables;
extern const char *repertoire_global;
extern int max_locarchive_open_retry;
extern bool no_archive;
/* Prototypes for a few program-wide used functions. */
@ -153,4 +157,24 @@ extern struct localedef_t *load_locale (int locale, const char *name,
const struct charmap_t *charmap,
struct localedef_t *copy_locale);
/* Open the locale archive. */
extern void open_archive (struct locarhandle *ah);
/* Close the locale archive. */
extern void close_archive (struct locarhandle *ah);
/* Add given locale data to the archive. */
extern int add_locale_to_archive (struct locarhandle *ah, const char *name,
locale_data_t data, bool replace);
/* Add content of named directories to locale archive. */
extern int add_locales_to_archive (size_t nlist, char *list[], bool replace);
/* Removed named locales from archive. */
extern int delete_locales_from_archive (size_t nlist, char *list[]);
/* List content of locale archive. */
extern void show_archive_content (void);
#endif /* localedef.h */

View File

@ -0,0 +1,931 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
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. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libintl.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/stat.h>
#include "../../crypt/md5.h"
#include "../localeinfo.h"
#include "../locarchive.h"
#include "simple-hash.h"
#include "localedef.h"
static const char archivefname[] = LOCALEDIR "/locale-archive";
static const char *locnames[] =
{
#define DEFINE_CATEGORY(category, category_name, items, a) \
[category] = category_name,
#include "categories.def"
#undef DEFINE_CATEGORY
};
/* Size of the initial archive header. */
#define INITIAL_NUM_NANES 450
#define INITIAL_SIZE_STRINGS 3500
#define INITIAL_NUM_LOCREC 350
#define INITIAL_NUM_SUMS 2000
static void
create_archive (struct locarhandle *ah)
{
int fd;
char fname[] = LOCALEDIR "/locale-archive.XXXXXX";
struct locarhead head;
void *p;
size_t total;
/* Create a temporary file in the correct directory. */
fd = mkstemp (fname);
if (fd == -1)
error (EXIT_FAILURE, errno, _("cannot create temporary file"));
/* Create the initial content of the archive. */
head.magic = AR_MAGIC;
head.namehash_offset = sizeof (struct locarhead);
head.namehash_used = 0;
head.namehash_size = next_prime (INITIAL_NUM_NANES);
head.string_offset = (head.namehash_offset
+ head.namehash_size * sizeof (struct namehashent));
head.string_used = 0;
head.string_size = INITIAL_SIZE_STRINGS;
head.locrectab_offset = head.string_offset + head.string_size;
head.locrectab_used = 0;
head.locrectab_size = INITIAL_NUM_LOCREC;
head.sumhash_offset = (head.locrectab_offset
+ head.locrectab_size * sizeof (struct locrecent));
head.sumhash_used = 0;
head.sumhash_size = next_prime (INITIAL_NUM_SUMS);
total = head.sumhash_offset + head.sumhash_size * sizeof (struct sumhashent);
/* Write out the header and create room for the other data structures. */
if (TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head))) != sizeof (head))
{
int errval = errno;
unlink (fname);
error (EXIT_FAILURE, errval, _("cannot initialize archive file"));
}
if (ftruncate64 (fd, total) != 0)
{
int errval = errno;
unlink (fname);
error (EXIT_FAILURE, errval, _("cannot resize archive file"));
}
/* Map the header and all the administration data structures. */
p = mmap64 (NULL, total, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED)
{
int errval = errno;
unlink (fname);
error (EXIT_FAILURE, errval, _("cannot map archive header"));
}
/* Now try to rename it. We don't use the rename function since
this would overwrite a file which has been created in
parallel. */
if (link (fname, archivefname) == -1)
{
int errval = errno;
/* We cannot use the just created file. */
close (fd);
unlink (fname);
if (errval == EEXIST)
{
/* There is already an archive. Must have been a localedef run
which happened in parallel. Simply open this file then. */
open_archive (ah);
return;
}
error (EXIT_FAILURE, errval, _("failed to create new locale archive"));
}
/* Remove the temporary name. */
unlink (fname);
/* Make the file globally readable. */
if (fchmod (fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) == -1)
{
int errval = errno;
unlink (archivefname);
error (EXIT_FAILURE, errval,
_("cannot change mode of new locale archive"));
}
ah->fd = fd;
ah->addr = p;
ah->len = total;
}
static void
enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
{
struct stat64 st;
int fd;
char fname[] = LOCALEDIR "/locale-archive.XXXXXX";
struct locarhead newhead;
size_t total;
void *p;
unsigned int cnt;
struct namehashent *oldnamehashtab;
struct locrecent *oldlocrectab;
struct locarhandle new_ah;
/* Not all of the old file has to be mapped. Change this now this
we will have to access the whole content. */
if (fstat64 (ah->fd, &st) != 0
|| (ah->addr = mmap64 (NULL, st.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, ah->fd, 0)) == MAP_FAILED)
error (EXIT_FAILURE, errno, _("cannot map locale archive file"));
ah->len = st.st_size;
/* Create a temporary file in the correct directory. */
fd = mkstemp (fname);
if (fd == -1)
error (EXIT_FAILURE, errno, _("cannot create temporary file"));
/* Copy the existing head information. */
newhead = *head;
/* Create the new archive header. The sizes of the various tables
should be double from what is currently used. */
newhead.namehash_size = MAX (next_prime (2 * newhead.namehash_used),
newhead.namehash_size);
printf ("name: size: %u, used: %d, new: size: %u\n",
head->namehash_size, head->namehash_used, newhead.namehash_size);
newhead.string_offset = (newhead.namehash_offset
+ (newhead.namehash_size
* sizeof (struct namehashent)));
newhead.string_size = MAX (2 * newhead.string_used, newhead.string_size);
newhead.locrectab_offset = newhead.string_offset + newhead.string_size;
newhead.locrectab_size = MAX (2 * newhead.locrectab_used,
newhead.locrectab_size);
newhead.sumhash_offset = (newhead.locrectab_offset
+ (newhead.locrectab_size
* sizeof (struct locrecent)));
newhead.sumhash_size = MAX (next_prime (2 * newhead.sumhash_used),
newhead.sumhash_size);
total = (newhead.sumhash_offset
+ newhead.sumhash_size * sizeof (struct sumhashent));
/* The new file is empty now. */
newhead.namehash_used = 0;
newhead.string_used = 0;
newhead.locrectab_used = 0;
newhead.sumhash_used = 0;
/* Write out the header and create room for the other data structures. */
if (TEMP_FAILURE_RETRY (write (fd, &newhead, sizeof (newhead)))
!= sizeof (newhead))
{
int errval = errno;
unlink (fname);
error (EXIT_FAILURE, errval, _("cannot initialize archive file"));
}
if (ftruncate64 (fd, total) != 0)
{
int errval = errno;
unlink (fname);
error (EXIT_FAILURE, errval, _("cannot resize archive file"));
}
/* Map the header and all the administration data structures. */
p = mmap64 (NULL, total, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED)
{
int errval = errno;
unlink (fname);
error (EXIT_FAILURE, errval, _("cannot map archive header"));
}
/* Lock the new file. */
if (lockf64 (fd, F_LOCK, total) != 0)
{
int errval = errno;
unlink (fname);
error (EXIT_FAILURE, errval, _("cannot lock new archive"));
}
new_ah.len = total;
new_ah.addr = p;
new_ah.fd = fd;
/* Walk through the hash name hash table to find out what data is
still referenced and transfer it into the new file. */
oldnamehashtab = (struct namehashent *) ((char *) ah->addr
+ head->namehash_offset);
oldlocrectab = (struct locrecent *) ((char *) ah->addr
+ head->locrectab_offset);
for (cnt = 0; cnt < head->namehash_size; ++cnt)
if (oldnamehashtab[cnt].locrec_offset != 0)
{
/* Insert this entry in the new hash table. */
locale_data_t old_data;
unsigned int idx;
struct locrecent *oldlocrec;
oldlocrec = (struct locrecent *) ((char *) ah->addr
+ oldnamehashtab[cnt].locrec_offset);
for (idx = 0; idx < __LC_LAST; ++idx)
if (idx != LC_ALL)
{
old_data[idx].size = oldlocrec->record[idx].len;
old_data[idx].addr
= ((char *) ah->addr + oldlocrec->record[idx].offset);
__md5_buffer (old_data[idx].addr, old_data[idx].size,
old_data[idx].sum);
}
if (add_locale_to_archive (&new_ah,
((char *) ah->addr
+ oldnamehashtab[cnt].name_offset),
old_data, 0) != 0)
error (EXIT_FAILURE, 0, _("cannot extend locale archive file"));
}
/* Make the file globally readable. */
if (fchmod (fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) == -1)
{
int errval = errno;
unlink (fname);
error (EXIT_FAILURE, errval,
_("cannot change mode of resized locale archive"));
}
/* Rename the new file. */
if (rename (fname, archivefname) != 0)
{
int errval = errno;
unlink (fname);
error (EXIT_FAILURE, errval, _("cannot rename new archive"));
}
/* Close the old file. */
close_archive (ah);
/* Add the information for the new one. */
*ah = new_ah;
}
void
open_archive (struct locarhandle *ah)
{
struct stat64 st;
struct stat64 st2;
int fd;
struct locarhead head;
int retry = 0;
again:
/* Open the archive. We must have exclusive write access. */
fd = open64 (archivefname, O_RDWR);
if (fd == -1)
{
/* Maybe the file does not yet exist. */
if (errno == ENOENT)
{
create_archive (ah);
return;
}
else
error (EXIT_FAILURE, errno, _("cannot open locale archive \"%s\""),
archivefname);
}
if (fstat64 (fd, &st) < 0)
error (EXIT_FAILURE, errno, _("cannot stat locale archive \"%s\""),
archivefname);
if (lockf64 (fd, F_LOCK, st.st_size) == -1)
{
close (fd);
if (retry++ < max_locarchive_open_retry)
{
struct timespec req;
/* Wait for a bit. */
req.tv_sec = 0;
req.tv_nsec = 1000000 * (random () % 500 + 1);
(void) nanosleep (&req, NULL);
goto again;
}
error (EXIT_FAILURE, errno, _("cannot lock locale archive \"%s\""),
archivefname);
}
/* One more check. Maybe another process replaced the archive file
with a new, larger one since we opened the file. */
if (stat64 (archivefname, &st2) == -1
|| st.st_dev != st2.st_dev
|| st.st_ino != st2.st_ino)
{
close (fd);
goto again;
}
/* Read the header. */
if (TEMP_FAILURE_RETRY (read (fd, &head, sizeof (head))) != sizeof (head))
error (EXIT_FAILURE, errno, _("cannot read archive header"));
ah->fd = fd;
ah->len = (head.sumhash_offset
+ head.sumhash_size * sizeof (struct sumhashent));
/* Now we know how large the administrative information part is.
Map all of it. */
ah->addr = mmap64 (NULL, ah->len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ah->addr == MAP_FAILED)
error (EXIT_FAILURE, errno, _("cannot map archive header"));
}
void
close_archive (struct locarhandle *ah)
{
munmap (ah->addr, ah->len);
close (ah->fd);
}
/* 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;
{
/* 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
we have to allocate a new locale record. */
size_t name_len = strlen (name);
uint32_t file_offsets[__LC_LAST];
unsigned int num_new_offsets = 0;
struct sumhashent *sumhashtab;
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;
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
is already somewhere in the archive. */
for (cnt = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL)
{
/* By default signal that we have no data. */
file_offsets[cnt] = 0;
++num_new_offsets;
/* Compute the hash value of the checksum to determine a
starting point for the search in the MD5 hash value
table. */
hval = compute_hashval (data[cnt].sum, 16);
idx = hval % head->sumhash_size;
incr = 1 + hval % (head->sumhash_size - 2);
while (sumhashtab[idx].file_offset != 0)
{
if (memcmp (data[cnt].sum, sumhashtab[idx].sum, 16) == 0)
{
/* Found it. */
file_offsets[cnt] = sumhashtab[idx].file_offset;
--num_new_offsets;
break;
}
idx += incr;
if (idx >= head->sumhash_size)
idx -= head->sumhash_size;
}
}
/* 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 (! 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];
/* Determine whether we have to resize the file. */
if (100 * (head->sumhash_used + num_new_offsets) > 75 * head->sumhash_size
|| (namehashent->locrec_offset == 0
&& (head->locrectab_used == head->locrectab_size
|| 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);
return add_locale_to_archive (ah, name, data, replace);
}
/* Add the locale data which is not yet in the archive. */
for (cnt = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL && file_offsets[cnt] == 0)
{
/* The data for this section is not yet available in the
archive. Append it. */
off64_t lastpos;
uint32_t md5hval;
lastpos = lseek64 (ah->fd, 0, SEEK_END);
if (lastpos == (off64_t) -1)
error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
/* Align all data to a 16 byte boundary. */
if ((lastpos & 15) != 0)
{
static const char zeros[15] = { 0, };
if (TEMP_FAILURE_RETRY (write (ah->fd, zeros, 16 - (lastpos & 15)))
!= 16 - (lastpos & 15))
error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
lastpos += 16 - (lastpos & 15);
}
/* Remember the position. */
file_offsets[cnt] = lastpos;
/* Write the data. */
if (TEMP_FAILURE_RETRY (write (ah->fd, data[cnt].addr, data[cnt].size))
!= data[cnt].size)
error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
/* Add the hash value to the hash table. */
md5hval = compute_hashval (data[cnt].sum, 16);
idx = md5hval % head->sumhash_size;
incr = 1 + md5hval % (head->sumhash_size - 2);
while (sumhashtab[idx].file_offset != 0)
{
idx += incr;
if (idx >= head->sumhash_size)
idx -= head->sumhash_size;
}
memcpy (sumhashtab[idx].sum, data[cnt].sum, 16);
sumhashtab[idx].file_offset = file_offsets[cnt];
++head->sumhash_used;
}
if (namehashent->locrec_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;
/* Allocate a name location record. */
namehashent->locrec_offset = (head->locrectab_offset
+ (head->locrectab_used++
* sizeof (struct locrecent)));
namehashent->hashval = hval;
++head->namehash_used;
}
/* 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)
{
locrecent->record[cnt].offset = file_offsets[cnt];
locrecent->record[cnt].len = data[cnt].size;
}
/* 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. */
return 0;
}
int
add_locales_to_archive (nlist, list, replace)
size_t nlist;
char *list[];
bool replace;
{
struct locarhandle ah;
int result = 0;
/* Open the archive. This call never returns if we cannot
successfully open the archive. */
open_archive (&ah);
while (nlist-- > 0)
{
const char *fname = *list++;
size_t fnamelen = strlen (fname);
struct stat64 st;
DIR *dirp;
struct dirent64 *d;
int seen;
locale_data_t data;
int cnt;
if (! be_quiet)
printf (_("Adding %s\n"), fname);
/* First see whether this really is a directory and whether it
contains all the require locale category files. */
if (stat64 (fname, &st) < 0)
{
error (0, 0, _("stat of \"%s\" failed: %s: ignored"), fname,
strerror (errno));
continue;
}
if (!S_ISDIR (st.st_mode))
{
error (0, 0, _("\"%s\" is no directory; ignored"), fname);
continue;
}
dirp = opendir (fname);
if (dirp == NULL)
{
error (0, 0, _("cannot open directory \"%s\": %s: ignored"),
fname, strerror (errno));
continue;
}
seen = 0;
while ((d = readdir64 (dirp)) != NULL)
{
for (cnt = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL)
if (strcmp (d->d_name, locnames[cnt]) == 0)
{
unsigned char d_type;
/* We have an object of the required name. If it's
a directory we have to look at a file with the
prefix "SYS_". Otherwise we have found what we
are looking for. */
#ifdef _DIRENT_HAVE_D_TYPE
d_type = d->d_type;
if (d_type != DT_REG)
#endif
{
char fullname[fnamelen + 2 * strlen (d->d_name) + 7];
#ifdef _DIRENT_HAVE_D_TYPE
if (d_type == DT_UNKNOWN)
#endif
{
strcpy (stpcpy (stpcpy (fullname, fname), "/"),
d->d_name);
if (stat64 (fullname, &st) == -1)
/* We cannot stat the file, ignore it. */
break;
d_type = IFTODT (st.st_mode);
}
if (d_type == DT_DIR)
{
/* We have to do more tests. The file is a
directory and it therefore must contain a
regular file with the same name except a
"SYS_" prefix. */
strcpy (stpcpy (stpcpy (stpcpy (stpcpy (fullname,
fname),
"/"),
d->d_name),
"/SYS_"),
d->d_name);
if (stat64 (fullname, &st) == -1)
/* There is no SYS_* file or we cannot
access it. */
break;
d_type = IFTODT (st.st_mode);
}
}
/* If we found a regular file (eventually after
following a symlink) we are successful. */
if (d_type == DT_REG)
++seen;
break;
}
}
closedir (dirp);
if (seen != __LC_LAST - 1)
{
/* We don't have all locale category files. Ignore the name. */
error (0, 0, _("incomplete set of locale files in \"%s\""),
fname);
continue;
}
/* Add the files to the archive. To do this we first compute
sizes and the MD5 sums of all the files. */
for (cnt = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL)
{
char fullname[fnamelen + 2 * strlen (locnames[cnt]) + 7];
int fd;
strcpy (stpcpy (stpcpy (fullname, fname), "/"), locnames[cnt]);
fd = open64 (fullname, O_RDONLY);
if (fd == -1 || fstat64 (fd, &st) == -1)
{
/* Cannot read the file. */
if (fd != -1)
close (fd);
break;
}
if (S_ISDIR (st.st_mode))
{
close (fd);
strcpy (stpcpy (stpcpy (stpcpy (stpcpy (fullname, fname),
"/"),
locnames[cnt]),
"/SYS_"),
locnames[cnt]);
fd = open64 (fullname, O_RDONLY);
if (fd == -1 || fstat64 (fd, &st) == -1
|| !S_ISREG (st.st_mode))
{
if (fd != -1)
close (fd);
break;
}
}
/* Map the file. */
data[cnt].addr = mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED,
fd, 0);
if (data[cnt].addr == MAP_FAILED)
{
/* Cannot map it. */
close (fd);
break;
}
data[cnt].size = st.st_size;
__md5_buffer (data[cnt].addr, st.st_size, data[cnt].sum);
/* We don't need the file descriptor anymore. */
close (fd);
}
if (cnt != __LC_LAST)
{
while (cnt-- > 0)
if (cnt != LC_ALL)
munmap (data[cnt].addr, data[cnt].size);
error (0, 0, _("cannot read all files in \"%s\": ignored"), fname);
continue;
}
result |= add_locale_to_archive (&ah, basename (fname), data, replace);
for (cnt = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL)
munmap (data[cnt].addr, data[cnt].size);
}
/* We are done. */
close_archive (&ah);
return result;
}
int
delete_locales_from_archive (nlist, list)
size_t nlist;
char *list[];
{
struct locarhandle ah;
struct locarhead *head;
struct namehashent *namehashtab;
/* Open the archive. This call never returns if we cannot
successfully open the archive. */
open_archive (&ah);
head = ah.addr;
namehashtab = (struct namehashent *) ((char *) ah.addr
+ head->namehash_offset);
while (nlist-- > 0)
{
const char *locname = *list++;
uint32_t hval;
unsigned int idx;
unsigned int incr;
/* Search for this locale in the archive. */
hval = compute_hashval (locname, strlen (locname));
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 (locname,
(char *) ah.addr + namehashtab[idx].name_offset)
== 0))
{
/* 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;
}
idx += incr;
if (idx >= head->namehash_size)
idx -= head->namehash_size;
}
if (namehashtab[idx].name_offset == 0 && ! be_quiet)
error (0, 0, _("locale \"%s\" not in archive"), locname);
}
close_archive (&ah);
return 0;
}
static int
xstrcmp (const void *a, const void *b)
{
return strcmp (*(const char **) a, *(const char **) b);
}
void
show_archive_content (void)
{
struct locarhandle ah;
struct locarhead *head;
struct namehashent *namehashtab;
int cnt;
char **names;
int used;
/* Open the archive. This call never returns if we cannot
successfully open the archive. */
open_archive (&ah);
head = ah.addr;
names = (char **) xmalloc (head->namehash_used * sizeof (char *));
namehashtab = (struct namehashent *) ((char *) ah.addr
+ head->namehash_offset);
for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
if (namehashtab[cnt].locrec_offset != 0)
{
assert (used < head->namehash_used);
names[used++] = ah.addr + namehashtab[cnt].name_offset;
}
/* Sort the names. */
qsort (names, used, sizeof (char *), xstrcmp);
for (cnt = 0; cnt < used; ++cnt)
puts (names[cnt]);
close_archive (&ah);
exit (EXIT_SUCCESS);
}

View File

@ -30,12 +30,18 @@
#include <sys/param.h>
#include <sys/stat.h>
#include "../../crypt/md5.h"
#include "localedef.h"
#include "locfile.h"
#include "simple-hash.h"
#include "locfile-kw.h"
/* Temporary storage of the locale data before writing it to the archive. */
static locale_data_t to_archive;
int
locfile_read (struct localedef_t *result, const struct charmap_t *charmap)
{
@ -312,9 +318,10 @@ static void (*const write_funcs[]) (struct localedef_t *,
[LC_IDENTIFICATION] = identification_output
};
void
write_all_categories (struct localedef_t *definitions,
const struct charmap_t *charmap,
const struct charmap_t *charmap, const char *locname,
const char *output_path)
{
int cnt;
@ -322,8 +329,25 @@ write_all_categories (struct localedef_t *definitions,
for (cnt = 0; cnt < sizeof (write_funcs) / sizeof (write_funcs[0]); ++cnt)
if (write_funcs[cnt] != NULL)
write_funcs[cnt] (definitions, charmap, output_path);
if (! no_archive)
{
/* The data has to be added to the archive. Do this now. */
struct locarhandle ah;
/* Open the archive. This call never returns if we cannot
successfully open the archive. */
open_archive (&ah);
if (add_locale_to_archive (&ah, locname, to_archive, true) != 0)
error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
/* We are done. */
close_archive (&ah);
}
}
/* Return a NULL terminated list of the directories next to output_path
that have the same owner, group, permissions and device as output_path. */
static const char **
@ -408,6 +432,7 @@ siblings_uncached (const char *output_path)
return elems;
}
/* Return a NULL terminated list of the directories next to output_path
that have the same owner, group, permissions and device as output_path.
Cache the result for future calls. */
@ -434,6 +459,7 @@ siblings (const char *output_path)
return last_result;
}
/* Read as many bytes from a file descriptor as possible. */
static ssize_t
full_read (int fd, void *bufarea, size_t nbyte)
@ -457,6 +483,7 @@ full_read (int fd, void *bufarea, size_t nbyte)
return buf - (char *) bufarea;
}
/* Compare the contents of two regular files of the same size. Return 0
if they are equal, 1 if they are different, or -1 if an error occurs. */
static int
@ -506,9 +533,10 @@ compare_files (const char *filename1, const char *filename2, size_t size,
return ret;
}
/* Write a locale file, with contents given by N_ELEM and VEC. */
void
write_locale_data (const char *output_path, const char *category,
write_locale_data (const char *output_path, int catidx, const char *category,
size_t n_elem, struct iovec *vec)
{
size_t cnt, step, maxiov;
@ -516,6 +544,32 @@ write_locale_data (const char *output_path, const char *category,
char *fname;
const char **other_paths;
if (! no_archive)
{
/* The data will be added to the archive. For now we simply
generate the image which will be written. First determine
the size. */
int cnt;
void *endp;
to_archive[catidx].size = 0;
for (cnt = 0; cnt < n_elem; ++cnt)
to_archive[catidx].size += vec[cnt].iov_len;
/* Allocate the memory for it. */
to_archive[catidx].addr = xmalloc (to_archive[catidx].size);
/* Fill it in. */
for (cnt = 0, endp = to_archive[catidx].addr; cnt < n_elem; ++cnt)
endp = mempcpy (endp, vec[cnt].iov_base, vec[cnt].iov_len);
/* Compute the MD5 sum for the data. */
__md5_buffer (to_archive[catidx].addr, to_archive[catidx].size,
to_archive[catidx].sum);
return;
}
fname = xmalloc (strlen (output_path) + 2 * strlen (category) + 7);
/* Normally we write to the directory pointed to by the OUTPUT_PATH.
@ -680,8 +734,7 @@ failure while writing data for category `%s'"), category));
char * tmp_fname =
(char *) xmalloc (strlen (fname) + 4 + 1);
strcpy (tmp_fname, fname);
strcat (tmp_fname, ".tmp");
strcpy (stpcpy (tmp_fname, fname), ".tmp");
if (link (other_fname, tmp_fname) >= 0)
{

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
/* Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.org>, 1996.
@ -115,11 +115,13 @@ extern void check_all_categories (struct localedef_t *definitions,
/* Write out all locale categories. */
extern void write_all_categories (struct localedef_t *definitions,
const struct charmap_t *charmap,
const char *locname,
const char *output_path);
/* Write out the data. */
extern void write_locale_data (const char *output_path, const char *category,
size_t n_elem, struct iovec *vec);
extern void write_locale_data (const char *output_path, int catidx,
const char *category, size_t n_elem,
struct iovec *vec);
/* Entrypoints for the parsers of the individual categories. */

View File

@ -1,5 +1,5 @@
/* Implement simple hashing table with string based keys.
Copyright (C) 1994-1997, 2000, 2001 Free Software Foundation, Inc.
Copyright (C) 1994-1997, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, October 1994.
@ -54,6 +54,8 @@
# define bcopy(s, d, n) memcpy ((d), (s), (n))
#endif
#include "hashval.h"
extern void *xmalloc (size_t __n);
extern void *xcalloc (size_t __n, size_t __m);
@ -72,7 +74,6 @@ static void insert_entry_2 (hash_table *htab, const void *key, size_t keylen,
unsigned long hval, size_t idx, void *data);
static size_t lookup (const hash_table *htab, const void *key, size_t keylen,
unsigned long int hval);
static unsigned long compute_hashval (const void *key, size_t keylen);
static int is_prime (unsigned long int candidate);
@ -297,30 +298,7 @@ lookup (htab, key, keylen, hval)
}
static unsigned long
compute_hashval (key, keylen)
const void *key;
size_t keylen;
{
size_t cnt;
unsigned long int hval;
/* Compute the hash value for the given string. The algorithm
is taken from [Aho,Sethi,Ullman], modified to reduce the number of
collisions for short strings with very varied bit patterns.
See http://www.clisp.org/haible/hashfunc.html. */
cnt = 0;
hval = keylen;
while (cnt < keylen)
{
hval = (hval << 9) | (hval >> (LONGBITS - 9));
hval += (unsigned long int) *(((char *) key) + cnt++);
}
return hval != 0 ? hval : ~((unsigned long) 0);
}
unsigned long
unsigned long int
next_prime (seed)
unsigned long int seed;
{

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001 Free Software Foundation, Inc.
/* Copyright (C) 1995-1999, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
@ -46,6 +46,8 @@ extern int iterate_table (const hash_table *htab, void **ptr,
const void **key, size_t *keylen, void **data)
__THROW;
extern unsigned long int compute_hashval (const void *key, size_t keylen)
__THROW;
extern unsigned long int next_prime (unsigned long int seed) __THROW;
#endif /* simple-hash.h */