1 /* Copyright (C) 2000, 2001, 2002, 2003, 2005, 2007
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
33 #include "localedef.h"
34 #include "charmap-dir.h"
36 /* The data type of a charmap directory being traversed. */
40 /* The directory pathname, ending in a slash. */
43 /* Scratch area used for returning pathnames. */
48 /* Starts a charmap directory traversal.
49 Returns a CHARMAP_DIR, or NULL if the directory doesn't exist. */
51 charmap_opendir (const char *directory)
53 struct charmap_dir *cdir;
58 dir = opendir (directory);
61 WITH_CUR_LOCALE (error (1, errno, gettext ("\
62 cannot read character map directory `%s'"), directory));
66 cdir = (struct charmap_dir *) xmalloc (sizeof (struct charmap_dir));
69 len = strlen (directory);
70 add_slash = (len == 0 || directory[len - 1] != '/');
71 cdir->directory = (char *) xmalloc (len + add_slash + 1);
72 memcpy (cdir->directory, directory, len);
74 cdir->directory[len] = '/';
75 cdir->directory[len + add_slash] = '\0';
76 cdir->directory_len = len + add_slash;
78 cdir->pathname = NULL;
79 cdir->pathname_size = 0;
84 /* Reads the next directory entry.
85 Returns its charmap name, or NULL if past the last entry or upon error.
86 The storage returned may be overwritten by a later charmap_readdir
87 call on the same CHARMAP_DIR. */
89 charmap_readdir (CHARMAP_DIR *cdir)
93 struct dirent64 *dirent;
99 dirent = readdir64 (cdir->dir);
102 if (strcmp (dirent->d_name, ".") == 0)
104 if (strcmp (dirent->d_name, "..") == 0)
107 len = strlen (dirent->d_name);
109 size = cdir->directory_len + len + 1;
110 if (size > cdir->pathname_size)
112 free (cdir->pathname);
113 if (size < 2 * cdir->pathname_size)
114 size = 2 * cdir->pathname_size;
115 cdir->pathname = (char *) xmalloc (size);
116 cdir->pathname_size = size;
119 stpcpy (stpcpy (cdir->pathname, cdir->directory), dirent->d_name);
120 filename = cdir->pathname + cdir->directory_len;
122 #ifdef _DIRENT_HAVE_D_TYPE
123 if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK)
124 mode = DTTOIF (dirent->d_type);
130 if (stat (cdir->pathname, &statbuf) < 0)
133 mode = statbuf.st_mode;
139 /* For compressed charmaps, the canonical charmap name does not
140 include the extension. */
141 if (len > 3 && memcmp (&filename[len - 3], ".gz", 3) == 0)
142 filename[len - 3] = '\0';
143 else if (len > 4 && memcmp (&filename[len - 4], ".bz2", 4) == 0)
144 filename[len - 4] = '\0';
150 /* Finishes a charmap directory traversal, and frees the resources
151 attached to the CHARMAP_DIR. */
153 charmap_closedir (CHARMAP_DIR *cdir)
155 DIR *dir = cdir->dir;
157 free (cdir->directory);
158 free (cdir->pathname);
160 return closedir (dir);
163 #ifndef NO_UNCOMPRESS
164 /* Creates a subprocess decompressing the given pathname, and returns
165 a stream reading its output (the decompressed data). */
168 fopen_uncompressed (const char *pathname, const char *compressor)
172 pfd = open (pathname, O_RDONLY);
178 if (fstat (pfd, &statbuf) >= 0
179 && S_ISREG (statbuf.st_mode)
183 = { (char *) compressor, (char *) "-d", (char *) "-c", NULL };
184 posix_spawn_file_actions_t actions;
186 if (posix_spawn_file_actions_init (&actions) == 0)
188 if (posix_spawn_file_actions_adddup2 (&actions,
189 fd[1], STDOUT_FILENO) == 0
190 && posix_spawn_file_actions_addclose (&actions, fd[1]) == 0
191 && posix_spawn_file_actions_addclose (&actions, fd[0]) == 0
192 && posix_spawn_file_actions_adddup2 (&actions,
193 pfd, STDIN_FILENO) == 0
194 && posix_spawn_file_actions_addclose (&actions, pfd) == 0
195 && posix_spawnp (NULL, compressor, &actions, NULL,
198 posix_spawn_file_actions_destroy (&actions);
201 return fdopen (fd[0], "r");
203 posix_spawn_file_actions_destroy (&actions);
214 /* Opens a charmap for reading, given its name (not an alias name). */
216 charmap_open (const char *directory, const char *name)
218 size_t dlen = strlen (directory);
219 int add_slash = (dlen == 0 || directory[dlen - 1] != '/');
220 size_t nlen = strlen (name);
225 pathname = alloca (dlen + add_slash + nlen + 5);
226 p = stpcpy (pathname, directory);
229 p = stpcpy (p, name);
231 stream = fopen (pathname, "rm");
235 #ifndef NO_UNCOMPRESS
236 memcpy (p, ".gz", 4);
237 stream = fopen_uncompressed (pathname, "gzip");
241 memcpy (p, ".bz2", 5);
242 stream = fopen_uncompressed (pathname, "bzip2");
250 /* An empty alias list. Avoids the need to return NULL from
252 static char *empty[1];
254 /* Returns a NULL terminated list of alias names of a charmap. */
256 charmap_aliases (const char *directory, const char *name)
262 stream = charmap_open (directory, name);
269 while (!feof (stream))
274 if (fscanf (stream, " <code_set_name> %as", &alias) == 1
275 || fscanf (stream, "%% alias %as", &alias) == 1)
277 aliases = (char **) xrealloc (aliases,
278 (naliases + 2) * sizeof (char *));
279 aliases[naliases++] = alias;
282 /* Read the rest of the line. */
283 if (fgets (junk, sizeof junk, stream) != NULL)
285 if (strstr (junk, "CHARMAP") != NULL)
286 /* We cannot expect more aliases from now on. */
289 while (strchr (junk, '\n') == NULL
290 && fgets (junk, sizeof junk, stream) != NULL)
300 aliases[naliases] = NULL;
304 /* Frees an alias list returned by charmap_aliases. */
306 charmap_free_aliases (char **aliases)
308 if (aliases != empty)
312 for (p = aliases; *p; p++)