* arm.md (*adddf_esfdf_df): Renamed from *adddf_df_esfdf.
[official-gcc.git] / texinfo / info / filesys.c
blob36287ab1f6ac5eb328d78ea4fd71cfd608ae6482
1 /* filesys.c -- File system specific functions for hacking this system.
2 $Id: filesys.c,v 1.1.1.3 1998/03/24 18:20:10 law Exp $
4 Copyright (C) 1993, 97, 98 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 Written by Brian Fox (bfox@ai.mit.edu). */
22 #include "info.h"
24 #include "tilde.h"
25 #include "filesys.h"
27 /* Local to this file. */
28 static char *info_file_in_path (), *lookup_info_filename ();
29 static void remember_info_filename (), maybe_initialize_infopath ();
31 typedef struct
33 char *suffix;
34 char *decompressor;
35 } COMPRESSION_ALIST;
37 static char *info_suffixes[] = {
38 "",
39 ".info",
40 "-info",
41 "/index",
42 (char *)NULL
45 static COMPRESSION_ALIST compress_suffixes[] = {
46 { ".Z", "uncompress" },
47 { ".Y", "unyabba" },
48 { ".z", "gunzip" },
49 { ".gz", "gunzip" },
50 { (char *)NULL, (char *)NULL }
53 /* The path on which we look for info files. You can initialize this
54 from the environment variable INFOPATH if there is one, or you can
55 call info_add_path () to add paths to the beginning or end of it.
56 You can call zap_infopath () to make the path go away. */
57 char *infopath = (char *)NULL;
58 static int infopath_size = 0;
60 /* Expand the filename in PARTIAL to make a real name for this operating
61 system. This looks in INFO_PATHS in order to find the correct file.
62 If it can't find the file, it returns NULL. */
63 static char *local_temp_filename = (char *)NULL;
64 static int local_temp_filename_size = 0;
66 char *
67 info_find_fullpath (partial)
68 char *partial;
70 int initial_character;
71 char *temp;
73 filesys_error_number = 0;
75 maybe_initialize_infopath ();
77 if (partial && (initial_character = *partial))
79 char *expansion;
81 expansion = lookup_info_filename (partial);
83 if (expansion)
84 return (expansion);
86 /* If we have the full path to this file, we still may have to add
87 various extensions to it. I guess we have to stat this file
88 after all. */
89 if (initial_character == '/')
90 temp = info_file_in_path (partial + 1, "/");
91 else if (initial_character == '~')
93 expansion = tilde_expand_word (partial);
94 if (*expansion == '/')
96 temp = info_file_in_path (expansion + 1, "/");
97 free (expansion);
99 else
100 temp = expansion;
102 else if (initial_character == '.' &&
103 (partial[1] == '/' || (partial[1] == '.' && partial[2] == '/')))
105 if (local_temp_filename_size < 1024)
106 local_temp_filename = (char *)xrealloc
107 (local_temp_filename, (local_temp_filename_size = 1024));
108 #if defined (HAVE_GETCWD)
109 if (!getcwd (local_temp_filename, local_temp_filename_size))
110 #else /* !HAVE_GETCWD */
111 if (!getwd (local_temp_filename))
112 #endif /* !HAVE_GETCWD */
114 filesys_error_number = errno;
115 return (partial);
118 strcat (local_temp_filename, "/");
119 strcat (local_temp_filename, partial);
120 return (local_temp_filename);
122 else
123 temp = info_file_in_path (partial, infopath);
125 if (temp)
127 remember_info_filename (partial, temp);
128 if (strlen (temp) > local_temp_filename_size)
129 local_temp_filename = (char *) xrealloc
130 (local_temp_filename,
131 (local_temp_filename_size = (50 + strlen (temp))));
132 strcpy (local_temp_filename, temp);
133 free (temp);
134 return (local_temp_filename);
137 return (partial);
140 /* Scan the list of directories in PATH looking for FILENAME. If we find
141 one that is a regular file, return it as a new string. Otherwise, return
142 a NULL pointer. */
143 static char *
144 info_file_in_path (filename, path)
145 char *filename, *path;
147 struct stat finfo;
148 char *temp_dirname;
149 int statable, dirname_index;
151 dirname_index = 0;
153 while ((temp_dirname = extract_colon_unit (path, &dirname_index)))
155 register int i, pre_suffix_length;
156 char *temp;
158 /* Expand a leading tilde if one is present. */
159 if (*temp_dirname == '~')
161 char *expanded_dirname;
163 expanded_dirname = tilde_expand_word (temp_dirname);
164 free (temp_dirname);
165 temp_dirname = expanded_dirname;
168 temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
169 strcpy (temp, temp_dirname);
170 if (temp[(strlen (temp)) - 1] != '/')
171 strcat (temp, "/");
172 strcat (temp, filename);
174 pre_suffix_length = strlen (temp);
176 free (temp_dirname);
178 for (i = 0; info_suffixes[i]; i++)
180 strcpy (temp + pre_suffix_length, info_suffixes[i]);
182 statable = (stat (temp, &finfo) == 0);
184 /* If we have found a regular file, then use that. Else, if we
185 have found a directory, look in that directory for this file. */
186 if (statable)
188 if (S_ISREG (finfo.st_mode))
190 return (temp);
192 else if (S_ISDIR (finfo.st_mode))
194 char *newpath, *filename_only, *newtemp;
196 newpath = xstrdup (temp);
197 filename_only = filename_non_directory (filename);
198 newtemp = info_file_in_path (filename_only, newpath);
200 free (newpath);
201 if (newtemp)
203 free (temp);
204 return (newtemp);
208 else
210 /* Add various compression suffixes to the name to see if
211 the file is present in compressed format. */
212 register int j, pre_compress_suffix_length;
214 pre_compress_suffix_length = strlen (temp);
216 for (j = 0; compress_suffixes[j].suffix; j++)
218 strcpy (temp + pre_compress_suffix_length,
219 compress_suffixes[j].suffix);
221 statable = (stat (temp, &finfo) == 0);
222 if (statable && (S_ISREG (finfo.st_mode)))
223 return (temp);
227 free (temp);
229 return ((char *)NULL);
232 /* Given a string containing units of information separated by colons,
233 return the next one pointed to by IDX, or NULL if there are no more.
234 Advance IDX to the character after the colon. */
235 char *
236 extract_colon_unit (string, idx)
237 char *string;
238 int *idx;
240 register int i, start;
242 i = start = *idx;
243 if ((i >= strlen (string)) || !string)
244 return ((char *) NULL);
246 while (string[i] && string[i] != ':')
247 i++;
248 if (i == start)
250 return ((char *) NULL);
252 else
254 char *value;
256 value = (char *) xmalloc (1 + (i - start));
257 strncpy (value, &string[start], (i - start));
258 value[i - start] = '\0';
259 if (string[i])
260 ++i;
261 *idx = i;
262 return (value);
266 /* A structure which associates a filename with its expansion. */
267 typedef struct {
268 char *filename;
269 char *expansion;
270 } FILENAME_LIST;
272 /* An array of remembered arguments and results. */
273 static FILENAME_LIST **names_and_files = (FILENAME_LIST **)NULL;
274 static int names_and_files_index = 0;
275 static int names_and_files_slots = 0;
277 /* Find the result for having already called info_find_fullpath () with
278 FILENAME. */
279 static char *
280 lookup_info_filename (filename)
281 char *filename;
283 if (filename && names_and_files)
285 register int i;
286 for (i = 0; names_and_files[i]; i++)
288 if (strcmp (names_and_files[i]->filename, filename) == 0)
289 return (names_and_files[i]->expansion);
292 return (char *)NULL;;
295 /* Add a filename and its expansion to our list. */
296 static void
297 remember_info_filename (filename, expansion)
298 char *filename, *expansion;
300 FILENAME_LIST *new;
302 if (names_and_files_index + 2 > names_and_files_slots)
304 int alloc_size;
305 names_and_files_slots += 10;
307 alloc_size = names_and_files_slots * sizeof (FILENAME_LIST *);
309 names_and_files =
310 (FILENAME_LIST **) xrealloc (names_and_files, alloc_size);
313 new = (FILENAME_LIST *)xmalloc (sizeof (FILENAME_LIST));
314 new->filename = xstrdup (filename);
315 new->expansion = expansion ? xstrdup (expansion) : (char *)NULL;
317 names_and_files[names_and_files_index++] = new;
318 names_and_files[names_and_files_index] = (FILENAME_LIST *)NULL;
321 static void
322 maybe_initialize_infopath ()
324 if (!infopath_size)
326 infopath = (char *)
327 xmalloc (infopath_size = (1 + strlen (DEFAULT_INFOPATH)));
329 strcpy (infopath, DEFAULT_INFOPATH);
333 /* Add PATH to the list of paths found in INFOPATH. 2nd argument says
334 whether to put PATH at the front or end of INFOPATH. */
335 void
336 info_add_path (path, where)
337 char *path;
338 int where;
340 int len;
342 if (!infopath)
344 infopath = (char *)xmalloc (infopath_size = 200 + strlen (path));
345 infopath[0] = '\0';
348 len = strlen (path) + strlen (infopath);
350 if (len + 2 >= infopath_size)
351 infopath = (char *)xrealloc (infopath, (infopath_size += (2 * len) + 2));
353 if (!*infopath)
354 strcpy (infopath, path);
355 else if (where == INFOPATH_APPEND)
357 strcat (infopath, ":");
358 strcat (infopath, path);
360 else if (where == INFOPATH_PREPEND)
362 char *temp = xstrdup (infopath);
363 strcpy (infopath, path);
364 strcat (infopath, ":");
365 strcat (infopath, temp);
366 free (temp);
370 /* Make INFOPATH have absolutely nothing in it. */
371 void
372 zap_infopath ()
374 if (infopath)
375 free (infopath);
377 infopath = (char *)NULL;
378 infopath_size = 0;
381 /* Read the contents of PATHNAME, returning a buffer with the contents of
382 that file in it, and returning the size of that buffer in FILESIZE.
383 FINFO is a stat struct which has already been filled in by the caller.
384 If the file cannot be read, return a NULL pointer. */
385 char *
386 filesys_read_info_file (pathname, filesize, finfo)
387 char *pathname;
388 long *filesize;
389 struct stat *finfo;
391 long st_size;
393 *filesize = filesys_error_number = 0;
395 if (compressed_filename_p (pathname))
396 return (filesys_read_compressed (pathname, filesize, finfo));
397 else
399 int descriptor;
400 char *contents;
402 descriptor = open (pathname, O_RDONLY, 0666);
404 /* If the file couldn't be opened, give up. */
405 if (descriptor < 0)
407 filesys_error_number = errno;
408 return ((char *)NULL);
411 /* Try to read the contents of this file. */
412 st_size = (long) finfo->st_size;
413 contents = (char *)xmalloc (1 + st_size);
414 if ((read (descriptor, contents, st_size)) != st_size)
416 filesys_error_number = errno;
417 close (descriptor);
418 free (contents);
419 return ((char *)NULL);
422 close (descriptor);
424 *filesize = st_size;
425 return (contents);
429 /* Typically, pipe buffers are 4k. */
430 #define BASIC_PIPE_BUFFER (4 * 1024)
432 /* We use some large multiple of that. */
433 #define FILESYS_PIPE_BUFFER_SIZE (16 * BASIC_PIPE_BUFFER)
435 char *
436 filesys_read_compressed (pathname, filesize, finfo)
437 char *pathname;
438 long *filesize;
439 struct stat *finfo;
441 FILE *stream;
442 char *command, *decompressor;
443 char *contents = (char *)NULL;
445 *filesize = filesys_error_number = 0;
447 decompressor = filesys_decompressor_for_file (pathname);
449 if (!decompressor)
450 return ((char *)NULL);
452 command = (char *)xmalloc (10 + strlen (pathname) + strlen (decompressor));
453 sprintf (command, "%s < %s", decompressor, pathname);
455 #if !defined (BUILDING_LIBRARY)
456 if (info_windows_initialized_p)
458 char *temp;
460 temp = (char *)xmalloc (5 + strlen (command));
461 sprintf (temp, "%s...", command);
462 message_in_echo_area ("%s", temp);
463 free (temp);
465 #endif /* !BUILDING_LIBRARY */
467 stream = popen (command, "r");
468 free (command);
470 /* Read chunks from this file until there are none left to read. */
471 if (stream)
473 int offset, size;
474 char *chunk;
476 offset = size = 0;
477 chunk = (char *)xmalloc (FILESYS_PIPE_BUFFER_SIZE);
479 while (1)
481 int bytes_read;
483 bytes_read = fread (chunk, 1, FILESYS_PIPE_BUFFER_SIZE, stream);
485 if (bytes_read + offset >= size)
486 contents = (char *)xrealloc
487 (contents, size += (2 * FILESYS_PIPE_BUFFER_SIZE));
489 memcpy (contents + offset, chunk, bytes_read);
490 offset += bytes_read;
491 if (bytes_read != FILESYS_PIPE_BUFFER_SIZE)
492 break;
495 free (chunk);
496 pclose (stream);
497 contents = (char *)xrealloc (contents, offset + 1);
498 *filesize = offset;
500 else
502 filesys_error_number = errno;
505 #if !defined (BUILDING_LIBARARY)
506 if (info_windows_initialized_p)
507 unmessage_in_echo_area ();
508 #endif /* !BUILDING_LIBRARY */
509 return (contents);
512 /* Return non-zero if FILENAME belongs to a compressed file. */
514 compressed_filename_p (filename)
515 char *filename;
517 char *decompressor;
519 /* Find the final extension of this filename, and see if it matches one
520 of our known ones. */
521 decompressor = filesys_decompressor_for_file (filename);
523 if (decompressor)
524 return (1);
525 else
526 return (0);
529 /* Return the command string that would be used to decompress FILENAME. */
530 char *
531 filesys_decompressor_for_file (filename)
532 char *filename;
534 register int i;
535 char *extension = (char *)NULL;
537 /* Find the final extension of FILENAME, and see if it appears in our
538 list of known compression extensions. */
539 for (i = strlen (filename) - 1; i > 0; i--)
540 if (filename[i] == '.')
542 extension = filename + i;
543 break;
546 if (!extension)
547 return ((char *)NULL);
549 for (i = 0; compress_suffixes[i].suffix; i++)
550 if (strcmp (extension, compress_suffixes[i].suffix) == 0)
551 return (compress_suffixes[i].decompressor);
553 return ((char *)NULL);
556 /* The number of the most recent file system error. */
557 int filesys_error_number = 0;
559 /* A function which returns a pointer to a static buffer containing
560 an error message for FILENAME and ERROR_NUM. */
561 static char *errmsg_buf = (char *)NULL;
562 static int errmsg_buf_size = 0;
564 char *
565 filesys_error_string (filename, error_num)
566 char *filename;
567 int error_num;
569 int len;
570 char *result;
572 if (error_num == 0)
573 return ((char *)NULL);
575 result = strerror (error_num);
577 len = 4 + strlen (filename) + strlen (result);
578 if (len >= errmsg_buf_size)
579 errmsg_buf = (char *)xrealloc (errmsg_buf, (errmsg_buf_size = 2 + len));
581 sprintf (errmsg_buf, "%s: %s", filename, result);
582 return (errmsg_buf);