From 3e07621988521feb5cdd8a99760d8bad1707cb57 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sun, 1 Oct 2000 19:15:29 +0000 Subject: Update. 2000-10-01 Bruno Haible * charmaps/BIG5: Add a width table. * charmaps/GB18030: Likewise. * charmaps/ISO-8859-6: Likewise. * charmaps/ISO-8859-8: Likewise. * charmaps/TIS-620: Likewise. --- locale/Makefile | 5 +- locale/programs/charmap-dir.c | 312 ++++++++++++++++++++++++++++++++++++++++++ locale/programs/charmap-dir.h | 48 +++++++ locale/programs/charmap.c | 142 +++++++++---------- locale/programs/linereader.c | 14 +- locale/programs/linereader.h | 3 +- locale/programs/locale.c | 110 +++++---------- 7 files changed, 471 insertions(+), 163 deletions(-) create mode 100644 locale/programs/charmap-dir.c create mode 100644 locale/programs/charmap-dir.h (limited to 'locale') diff --git a/locale/Makefile b/locale/Makefile index 2b278d5..a5abf54 100644 --- a/locale/Makefile +++ b/locale/Makefile @@ -33,7 +33,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) + 3level.h charmap-dir.h) routines = setlocale findlocale loadlocale localeconv nl_langinfo \ nl_langinfo_l mb_cur_max codeset_name \ newlocale duplocale freelocale @@ -59,7 +59,7 @@ vpath %.gperf programs localedef-modules := $(categories:%=ld-%) charmap linereader locfile \ repertoire locale-modules := locale-spec -lib-modules := simple-hash xmalloc xstrdup +lib-modules := charmap-dir simple-hash xmalloc xstrdup GPERF = gperf @@ -94,6 +94,7 @@ locale-CPPFLAGS := -DLOCALE_PATH='$(localepath)' \ CFLAGS-charmap.c = -Wno-write-strings -Wno-char-subscripts CFLAGS-locfile.c = -Wno-write-strings -Wno-char-subscripts +CFLAGS-charmap-dir.c = -Wno-write-strings # Depend on libc.so so a DT_NEEDED is generated in the shared objects. # This ensures they will load libc.so for needed symbols if loaded by diff --git a/locale/programs/charmap-dir.c b/locale/programs/charmap-dir.c new file mode 100644 index 0000000..a1eb843 --- /dev/null +++ b/locale/programs/charmap-dir.c @@ -0,0 +1,312 @@ +/* Copyright (C) 2000 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "charmap-dir.h" + +extern void *xmalloc (size_t n); +extern void *xrealloc (void *p, size_t n); + +/* The data type of a charmap directory being traversed. */ +struct charmap_dir +{ + DIR *dir; + /* The directory pathname, ending in a slash. */ + char *directory; + size_t directory_len; + /* Scratch area used for returning pathnames. */ + char *pathname; + size_t pathname_size; +}; + +/* Starts a charmap directory traversal. + Returns a CHARMAP_DIR, or NULL if the directory doesn't exist. */ +CHARMAP_DIR * +charmap_opendir (const char *directory) +{ + struct charmap_dir *cdir; + DIR *dir; + size_t len; + int add_slash; + + dir = opendir (directory); + if (dir == NULL) + { + error (1, errno, gettext ("cannot read character map directory `%s'"), + directory); + return NULL; + } + + cdir = (struct charmap_dir *) xmalloc (sizeof (struct charmap_dir)); + cdir->dir = dir; + + len = strlen (directory); + add_slash = (len == 0 || directory[len - 1] != '/'); + cdir->directory = (char *) xmalloc (len + add_slash + 1); + memcpy (cdir->directory, directory, len); + if (add_slash) + cdir->directory[len] = '/'; + cdir->directory[len + add_slash] = '\0'; + cdir->directory_len = len + add_slash; + + cdir->pathname = NULL; + cdir->pathname_size = 0; + + return cdir; +} + +/* Reads the next directory entry. + Returns its charmap name, or NULL if past the last entry or upon error. + The storage returned may be overwritten by a later charmap_readdir + call on the same CHARMAP_DIR. */ +const char * +charmap_readdir (CHARMAP_DIR *cdir) +{ + for (;;) + { + struct dirent *dirent; + size_t len; + size_t size; + char *filename; + mode_t mode; + + dirent = readdir (cdir->dir); + if (dirent == NULL) + return NULL; + if (strcmp (dirent->d_name, ".") == 0) + continue; + if (strcmp (dirent->d_name, "..") == 0) + continue; + + len = strlen (dirent->d_name); + + size = cdir->directory_len + len + 1; + if (size > cdir->pathname_size) + { + free (cdir->pathname); + if (size < 2 * cdir->pathname_size) + size = 2 * cdir->pathname_size; + cdir->pathname = (char *) xmalloc (size); + cdir->pathname_size = size; + } + + stpcpy (stpcpy (cdir->pathname, cdir->directory), dirent->d_name); + filename = cdir->pathname + cdir->directory_len; + +#ifdef _DIRENT_HAVE_D_TYPE + if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK) + mode = DTTOIF (dirent->d_type); + else +#endif + { + struct stat statbuf; + + if (stat (cdir->pathname, &statbuf) < 0) + continue; + + mode = statbuf.st_mode; + } + + if (!S_ISREG (mode)) + continue; + + /* For compressed charmaps, the canonical charmap name does not + include the extension. */ + if (len > 3 && memcmp (&filename[len - 3], ".gz", 3) == 0) + filename[len - 3] = '\0'; + else if (len > 4 && memcmp (&filename[len - 4], ".bz2", 4) == 0) + filename[len - 4] = '\0'; + + return filename; + } +} + +/* Finishes a charmap directory traversal, and frees the resources + attached to the CHARMAP_DIR. */ +int +charmap_closedir (CHARMAP_DIR *cdir) +{ + DIR *dir = cdir->dir; + + free (cdir->directory); + free (cdir->pathname); + free (cdir); + return closedir (dir); +} + +/* Creates a subprocess decompressing the given pathname, and returns + a stream reading its output (the decompressed data). */ +static +FILE * +fopen_uncompressed (const char *pathname, char *compressor) +{ + int pfd; + + pfd = open (pathname, O_RDONLY); + if (pfd >= 0) + { + struct stat statbuf; + int fd[2]; + + if (fstat (pfd, &statbuf) >= 0 + && S_ISREG (statbuf.st_mode) + && pipe (fd) >= 0) + { + char *argv[4] = { compressor, "-d", "-c", NULL }; + posix_spawn_file_actions_t actions; + + if (posix_spawn_file_actions_init (&actions) == 0) + { + if (posix_spawn_file_actions_adddup2 (&actions, + fd[1], STDOUT_FILENO) == 0 + && posix_spawn_file_actions_addclose (&actions, fd[1]) == 0 + && posix_spawn_file_actions_addclose (&actions, fd[0]) == 0 + && posix_spawn_file_actions_adddup2 (&actions, + pfd, STDIN_FILENO) == 0 + && posix_spawn_file_actions_addclose (&actions, pfd) == 0 + && posix_spawnp (NULL, compressor, &actions, NULL, + argv, environ) == 0) + { + posix_spawn_file_actions_destroy (&actions); + close (fd[1]); + close (pfd); + return fdopen (fd[0], "r"); + } + posix_spawn_file_actions_destroy (&actions); + } + close (fd[1]); + close (fd[0]); + } + close (pfd); + } + return NULL; +} + +/* Opens a charmap for reading, given its name (not an alias name). */ +FILE * +charmap_open (const char *directory, const char *name) +{ + size_t dlen = strlen (directory); + int add_slash = (dlen == 0 || directory[dlen - 1] != '/'); + size_t nlen = strlen (name); + char *pathname; + char *p; + FILE *stream; + + pathname = alloca (dlen + add_slash + nlen + 5); + p = stpcpy (pathname, directory); + if (add_slash) + *p++ = '/'; + p = stpcpy (p, name); + + stream = fopen (pathname, "r"); + if (stream != NULL) + return stream; + + memcpy (p, ".gz", 4); + stream = fopen_uncompressed (pathname, "gzip"); + if (stream != NULL) + return stream; + + memcpy (p, ".bz2", 5); + stream = fopen_uncompressed (pathname, "bzip2"); + if (stream != NULL) + return stream; + + return NULL; +} + +/* An empty alias list. Avoids the need to return NULL from + charmap_aliases. */ +static char *empty[1]; + +/* Returns a NULL terminated list of alias names of a charmap. */ +char ** +charmap_aliases (const char *directory, const char *name) +{ + FILE *stream; + char **aliases; + size_t naliases; + + stream = charmap_open (directory, name); + if (stream == NULL) + return empty; + + aliases = NULL; + naliases = 0; + + while (!feof (stream)) + { + char *alias = NULL; + char junk[BUFSIZ]; + + if (fscanf (stream, " %as", &alias) == 1 + || fscanf (stream, "%% alias %as", &alias) == 1) + { + aliases = (char **) xrealloc (aliases, + (naliases + 2) * sizeof (char *)); + aliases[naliases++] = alias; + } + + /* Read the rest of the line. */ + if (fgets (junk, sizeof junk, stream) != NULL) + { + if (strstr (junk, "CHARMAP") != NULL) + /* We cannot expect more aliases from now on. */ + break; + + while (strchr (junk, '\n') == NULL + && fgets (junk, sizeof junk, stream) != NULL) + continue; + } + } + + fclose (stream); + + if (naliases == 0) + return empty; + + aliases[naliases] = NULL; + return aliases; +} + +/* Frees an alias list returned by charmap_aliases. */ +void +charmap_free_aliases (char **aliases) +{ + if (aliases != empty) + { + char **p; + + for (p = aliases; *p; p++) + free (*p); + + free (aliases); + } +} diff --git a/locale/programs/charmap-dir.h b/locale/programs/charmap-dir.h new file mode 100644 index 0000000..ac19624 --- /dev/null +++ b/locale/programs/charmap-dir.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2000 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _CHARMAP_DIR_H +#define _CHARMAP_DIR_H 1 + +/* The data type of a charmap directory being traversed. */ +typedef struct charmap_dir CHARMAP_DIR; + +/* Starts a charmap directory traversal. + Returns a CHARMAP_DIR, or NULL if the directory doesn't exist. */ +extern CHARMAP_DIR *charmap_opendir (const char *directory); + +/* Reads the next directory entry. + Returns its charmap name, or NULL if past the last entry or upon error. + The storage returned may be overwritten by a later charmap_readdir + call on the same CHARMAP_DIR. */ +extern const char *charmap_readdir (CHARMAP_DIR *dir); + +/* Finishes a charmap directory traversal, and frees the resources + attached to the CHARMAP_DIR. */ +extern int charmap_closedir (CHARMAP_DIR *dir); + +/* Returns a NULL terminated list of alias names of a charmap. */ +extern char **charmap_aliases (const char *directory, const char *name); + +/* Frees an alias list returned by charmap_aliases. */ +extern void charmap_free_aliases (char **aliases); + +/* Opens a charmap for reading, given its name (not an alias name). */ +extern FILE *charmap_open (const char *directory, const char *name); + +#endif /* _CHARMAP_DIR_H */ diff --git a/locale/programs/charmap.c b/locale/programs/charmap.c index b8e994f..776d6ff 100644 --- a/locale/programs/charmap.c +++ b/locale/programs/charmap.c @@ -22,18 +22,17 @@ #endif #include -#include #include #include #include #include #include #include -#include #include "error.h" #include "linereader.h" #include "charmap.h" +#include "charmap-dir.h" #include "locfile.h" #include "repertoire.h" @@ -55,6 +54,31 @@ static void charmap_new_char (struct linereader *lr, struct charmap_t *cm, int nbytes, char *bytes, const char *from, const char *to, int decimal_ellipsis, int step); +static struct linereader * +cmlr_open (const char *directory, const char *name, kw_hash_fct_t hf) +{ + FILE *fp; + + fp = charmap_open (directory, name); + if (fp == NULL) + return NULL; + else + { + size_t dlen = strlen (directory); + int add_slash = (dlen == 0 || directory[dlen - 1] != '/'); + size_t nlen = strlen (name); + char *pathname; + char *p; + + pathname = alloca (dlen + add_slash + nlen + 1); + p = stpcpy (pathname, directory); + if (add_slash) + *p++ = '/'; + stpcpy (p, name); + + return lr_create (fp, pathname, hf); + } +} struct charmap_t * charmap_read (const char *filename) @@ -76,26 +100,20 @@ charmap_read (const char *filename) char *i18npath = getenv ("I18NPATH"); if (i18npath != NULL && *i18npath != '\0') { - char path[strlen (filename) + 1 + strlen (i18npath) - + sizeof ("/charmaps/") - 1]; + char path[strlen (i18npath) + sizeof ("/charmaps")]; char *next; i18npath = strdupa (i18npath); - while (cmfile == NULL && (next = strsep (&i18npath, ":")) != NULL) { - stpcpy (stpcpy (stpcpy (path, next), "/charmaps/"), - filename); - - cmfile = lr_open (path, charmap_hash); + stpcpy (stpcpy (path, next), "/charmaps"); + cmfile = cmlr_open (path, filename, charmap_hash); if (cmfile == NULL) { /* Try without the "/charmaps" part. */ - stpcpy (stpcpy (path, next), filename); - - cmfile = lr_open (path, charmap_hash); + cmfile = cmlr_open (next, filename, charmap_hash); } } } @@ -103,10 +121,7 @@ charmap_read (const char *filename) if (cmfile == NULL) { /* Try the default directory. */ - char path[sizeof (CHARMAP_PATH) + strlen (filename) + 1]; - - stpcpy (stpcpy (stpcpy (path, CHARMAP_PATH), "/"), filename); - cmfile = lr_open (path, charmap_hash); + cmfile = cmlr_open (CHARMAP_PATH, filename, charmap_hash); } } } @@ -125,73 +140,42 @@ charmap_read (const char *filename) /* OK, one more try. We also accept the names given to the character sets in the files. Sometimes they differ from the file name. */ - DIR *dir; - struct dirent *dirent; + CHARMAP_DIR *dir; - dir = opendir (CHARMAP_PATH); + dir = charmap_opendir (CHARMAP_PATH); if (dir != NULL) { - while ((dirent = readdir (dir)) != NULL) - if (strcmp (dirent->d_name, ".") != 0 - && strcmp (dirent->d_name, "..") != 0) - { - char buf[sizeof (CHARMAP_PATH) - + strlen (dirent->d_name) + 1]; - FILE *fp; -#ifdef _DIRENT_HAVE_D_TYPE - if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_REG) - continue; -#endif - stpcpy (stpcpy (stpcpy (buf, CHARMAP_PATH), "/"), - dirent->d_name); + const char *dirent; - fp = fopen (buf, "r"); - if (fp != NULL) + while ((dirent = charmap_readdir (dir)) != NULL) + { + char **aliases; + char **p; + int found; + + aliases = charmap_aliases (CHARMAP_PATH, dirent); + found = 0; + for (p = aliases; *p; p++) + if (strcasecmp (*p, filename) == 0) { - char *name = NULL; - - while (!feof (fp)) - { - char junk[BUFSIZ]; - - if (fscanf (fp, " %as", &name) == 1 - || fscanf (fp, "%% alias %as", &name) == 1) - { - if (strcasecmp (name, filename) == 0) - break; - - free (name); - name = NULL; - } - - if (fgets (junk, sizeof junk, fp) != NULL) - { - if (strstr (junk, "CHARMAP") != NULL) - /* We cannot expect more aliases from now on. */ - break; - - while (strchr (junk, '\n') == NULL - && fgets (junk, sizeof junk, fp) != NULL) - continue; - } - } - - fclose (fp); - - if (name != NULL) - { - struct linereader *cmfile; - - cmfile = lr_open (buf, charmap_hash); - result = (cmfile == NULL - ? NULL : parse_charmap (cmfile)); - - break; - } + found = 1; + break; } - } + charmap_free_aliases (aliases); + + if (found) + { + struct linereader *cmfile; + + cmfile = cmlr_open (CHARMAP_PATH, dirent, charmap_hash); + if (cmfile != NULL) + result = parse_charmap (cmfile); - closedir (dir); + break; + } + } + + charmap_closedir (dir); } } @@ -199,9 +183,9 @@ charmap_read (const char *filename) { struct linereader *cmfile; - cmfile = lr_open (CHARMAP_PATH "/" DEFAULT_CHARMAP, charmap_hash); - - result = cmfile == NULL ? NULL : parse_charmap (cmfile); + cmfile = cmlr_open (CHARMAP_PATH, DEFAULT_CHARMAP, charmap_hash); + if (cmfile != NULL) + result = parse_charmap (cmfile); if (result == NULL) error (4, errno, _("default character map file `%s' not found"), diff --git a/locale/programs/linereader.c b/locale/programs/linereader.c index 6237094..3638ba1 100644 --- a/locale/programs/linereader.c +++ b/locale/programs/linereader.c @@ -47,23 +47,29 @@ struct linereader * lr_open (const char *fname, kw_hash_fct_t hf) { FILE *fp; - struct linereader *result; - int n; if (fname == NULL || strcmp (fname, "-") == 0 || strcmp (fname, "/dev/stdin") == 0) - fp = stdin; + return lr_create (stdin, "", hf); else { fp = fopen (fname, "r"); if (fp == NULL) return NULL; + return lr_create (fp, fname, hf); } +} + +struct linereader * +lr_create (FILE *fp, const char *fname, kw_hash_fct_t hf) +{ + struct linereader *result; + int n; result = (struct linereader *) xmalloc (sizeof (*result)); result->fp = fp; - result->fname = xstrdup (fname ? : ""); + result->fname = xstrdup (fname); result->buf = NULL; result->bufsize = 0; result->lineno = 1; diff --git a/locale/programs/linereader.h b/locale/programs/linereader.h index 1c98f68..77fa61a 100644 --- a/locale/programs/linereader.h +++ b/locale/programs/linereader.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper, . @@ -85,6 +85,7 @@ struct linereader /* Functions defined in linereader.c. */ extern struct linereader *lr_open (const char *fname, kw_hash_fct_t hf); +extern struct linereader *lr_create (FILE *fp, const char *fname, kw_hash_fct_t hf); extern int lr_eof (struct linereader *lr); extern void lr_close (struct linereader *lr); extern int lr_next (struct linereader *lr); diff --git a/locale/programs/locale.c b/locale/programs/locale.c index c37dad8..7a42f1e 100644 --- a/locale/programs/locale.c +++ b/locale/programs/locale.c @@ -35,10 +35,12 @@ #include #include #include -#include #include #include "localeinfo.h" +#include "charmap-dir.h" + +extern char *xstrdup (const char *__str); /* If set print the name of the category. */ @@ -251,7 +253,7 @@ more_help (int key, const char *text, void *input) { case ARGP_KEY_HELP_EXTRA: /* We print some extra information. */ - return strdup (gettext ("\ + return xstrdup (gettext ("\ Report bugs using the `glibcbug' script to .\n")); default: break; @@ -320,7 +322,7 @@ write_locales (void) { mode_t mode; #ifdef _DIRENT_HAVE_D_TYPE - if (dirent->d_type != DT_UNKNOWN) + if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK) mode = DTTOIF (dirent->d_type); else #endif @@ -348,7 +350,7 @@ write_locales (void) "/LC_CTYPE"); if (stat (buf, &st) == 0 && S_ISREG (st.st_mode)) - PUT (strdup (dirent->d_name)); + PUT (xstrdup (dirent->d_name)); } } @@ -425,7 +427,7 @@ write_locales (void) *cp++ = '\0'; /* Add the alias. */ - PUT (strdup (alias)); + PUT (xstrdup (alias)); } } @@ -453,84 +455,38 @@ static void write_charmaps (void) { void *all_data = NULL; - DIR *dir; - struct dirent *dirent; + CHARMAP_DIR *dir; + const char *dirent; - dir = opendir (CHARMAP_PATH); + /* Look for all files in the charmap directory. */ + dir = charmap_opendir (CHARMAP_PATH); if (dir == NULL) - { - error (1, errno, gettext ("cannot read character map directory `%s'"), - CHARMAP_PATH); - return; - } - - /* Now we can look for all files in the directory. */ - while ((dirent = readdir (dir)) != NULL) - if (strcmp (dirent->d_name, ".") != 0 - && strcmp (dirent->d_name, "..") != 0) - { - char *buf = NULL; - mode_t mode; + return; -#ifdef _DIRENT_HAVE_D_TYPE - if (dirent->d_type != DT_UNKNOWN) - mode = DTTOIF (dirent->d_type); - else + while ((dirent = charmap_readdir (dir)) != NULL) + { + char **aliases; + char **p; + + PUT (xstrdup (dirent)); + + aliases = charmap_aliases (CHARMAP_PATH, dirent); + +#if 0 + /* Add the code_set_name and the aliases. */ + for (p = aliases; *p; p++) + PUT (xstrdup (*p)); +#else + /* Add the code_set_name only. Most aliases are obsolete. */ + p = aliases; + if (*p) + PUT (xstrdup (*p)); #endif - { - struct stat st; - - buf = alloca (sizeof (CHARMAP_PATH) + strlen (dirent->d_name) + 1); - - stpcpy (stpcpy (stpcpy (buf, CHARMAP_PATH), "/"), dirent->d_name); - - if (stat (buf, &st) < 0) - continue; - mode = st.st_mode; - } - - if (S_ISREG (mode)) - { - FILE *fp; - - PUT (strdup (dirent->d_name)); - - /* Read the file and learn about the code set name. */ - if (buf == NULL) - { - buf = alloca (sizeof (CHARMAP_PATH) - + strlen (dirent->d_name) + 1); - - stpcpy (stpcpy (stpcpy (buf, CHARMAP_PATH), "/"), - dirent->d_name); - } - fp = fopen (buf, "r"); - if (fp != NULL) - { - char *name = NULL; - - while (!feof (fp)) - { - char junk[BUFSIZ]; - - if (fscanf (fp, " %as", &name) == 1) - break; - - while (fgets (junk, sizeof junk, fp) != NULL - && strchr (junk, '\n') == NULL) - continue; - } - - fclose (fp); - - if (name != NULL) - PUT (name); - } - } - } + charmap_free_aliases (aliases); + } - closedir (dir); + charmap_closedir (dir); twalk (all_data, print_names); } -- cgit v1.1