summaryrefslogtreecommitdiff
path: root/REORG.TODO/locale/programs/charmap-dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/locale/programs/charmap-dir.c')
-rw-r--r--REORG.TODO/locale/programs/charmap-dir.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/REORG.TODO/locale/programs/charmap-dir.c b/REORG.TODO/locale/programs/charmap-dir.c
new file mode 100644
index 0000000000..e55ab86e28
--- /dev/null
+++ b/REORG.TODO/locale/programs/charmap-dir.c
@@ -0,0 +1,309 @@
+/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "localedef.h"
+#include "charmap-dir.h"
+
+/* 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)
+ {
+ WITH_CUR_LOCALE (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 dirent64 *dirent;
+ size_t len;
+ size_t size;
+ char *filename;
+ mode_t mode;
+
+ dirent = readdir64 (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 stat64 statbuf;
+
+ if (stat64 (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, const char *compressor)
+{
+ int pfd;
+
+ pfd = open (pathname, O_RDONLY);
+ if (pfd >= 0)
+ {
+ struct stat64 statbuf;
+ int fd[2];
+
+ if (fstat64 (pfd, &statbuf) >= 0
+ && S_ISREG (statbuf.st_mode)
+ && pipe (fd) >= 0)
+ {
+ char *argv[4]
+ = { (char *) compressor, (char *) "-d", (char *) "-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, "rm");
+ 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, " <code_set_name> %ms", &alias) == 1
+ || fscanf (stream, "%% alias %ms", &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);
+ }
+}