1 /* Copyright (C) 2000 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
31 #include "charmap-dir.h"
33 extern void *xmalloc (size_t n
);
34 extern void *xrealloc (void *p
, size_t n
);
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 error (1, errno
, gettext ("cannot read character map directory `%s'"),
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 dirent
*dirent
;
99 dirent
= readdir (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 /* Creates a subprocess decompressing the given pathname, and returns
164 a stream reading its output (the decompressed data). */
167 fopen_uncompressed (const char *pathname
, char *compressor
)
171 pfd
= open (pathname
, O_RDONLY
);
177 if (fstat (pfd
, &statbuf
) >= 0
178 && S_ISREG (statbuf
.st_mode
)
181 char *argv
[4] = { compressor
, "-d", "-c", NULL
};
182 posix_spawn_file_actions_t actions
;
184 if (posix_spawn_file_actions_init (&actions
) == 0)
186 if (posix_spawn_file_actions_adddup2 (&actions
,
187 fd
[1], STDOUT_FILENO
) == 0
188 && posix_spawn_file_actions_addclose (&actions
, fd
[1]) == 0
189 && posix_spawn_file_actions_addclose (&actions
, fd
[0]) == 0
190 && posix_spawn_file_actions_adddup2 (&actions
,
191 pfd
, STDIN_FILENO
) == 0
192 && posix_spawn_file_actions_addclose (&actions
, pfd
) == 0
193 && posix_spawnp (NULL
, compressor
, &actions
, NULL
,
196 posix_spawn_file_actions_destroy (&actions
);
199 return fdopen (fd
[0], "r");
201 posix_spawn_file_actions_destroy (&actions
);
211 /* Opens a charmap for reading, given its name (not an alias name). */
213 charmap_open (const char *directory
, const char *name
)
215 size_t dlen
= strlen (directory
);
216 int add_slash
= (dlen
== 0 || directory
[dlen
- 1] != '/');
217 size_t nlen
= strlen (name
);
222 pathname
= alloca (dlen
+ add_slash
+ nlen
+ 5);
223 p
= stpcpy (pathname
, directory
);
226 p
= stpcpy (p
, name
);
228 stream
= fopen (pathname
, "r");
232 memcpy (p
, ".gz", 4);
233 stream
= fopen_uncompressed (pathname
, "gzip");
237 memcpy (p
, ".bz2", 5);
238 stream
= fopen_uncompressed (pathname
, "bzip2");
245 /* An empty alias list. Avoids the need to return NULL from
247 static char *empty
[1];
249 /* Returns a NULL terminated list of alias names of a charmap. */
251 charmap_aliases (const char *directory
, const char *name
)
257 stream
= charmap_open (directory
, name
);
264 while (!feof (stream
))
269 if (fscanf (stream
, " <code_set_name> %as", &alias
) == 1
270 || fscanf (stream
, "%% alias %as", &alias
) == 1)
272 aliases
= (char **) xrealloc (aliases
,
273 (naliases
+ 2) * sizeof (char *));
274 aliases
[naliases
++] = alias
;
277 /* Read the rest of the line. */
278 if (fgets (junk
, sizeof junk
, stream
) != NULL
)
280 if (strstr (junk
, "CHARMAP") != NULL
)
281 /* We cannot expect more aliases from now on. */
284 while (strchr (junk
, '\n') == NULL
285 && fgets (junk
, sizeof junk
, stream
) != NULL
)
295 aliases
[naliases
] = NULL
;
299 /* Frees an alias list returned by charmap_aliases. */
301 charmap_free_aliases (char **aliases
)
303 if (aliases
!= empty
)
307 for (p
= aliases
; *p
; p
++)