filesys.c revision 1.1 1 1.1 christos /* $NetBSD: filesys.c,v 1.1 2016/01/14 00:11:29 christos Exp $ */
2 1.1 christos
3 1.1 christos /* filesys.c -- filesystem specific functions.
4 1.1 christos Id: filesys.c,v 1.6 2004/07/30 17:17:40 karl Exp
5 1.1 christos
6 1.1 christos Copyright (C) 1993, 1997, 1998, 2000, 2002, 2003, 2004 Free Software
7 1.1 christos Foundation, Inc.
8 1.1 christos
9 1.1 christos This program is free software; you can redistribute it and/or modify
10 1.1 christos it under the terms of the GNU General Public License as published by
11 1.1 christos the Free Software Foundation; either version 2, or (at your option)
12 1.1 christos any later version.
13 1.1 christos
14 1.1 christos This program is distributed in the hope that it will be useful,
15 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
16 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 1.1 christos GNU General Public License for more details.
18 1.1 christos
19 1.1 christos You should have received a copy of the GNU General Public License
20 1.1 christos along with this program; if not, write to the Free Software
21 1.1 christos Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 1.1 christos
23 1.1 christos Written by Brian Fox (bfox (at) ai.mit.edu). */
24 1.1 christos
25 1.1 christos #include "info.h"
26 1.1 christos
27 1.1 christos #include "tilde.h"
28 1.1 christos #include "filesys.h"
29 1.1 christos
30 1.1 christos /* Local to this file. */
31 1.1 christos static char *info_file_in_path (char *filename, char *path);
32 1.1 christos static char *lookup_info_filename (char *filename);
33 1.1 christos static char *info_absolute_file (char *fname);
34 1.1 christos
35 1.1 christos static void remember_info_filename (char *filename, char *expansion);
36 1.1 christos static void maybe_initialize_infopath (void);
37 1.1 christos
38 1.1 christos typedef struct
39 1.1 christos {
40 1.1 christos char *suffix;
41 1.1 christos char *decompressor;
42 1.1 christos } COMPRESSION_ALIST;
43 1.1 christos
44 1.1 christos static char *info_suffixes[] = {
45 1.1 christos ".info",
46 1.1 christos "-info",
47 1.1 christos "/index",
48 1.1 christos ".inf", /* 8+3 file on filesystem which supports long file names */
49 1.1 christos #ifdef __MSDOS__
50 1.1 christos /* 8+3 file names strike again... */
51 1.1 christos ".in", /* for .inz, .igz etc. */
52 1.1 christos ".i",
53 1.1 christos #endif
54 1.1 christos "",
55 1.1 christos NULL
56 1.1 christos };
57 1.1 christos
58 1.1 christos static COMPRESSION_ALIST compress_suffixes[] = {
59 1.1 christos { ".gz", "gunzip" },
60 1.1 christos { ".bz2", "bunzip2" },
61 1.1 christos { ".z", "gunzip" },
62 1.1 christos { ".Z", "uncompress" },
63 1.1 christos { ".Y", "unyabba" },
64 1.1 christos #ifdef __MSDOS__
65 1.1 christos { "gz", "gunzip" },
66 1.1 christos { "z", "gunzip" },
67 1.1 christos #endif
68 1.1 christos { (char *)NULL, (char *)NULL }
69 1.1 christos };
70 1.1 christos
71 1.1 christos /* The path on which we look for info files. You can initialize this
72 1.1 christos from the environment variable INFOPATH if there is one, or you can
73 1.1 christos call info_add_path () to add paths to the beginning or end of it.
74 1.1 christos You can call zap_infopath () to make the path go away. */
75 1.1 christos char *infopath = (char *)NULL;
76 1.1 christos static int infopath_size = 0;
77 1.1 christos
78 1.1 christos /* Expand the filename in PARTIAL to make a real name for this operating
79 1.1 christos system. This looks in INFO_PATHS in order to find the correct file.
80 1.1 christos If it can't find the file, it returns NULL. */
81 1.1 christos static char *local_temp_filename = (char *)NULL;
82 1.1 christos static int local_temp_filename_size = 0;
83 1.1 christos
84 1.1 christos char *
85 1.1 christos info_find_fullpath (char *partial)
86 1.1 christos {
87 1.1 christos int initial_character;
88 1.1 christos char *temp;
89 1.1 christos
90 1.1 christos filesys_error_number = 0;
91 1.1 christos
92 1.1 christos maybe_initialize_infopath ();
93 1.1 christos
94 1.1 christos if (partial && (initial_character = *partial))
95 1.1 christos {
96 1.1 christos char *expansion;
97 1.1 christos
98 1.1 christos expansion = lookup_info_filename (partial);
99 1.1 christos
100 1.1 christos if (expansion)
101 1.1 christos return (expansion);
102 1.1 christos
103 1.1 christos /* If we have the full path to this file, we still may have to add
104 1.1 christos various extensions to it. I guess we have to stat this file
105 1.1 christos after all. */
106 1.1 christos if (IS_ABSOLUTE (partial))
107 1.1 christos temp = info_absolute_file (partial);
108 1.1 christos else if (initial_character == '~')
109 1.1 christos {
110 1.1 christos expansion = tilde_expand_word (partial);
111 1.1 christos if (IS_ABSOLUTE (expansion))
112 1.1 christos {
113 1.1 christos temp = info_absolute_file (expansion);
114 1.1 christos free (expansion);
115 1.1 christos }
116 1.1 christos else
117 1.1 christos temp = expansion;
118 1.1 christos }
119 1.1 christos else if (initial_character == '.' &&
120 1.1 christos (IS_SLASH (partial[1]) ||
121 1.1 christos (partial[1] == '.' && IS_SLASH (partial[2]))))
122 1.1 christos {
123 1.1 christos if (local_temp_filename_size < 1024)
124 1.1 christos local_temp_filename = (char *)xrealloc
125 1.1 christos (local_temp_filename, (local_temp_filename_size = 1024));
126 1.1 christos #if defined (HAVE_GETCWD)
127 1.1 christos if (!getcwd (local_temp_filename, local_temp_filename_size))
128 1.1 christos #else /* !HAVE_GETCWD */
129 1.1 christos if (!getwd (local_temp_filename))
130 1.1 christos #endif /* !HAVE_GETCWD */
131 1.1 christos {
132 1.1 christos filesys_error_number = errno;
133 1.1 christos return (partial);
134 1.1 christos }
135 1.1 christos
136 1.1 christos strcat (local_temp_filename, "/");
137 1.1 christos strcat (local_temp_filename, partial);
138 1.1 christos temp = info_absolute_file (local_temp_filename); /* try extensions */
139 1.1 christos if (!temp)
140 1.1 christos partial = local_temp_filename;
141 1.1 christos }
142 1.1 christos else
143 1.1 christos temp = info_file_in_path (partial, infopath);
144 1.1 christos
145 1.1 christos if (temp)
146 1.1 christos {
147 1.1 christos remember_info_filename (partial, temp);
148 1.1 christos if (strlen (temp) > (unsigned int) local_temp_filename_size)
149 1.1 christos local_temp_filename = (char *) xrealloc
150 1.1 christos (local_temp_filename,
151 1.1 christos (local_temp_filename_size = (50 + strlen (temp))));
152 1.1 christos strcpy (local_temp_filename, temp);
153 1.1 christos free (temp);
154 1.1 christos return (local_temp_filename);
155 1.1 christos }
156 1.1 christos }
157 1.1 christos return (partial);
158 1.1 christos }
159 1.1 christos
160 1.1 christos /* Scan the list of directories in PATH looking for FILENAME. If we find
161 1.1 christos one that is a regular file, return it as a new string. Otherwise, return
162 1.1 christos a NULL pointer. */
163 1.1 christos static char *
164 1.1 christos info_file_in_path (char *filename, char *path)
165 1.1 christos {
166 1.1 christos struct stat finfo;
167 1.1 christos char *temp_dirname;
168 1.1 christos int statable, dirname_index;
169 1.1 christos
170 1.1 christos /* Reject ridiculous cases up front, to prevent infinite recursion
171 1.1 christos later on. E.g., someone might say "info '(.)foo'"... */
172 1.1 christos if (!*filename || STREQ (filename, ".") || STREQ (filename, ".."))
173 1.1 christos return NULL;
174 1.1 christos
175 1.1 christos dirname_index = 0;
176 1.1 christos
177 1.1 christos while ((temp_dirname = extract_colon_unit (path, &dirname_index)))
178 1.1 christos {
179 1.1 christos register int i, pre_suffix_length;
180 1.1 christos char *temp;
181 1.1 christos
182 1.1 christos /* Expand a leading tilde if one is present. */
183 1.1 christos if (*temp_dirname == '~')
184 1.1 christos {
185 1.1 christos char *expanded_dirname;
186 1.1 christos
187 1.1 christos expanded_dirname = tilde_expand_word (temp_dirname);
188 1.1 christos free (temp_dirname);
189 1.1 christos temp_dirname = expanded_dirname;
190 1.1 christos }
191 1.1 christos
192 1.1 christos temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
193 1.1 christos strcpy (temp, temp_dirname);
194 1.1 christos if (!IS_SLASH (temp[(strlen (temp)) - 1]))
195 1.1 christos strcat (temp, "/");
196 1.1 christos strcat (temp, filename);
197 1.1 christos
198 1.1 christos pre_suffix_length = strlen (temp);
199 1.1 christos
200 1.1 christos free (temp_dirname);
201 1.1 christos
202 1.1 christos for (i = 0; info_suffixes[i]; i++)
203 1.1 christos {
204 1.1 christos strcpy (temp + pre_suffix_length, info_suffixes[i]);
205 1.1 christos
206 1.1 christos statable = (stat (temp, &finfo) == 0);
207 1.1 christos
208 1.1 christos /* If we have found a regular file, then use that. Else, if we
209 1.1 christos have found a directory, look in that directory for this file. */
210 1.1 christos if (statable)
211 1.1 christos {
212 1.1 christos if (S_ISREG (finfo.st_mode))
213 1.1 christos {
214 1.1 christos return (temp);
215 1.1 christos }
216 1.1 christos else if (S_ISDIR (finfo.st_mode))
217 1.1 christos {
218 1.1 christos char *newpath, *filename_only, *newtemp;
219 1.1 christos
220 1.1 christos newpath = xstrdup (temp);
221 1.1 christos filename_only = filename_non_directory (filename);
222 1.1 christos newtemp = info_file_in_path (filename_only, newpath);
223 1.1 christos
224 1.1 christos free (newpath);
225 1.1 christos if (newtemp)
226 1.1 christos {
227 1.1 christos free (temp);
228 1.1 christos return (newtemp);
229 1.1 christos }
230 1.1 christos }
231 1.1 christos }
232 1.1 christos else
233 1.1 christos {
234 1.1 christos /* Add various compression suffixes to the name to see if
235 1.1 christos the file is present in compressed format. */
236 1.1 christos register int j, pre_compress_suffix_length;
237 1.1 christos
238 1.1 christos pre_compress_suffix_length = strlen (temp);
239 1.1 christos
240 1.1 christos for (j = 0; compress_suffixes[j].suffix; j++)
241 1.1 christos {
242 1.1 christos strcpy (temp + pre_compress_suffix_length,
243 1.1 christos compress_suffixes[j].suffix);
244 1.1 christos
245 1.1 christos statable = (stat (temp, &finfo) == 0);
246 1.1 christos if (statable && (S_ISREG (finfo.st_mode)))
247 1.1 christos return (temp);
248 1.1 christos }
249 1.1 christos }
250 1.1 christos }
251 1.1 christos free (temp);
252 1.1 christos }
253 1.1 christos return ((char *)NULL);
254 1.1 christos }
255 1.1 christos
256 1.1 christos /* Assume FNAME is an absolute file name, and check whether it is
257 1.1 christos a regular file. If it is, return it as a new string; otherwise
258 1.1 christos return a NULL pointer. We do it by taking the file name apart
259 1.1 christos into its directory and basename parts, and calling info_file_in_path.*/
260 1.1 christos static char *
261 1.1 christos info_absolute_file (char *fname)
262 1.1 christos {
263 1.1 christos char *containing_dir = xstrdup (fname);
264 1.1 christos char *base = filename_non_directory (containing_dir);
265 1.1 christos
266 1.1 christos if (base > containing_dir)
267 1.1 christos base[-1] = '\0';
268 1.1 christos
269 1.1 christos return info_file_in_path (filename_non_directory (fname), containing_dir);
270 1.1 christos }
271 1.1 christos
272 1.1 christos
273 1.1 christos /* Given a string containing units of information separated by the
274 1.1 christos PATH_SEP character, return the next one after IDX, or NULL if there
275 1.1 christos are no more. Advance IDX to the character after the colon. */
276 1.1 christos
277 1.1 christos char *
278 1.1 christos extract_colon_unit (char *string, int *idx)
279 1.1 christos {
280 1.1 christos unsigned int i = (unsigned int) *idx;
281 1.1 christos unsigned int start = i;
282 1.1 christos
283 1.1 christos if (!string || i >= strlen (string))
284 1.1 christos return NULL;
285 1.1 christos
286 1.1 christos if (!string[i]) /* end of string */
287 1.1 christos return NULL;
288 1.1 christos
289 1.1 christos /* Advance to next PATH_SEP. */
290 1.1 christos while (string[i] && string[i] != PATH_SEP[0])
291 1.1 christos i++;
292 1.1 christos
293 1.1 christos {
294 1.1 christos char *value = xmalloc ((i - start) + 1);
295 1.1 christos strncpy (value, &string[start], (i - start));
296 1.1 christos value[i - start] = 0;
297 1.1 christos
298 1.1 christos i++; /* move past PATH_SEP */
299 1.1 christos *idx = i;
300 1.1 christos return value;
301 1.1 christos }
302 1.1 christos }
303 1.1 christos
304 1.1 christos /* A structure which associates a filename with its expansion. */
305 1.1 christos typedef struct
306 1.1 christos {
307 1.1 christos char *filename;
308 1.1 christos char *expansion;
309 1.1 christos } FILENAME_LIST;
310 1.1 christos
311 1.1 christos /* An array of remembered arguments and results. */
312 1.1 christos static FILENAME_LIST **names_and_files = (FILENAME_LIST **)NULL;
313 1.1 christos static int names_and_files_index = 0;
314 1.1 christos static int names_and_files_slots = 0;
315 1.1 christos
316 1.1 christos /* Find the result for having already called info_find_fullpath () with
317 1.1 christos FILENAME. */
318 1.1 christos static char *
319 1.1 christos lookup_info_filename (char *filename)
320 1.1 christos {
321 1.1 christos if (filename && names_and_files)
322 1.1 christos {
323 1.1 christos register int i;
324 1.1 christos for (i = 0; names_and_files[i]; i++)
325 1.1 christos {
326 1.1 christos if (FILENAME_CMP (names_and_files[i]->filename, filename) == 0)
327 1.1 christos return (names_and_files[i]->expansion);
328 1.1 christos }
329 1.1 christos }
330 1.1 christos return (char *)NULL;;
331 1.1 christos }
332 1.1 christos
333 1.1 christos /* Add a filename and its expansion to our list. */
334 1.1 christos static void
335 1.1 christos remember_info_filename (char *filename, char *expansion)
336 1.1 christos {
337 1.1 christos FILENAME_LIST *new;
338 1.1 christos
339 1.1 christos if (names_and_files_index + 2 > names_and_files_slots)
340 1.1 christos {
341 1.1 christos int alloc_size;
342 1.1 christos names_and_files_slots += 10;
343 1.1 christos
344 1.1 christos alloc_size = names_and_files_slots * sizeof (FILENAME_LIST *);
345 1.1 christos
346 1.1 christos names_and_files =
347 1.1 christos (FILENAME_LIST **) xrealloc (names_and_files, alloc_size);
348 1.1 christos }
349 1.1 christos
350 1.1 christos new = (FILENAME_LIST *)xmalloc (sizeof (FILENAME_LIST));
351 1.1 christos new->filename = xstrdup (filename);
352 1.1 christos new->expansion = expansion ? xstrdup (expansion) : (char *)NULL;
353 1.1 christos
354 1.1 christos names_and_files[names_and_files_index++] = new;
355 1.1 christos names_and_files[names_and_files_index] = (FILENAME_LIST *)NULL;
356 1.1 christos }
357 1.1 christos
358 1.1 christos static void
359 1.1 christos maybe_initialize_infopath (void)
360 1.1 christos {
361 1.1 christos if (!infopath_size)
362 1.1 christos {
363 1.1 christos infopath = (char *)
364 1.1 christos xmalloc (infopath_size = (1 + strlen (DEFAULT_INFOPATH)));
365 1.1 christos
366 1.1 christos strcpy (infopath, DEFAULT_INFOPATH);
367 1.1 christos }
368 1.1 christos }
369 1.1 christos
370 1.1 christos /* Add PATH to the list of paths found in INFOPATH. 2nd argument says
371 1.1 christos whether to put PATH at the front or end of INFOPATH. */
372 1.1 christos void
373 1.1 christos info_add_path (char *path, int where)
374 1.1 christos {
375 1.1 christos int len;
376 1.1 christos
377 1.1 christos if (!infopath)
378 1.1 christos {
379 1.1 christos infopath = (char *)xmalloc (infopath_size = 200 + strlen (path));
380 1.1 christos infopath[0] = '\0';
381 1.1 christos }
382 1.1 christos
383 1.1 christos len = strlen (path) + strlen (infopath);
384 1.1 christos
385 1.1 christos if (len + 2 >= infopath_size)
386 1.1 christos infopath = (char *)xrealloc (infopath, (infopath_size += (2 * len) + 2));
387 1.1 christos
388 1.1 christos if (!*infopath)
389 1.1 christos strcpy (infopath, path);
390 1.1 christos else if (where == INFOPATH_APPEND)
391 1.1 christos {
392 1.1 christos strcat (infopath, PATH_SEP);
393 1.1 christos strcat (infopath, path);
394 1.1 christos }
395 1.1 christos else if (where == INFOPATH_PREPEND)
396 1.1 christos {
397 1.1 christos char *temp = xstrdup (infopath);
398 1.1 christos strcpy (infopath, path);
399 1.1 christos strcat (infopath, PATH_SEP);
400 1.1 christos strcat (infopath, temp);
401 1.1 christos free (temp);
402 1.1 christos }
403 1.1 christos }
404 1.1 christos
405 1.1 christos /* Make INFOPATH have absolutely nothing in it. */
406 1.1 christos void
407 1.1 christos zap_infopath (void)
408 1.1 christos {
409 1.1 christos if (infopath)
410 1.1 christos free (infopath);
411 1.1 christos
412 1.1 christos infopath = (char *)NULL;
413 1.1 christos infopath_size = 0;
414 1.1 christos }
415 1.1 christos
416 1.1 christos /* Given a chunk of text and its length, convert all CRLF pairs at every
417 1.1 christos end-of-line into a single Newline character. Return the length of
418 1.1 christos produced text.
419 1.1 christos
420 1.1 christos This is required because the rest of code is too entrenched in having
421 1.1 christos a single newline at each EOL; in particular, searching for various
422 1.1 christos Info headers and cookies can become extremely tricky if that assumption
423 1.1 christos breaks.
424 1.1 christos
425 1.1 christos FIXME: this could also support Mac-style text files with a single CR
426 1.1 christos at the EOL, but what about random CR characters in non-Mac files? Can
427 1.1 christos we afford converting them into newlines as well? Maybe implement some
428 1.1 christos heuristics here, like in Emacs 20.
429 1.1 christos
430 1.1 christos FIXME: is it a good idea to show the EOL type on the modeline? */
431 1.1 christos long
432 1.1 christos convert_eols (char *text, long int textlen)
433 1.1 christos {
434 1.1 christos register char *s = text;
435 1.1 christos register char *d = text;
436 1.1 christos
437 1.1 christos while (textlen--)
438 1.1 christos {
439 1.1 christos if (*s == '\r' && textlen && s[1] == '\n')
440 1.1 christos {
441 1.1 christos s++;
442 1.1 christos textlen--;
443 1.1 christos }
444 1.1 christos *d++ = *s++;
445 1.1 christos }
446 1.1 christos
447 1.1 christos return (long)(d - text);
448 1.1 christos }
449 1.1 christos
450 1.1 christos /* Read the contents of PATHNAME, returning a buffer with the contents of
451 1.1 christos that file in it, and returning the size of that buffer in FILESIZE.
452 1.1 christos FINFO is a stat struct which has already been filled in by the caller.
453 1.1 christos If the file turns out to be compressed, set IS_COMPRESSED to non-zero.
454 1.1 christos If the file cannot be read, return a NULL pointer. */
455 1.1 christos char *
456 1.1 christos filesys_read_info_file (char *pathname, long int *filesize,
457 1.1 christos struct stat *finfo, int *is_compressed)
458 1.1 christos {
459 1.1 christos long st_size;
460 1.1 christos
461 1.1 christos *filesize = filesys_error_number = 0;
462 1.1 christos
463 1.1 christos if (compressed_filename_p (pathname))
464 1.1 christos {
465 1.1 christos *is_compressed = 1;
466 1.1 christos return (filesys_read_compressed (pathname, filesize));
467 1.1 christos }
468 1.1 christos else
469 1.1 christos {
470 1.1 christos int descriptor;
471 1.1 christos char *contents;
472 1.1 christos
473 1.1 christos *is_compressed = 0;
474 1.1 christos descriptor = open (pathname, O_RDONLY | O_BINARY, 0666);
475 1.1 christos
476 1.1 christos /* If the file couldn't be opened, give up. */
477 1.1 christos if (descriptor < 0)
478 1.1 christos {
479 1.1 christos filesys_error_number = errno;
480 1.1 christos return ((char *)NULL);
481 1.1 christos }
482 1.1 christos
483 1.1 christos /* Try to read the contents of this file. */
484 1.1 christos st_size = (long) finfo->st_size;
485 1.1 christos contents = (char *)xmalloc (1 + st_size);
486 1.1 christos if ((read (descriptor, contents, st_size)) != st_size)
487 1.1 christos {
488 1.1 christos filesys_error_number = errno;
489 1.1 christos close (descriptor);
490 1.1 christos free (contents);
491 1.1 christos return ((char *)NULL);
492 1.1 christos }
493 1.1 christos
494 1.1 christos close (descriptor);
495 1.1 christos
496 1.1 christos /* Convert any DOS-style CRLF EOLs into Unix-style NL.
497 1.1 christos Seems like a good idea to have even on Unix, in case the Info
498 1.1 christos files are coming from some Windows system across a network. */
499 1.1 christos *filesize = convert_eols (contents, st_size);
500 1.1 christos
501 1.1 christos /* EOL conversion can shrink the text quite a bit. We don't
502 1.1 christos want to waste storage. */
503 1.1 christos if (*filesize < st_size)
504 1.1 christos contents = (char *)xrealloc (contents, 1 + *filesize);
505 1.1 christos contents[*filesize] = '\0';
506 1.1 christos
507 1.1 christos return (contents);
508 1.1 christos }
509 1.1 christos }
510 1.1 christos
511 1.1 christos /* Typically, pipe buffers are 4k. */
512 1.1 christos #define BASIC_PIPE_BUFFER (4 * 1024)
513 1.1 christos
514 1.1 christos /* We use some large multiple of that. */
515 1.1 christos #define FILESYS_PIPE_BUFFER_SIZE (16 * BASIC_PIPE_BUFFER)
516 1.1 christos
517 1.1 christos char *
518 1.1 christos filesys_read_compressed (char *pathname, long int *filesize)
519 1.1 christos {
520 1.1 christos FILE *stream;
521 1.1 christos char *command, *decompressor;
522 1.1 christos char *contents = (char *)NULL;
523 1.1 christos
524 1.1 christos *filesize = filesys_error_number = 0;
525 1.1 christos
526 1.1 christos decompressor = filesys_decompressor_for_file (pathname);
527 1.1 christos
528 1.1 christos if (!decompressor)
529 1.1 christos return ((char *)NULL);
530 1.1 christos
531 1.1 christos command = (char *)xmalloc (15 + strlen (pathname) + strlen (decompressor));
532 1.1 christos /* Explicit .exe suffix makes the diagnostics of `popen'
533 1.1 christos better on systems where COMMAND.COM is the stock shell. */
534 1.1 christos sprintf (command, "%s%s < %s",
535 1.1 christos decompressor, STRIP_DOT_EXE ? ".exe" : "", pathname);
536 1.1 christos
537 1.1 christos #if !defined (BUILDING_LIBRARY)
538 1.1 christos if (info_windows_initialized_p)
539 1.1 christos {
540 1.1 christos char *temp;
541 1.1 christos
542 1.1 christos temp = (char *)xmalloc (5 + strlen (command));
543 1.1 christos sprintf (temp, "%s...", command);
544 1.1 christos message_in_echo_area ("%s", temp, NULL);
545 1.1 christos free (temp);
546 1.1 christos }
547 1.1 christos #endif /* !BUILDING_LIBRARY */
548 1.1 christos
549 1.1 christos stream = popen (command, FOPEN_RBIN);
550 1.1 christos free (command);
551 1.1 christos
552 1.1 christos /* Read chunks from this file until there are none left to read. */
553 1.1 christos if (stream)
554 1.1 christos {
555 1.1 christos long offset, size;
556 1.1 christos char *chunk;
557 1.1 christos
558 1.1 christos offset = size = 0;
559 1.1 christos chunk = (char *)xmalloc (FILESYS_PIPE_BUFFER_SIZE);
560 1.1 christos
561 1.1 christos while (1)
562 1.1 christos {
563 1.1 christos int bytes_read;
564 1.1 christos
565 1.1 christos bytes_read = fread (chunk, 1, FILESYS_PIPE_BUFFER_SIZE, stream);
566 1.1 christos
567 1.1 christos if (bytes_read + offset >= size)
568 1.1 christos contents = (char *)xrealloc
569 1.1 christos (contents, size += (2 * FILESYS_PIPE_BUFFER_SIZE));
570 1.1 christos
571 1.1 christos memcpy (contents + offset, chunk, bytes_read);
572 1.1 christos offset += bytes_read;
573 1.1 christos if (bytes_read != FILESYS_PIPE_BUFFER_SIZE)
574 1.1 christos break;
575 1.1 christos }
576 1.1 christos
577 1.1 christos free (chunk);
578 1.1 christos if (pclose (stream) == -1)
579 1.1 christos {
580 1.1 christos if (contents)
581 1.1 christos free (contents);
582 1.1 christos contents = (char *)NULL;
583 1.1 christos filesys_error_number = errno;
584 1.1 christos }
585 1.1 christos else
586 1.1 christos {
587 1.1 christos *filesize = convert_eols (contents, offset);
588 1.1 christos contents = (char *)xrealloc (contents, 1 + *filesize);
589 1.1 christos contents[*filesize] = '\0';
590 1.1 christos }
591 1.1 christos }
592 1.1 christos else
593 1.1 christos {
594 1.1 christos filesys_error_number = errno;
595 1.1 christos }
596 1.1 christos
597 1.1 christos #if !defined (BUILDING_LIBARARY)
598 1.1 christos if (info_windows_initialized_p)
599 1.1 christos unmessage_in_echo_area ();
600 1.1 christos #endif /* !BUILDING_LIBRARY */
601 1.1 christos return (contents);
602 1.1 christos }
603 1.1 christos
604 1.1 christos /* Return non-zero if FILENAME belongs to a compressed file. */
605 1.1 christos int
606 1.1 christos compressed_filename_p (char *filename)
607 1.1 christos {
608 1.1 christos char *decompressor;
609 1.1 christos
610 1.1 christos /* Find the final extension of this filename, and see if it matches one
611 1.1 christos of our known ones. */
612 1.1 christos decompressor = filesys_decompressor_for_file (filename);
613 1.1 christos
614 1.1 christos if (decompressor)
615 1.1 christos return (1);
616 1.1 christos else
617 1.1 christos return (0);
618 1.1 christos }
619 1.1 christos
620 1.1 christos /* Return the command string that would be used to decompress FILENAME. */
621 1.1 christos char *
622 1.1 christos filesys_decompressor_for_file (char *filename)
623 1.1 christos {
624 1.1 christos register int i;
625 1.1 christos char *extension = (char *)NULL;
626 1.1 christos
627 1.1 christos /* Find the final extension of FILENAME, and see if it appears in our
628 1.1 christos list of known compression extensions. */
629 1.1 christos for (i = strlen (filename) - 1; i > 0; i--)
630 1.1 christos if (filename[i] == '.')
631 1.1 christos {
632 1.1 christos extension = filename + i;
633 1.1 christos break;
634 1.1 christos }
635 1.1 christos
636 1.1 christos if (!extension)
637 1.1 christos return ((char *)NULL);
638 1.1 christos
639 1.1 christos for (i = 0; compress_suffixes[i].suffix; i++)
640 1.1 christos if (FILENAME_CMP (extension, compress_suffixes[i].suffix) == 0)
641 1.1 christos return (compress_suffixes[i].decompressor);
642 1.1 christos
643 1.1 christos #if defined (__MSDOS__)
644 1.1 christos /* If no other suffix matched, allow any extension which ends
645 1.1 christos with `z' to be decompressed by gunzip. Due to limited 8+3 DOS
646 1.1 christos file namespace, we can expect many such cases, and supporting
647 1.1 christos every weird suffix thus produced would be a pain. */
648 1.1 christos if (extension[strlen (extension) - 1] == 'z' ||
649 1.1 christos extension[strlen (extension) - 1] == 'Z')
650 1.1 christos return "gunzip";
651 1.1 christos #endif
652 1.1 christos
653 1.1 christos return ((char *)NULL);
654 1.1 christos }
655 1.1 christos
656 1.1 christos /* The number of the most recent file system error. */
657 1.1 christos int filesys_error_number = 0;
658 1.1 christos
659 1.1 christos /* A function which returns a pointer to a static buffer containing
660 1.1 christos an error message for FILENAME and ERROR_NUM. */
661 1.1 christos static char *errmsg_buf = (char *)NULL;
662 1.1 christos static int errmsg_buf_size = 0;
663 1.1 christos
664 1.1 christos char *
665 1.1 christos filesys_error_string (char *filename, int error_num)
666 1.1 christos {
667 1.1 christos int len;
668 1.1 christos char *result;
669 1.1 christos
670 1.1 christos if (error_num == 0)
671 1.1 christos return ((char *)NULL);
672 1.1 christos
673 1.1 christos result = strerror (error_num);
674 1.1 christos
675 1.1 christos len = 4 + strlen (filename) + strlen (result);
676 1.1 christos if (len >= errmsg_buf_size)
677 1.1 christos errmsg_buf = (char *)xrealloc (errmsg_buf, (errmsg_buf_size = 2 + len));
678 1.1 christos
679 1.1 christos sprintf (errmsg_buf, "%s: %s", filename, result);
680 1.1 christos return (errmsg_buf);
681 1.1 christos }
682 1.1 christos
683 1.1 christos
684 1.1 christos /* Check for "dir" with all the possible info and compression suffixes,
686 1.1 christos in combination. */
687 1.1 christos
688 1.1 christos int
689 1.1 christos is_dir_name (char *filename)
690 1.1 christos {
691 1.1 christos unsigned i;
692 1.1 christos
693 1.1 christos for (i = 0; info_suffixes[i]; i++)
694 1.1 christos {
695 1.1 christos unsigned c;
696 1.1 christos char trydir[50];
697 1.1 christos strcpy (trydir, "dir");
698 1.1 christos strcat (trydir, info_suffixes[i]);
699 1.1 christos
700 1.1 christos if (strcasecmp (filename, trydir) == 0)
701 1.1 christos return 1;
702 1.1 christos
703 1.1 christos for (c = 0; compress_suffixes[c].suffix; c++)
704 1.1 christos {
705 1.1 christos char dir_compressed[50]; /* can be short */
706 1.1 christos strcpy (dir_compressed, trydir);
707 1.1 christos strcat (dir_compressed, compress_suffixes[c].suffix);
708 1.1 christos if (strcasecmp (filename, dir_compressed) == 0)
709 1.1 christos return 1;
710 1.1 christos }
711 1.1 christos }
712 1.1 christos
713 1.1 christos return 0;
714 }
715