diff options
Diffstat (limited to 'locale')
-rw-r--r-- | locale/Makefile | 9 | ||||
-rw-r--r-- | locale/hashval.h | 41 | ||||
-rw-r--r-- | locale/locarchive.h | 97 | ||||
-rw-r--r-- | locale/programs/ld-address.c | 2 | ||||
-rw-r--r-- | locale/programs/ld-collate.c | 4 | ||||
-rw-r--r-- | locale/programs/ld-ctype.c | 3 | ||||
-rw-r--r-- | locale/programs/ld-identification.c | 3 | ||||
-rw-r--r-- | locale/programs/ld-measurement.c | 2 | ||||
-rw-r--r-- | locale/programs/ld-messages.c | 2 | ||||
-rw-r--r-- | locale/programs/ld-monetary.c | 2 | ||||
-rw-r--r-- | locale/programs/ld-name.c | 2 | ||||
-rw-r--r-- | locale/programs/ld-numeric.c | 2 | ||||
-rw-r--r-- | locale/programs/ld-paper.c | 2 | ||||
-rw-r--r-- | locale/programs/ld-telephone.c | 2 | ||||
-rw-r--r-- | locale/programs/ld-time.c | 2 | ||||
-rw-r--r-- | locale/programs/localedef.c | 95 | ||||
-rw-r--r-- | locale/programs/localedef.h | 28 | ||||
-rw-r--r-- | locale/programs/locarchive.c | 931 | ||||
-rw-r--r-- | locale/programs/locfile.c | 61 | ||||
-rw-r--r-- | locale/programs/locfile.h | 8 | ||||
-rw-r--r-- | locale/programs/simple-hash.c | 30 | ||||
-rw-r--r-- | locale/programs/simple-hash.h | 4 |
22 files changed, 1268 insertions, 64 deletions
diff --git a/locale/Makefile b/locale/Makefile index 03ed1b66fa..7a773f104f 100644 --- a/locale/Makefile +++ b/locale/Makefile @@ -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 diff --git a/locale/hashval.h b/locale/hashval.h new file mode 100644 index 0000000000..15ec1244cf --- /dev/null +++ b/locale/hashval.h @@ -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); +} diff --git a/locale/locarchive.h b/locale/locarchive.h new file mode 100644 index 0000000000..2005989598 --- /dev/null +++ b/locale/locarchive.h @@ -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 */ diff --git a/locale/programs/ld-address.c b/locale/programs/ld-address.c index 52b91cfc28..5c8efaa282 100644 --- a/locale/programs/ld-address.c +++ b/locale/programs/ld-address.c @@ -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); } diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c index 191194799d..ca58266839 100644 --- a/locale/programs/ld-collate.c +++ b/locale/programs/ld-collate.c @@ -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); diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c index 1026133dc2..eed2e94732 100644 --- a/locale/programs/ld-ctype.c +++ b/locale/programs/ld-ctype.c @@ -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); } diff --git a/locale/programs/ld-identification.c b/locale/programs/ld-identification.c index 481e4e79c4..ae5ea6fb16 100644 --- a/locale/programs/ld-identification.c +++ b/locale/programs/ld-identification.c @@ -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); } diff --git a/locale/programs/ld-measurement.c b/locale/programs/ld-measurement.c index 75219bdf9f..2aa75b47dc 100644 --- a/locale/programs/ld-measurement.c +++ b/locale/programs/ld-measurement.c @@ -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); } diff --git a/locale/programs/ld-messages.c b/locale/programs/ld-messages.c index fadf82757f..d5cc393e4b 100644 --- a/locale/programs/ld-messages.c +++ b/locale/programs/ld-messages.c @@ -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); } diff --git a/locale/programs/ld-monetary.c b/locale/programs/ld-monetary.c index 4bb7c0bba4..4c36c505ba 100644 --- a/locale/programs/ld-monetary.c +++ b/locale/programs/ld-monetary.c @@ -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); } diff --git a/locale/programs/ld-name.c b/locale/programs/ld-name.c index 11e0ace7d6..80b42f7048 100644 --- a/locale/programs/ld-name.c +++ b/locale/programs/ld-name.c @@ -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); } diff --git a/locale/programs/ld-numeric.c b/locale/programs/ld-numeric.c index 6e385f2be6..594c0c8c1b 100644 --- a/locale/programs/ld-numeric.c +++ b/locale/programs/ld-numeric.c @@ -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); } diff --git a/locale/programs/ld-paper.c b/locale/programs/ld-paper.c index 2dce9ca8da..2910954f04 100644 --- a/locale/programs/ld-paper.c +++ b/locale/programs/ld-paper.c @@ -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); } diff --git a/locale/programs/ld-telephone.c b/locale/programs/ld-telephone.c index 01dcf36008..5a60c016b0 100644 --- a/locale/programs/ld-telephone.c +++ b/locale/programs/ld-telephone.c @@ -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); } diff --git a/locale/programs/ld-time.c b/locale/programs/ld-time.c index 32d9dad971..2ff56b0034 100644 --- a/locale/programs/ld-time.c +++ b/locale/programs/ld-time.c @@ -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); } diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c index 3c159560e9..526f2025e7 100644 --- a/locale/programs/localedef.c +++ b/locale/programs/localedef.c @@ -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; diff --git a/locale/programs/localedef.h b/locale/programs/localedef.h index 717962e10b..9567845080 100644 --- a/locale/programs/localedef.h +++ b/locale/programs/localedef.h @@ -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 <errno.h> #include <locale.h> +#include <stdbool.h> #include <stddef.h> -#include <errno.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 */ diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c new file mode 100644 index 0000000000..861dd5bd68 --- /dev/null +++ b/locale/programs/locarchive.c @@ -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); +} diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c index 07a65bbb54..4d978d12a1 100644 --- a/locale/programs/locfile.c +++ b/locale/programs/locfile.c @@ -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) { diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h index 4f6c8fee3e..2e96c62ec7 100644 --- a/locale/programs/locfile.h +++ b/locale/programs/locfile.h @@ -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. */ diff --git a/locale/programs/simple-hash.c b/locale/programs/simple-hash.c index e501038a1a..b52b5593d0 100644 --- a/locale/programs/simple-hash.c +++ b/locale/programs/simple-hash.c @@ -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; { diff --git a/locale/programs/simple-hash.h b/locale/programs/simple-hash.h index b811a6fd4d..469caedc19 100644 --- a/locale/programs/simple-hash.h +++ b/locale/programs/simple-hash.h @@ -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 */ |