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)
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). */
27 /* Local to this file. */
28 static char *info_file_in_path (), *lookup_info_filename ();
29 static void remember_info_filename (), maybe_initialize_infopath ();
37 static char *info_suffixes
[] = {
45 static COMPRESSION_ALIST compress_suffixes
[] = {
46 { ".Z", "uncompress" },
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;
67 info_find_fullpath (partial
)
70 int initial_character
;
73 filesys_error_number
= 0;
75 maybe_initialize_infopath ();
77 if (partial
&& (initial_character
= *partial
))
81 expansion
= lookup_info_filename (partial
);
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
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, "/");
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
;
118 strcat (local_temp_filename
, "/");
119 strcat (local_temp_filename
, partial
);
120 return (local_temp_filename
);
123 temp
= info_file_in_path (partial
, infopath
);
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
);
134 return (local_temp_filename
);
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
144 info_file_in_path (filename
, path
)
145 char *filename
, *path
;
149 int statable
, dirname_index
;
153 while ((temp_dirname
= extract_colon_unit (path
, &dirname_index
)))
155 register int i
, pre_suffix_length
;
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
);
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] != '/')
172 strcat (temp
, filename
);
174 pre_suffix_length
= strlen (temp
);
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. */
188 if (S_ISREG (finfo
.st_mode
))
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
);
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
)))
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. */
236 extract_colon_unit (string
, idx
)
240 register int i
, start
;
243 if ((i
>= strlen (string
)) || !string
)
244 return ((char *) NULL
);
246 while (string
[i
] && string
[i
] != ':')
250 return ((char *) NULL
);
256 value
= (char *) xmalloc (1 + (i
- start
));
257 strncpy (value
, &string
[start
], (i
- start
));
258 value
[i
- start
] = '\0';
266 /* A structure which associates a filename with its expansion. */
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
280 lookup_info_filename (filename
)
283 if (filename
&& names_and_files
)
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. */
297 remember_info_filename (filename
, expansion
)
298 char *filename
, *expansion
;
302 if (names_and_files_index
+ 2 > names_and_files_slots
)
305 names_and_files_slots
+= 10;
307 alloc_size
= names_and_files_slots
* sizeof (FILENAME_LIST
*);
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
;
322 maybe_initialize_infopath ()
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. */
336 info_add_path (path
, where
)
344 infopath
= (char *)xmalloc (infopath_size
= 200 + strlen (path
));
348 len
= strlen (path
) + strlen (infopath
);
350 if (len
+ 2 >= infopath_size
)
351 infopath
= (char *)xrealloc (infopath
, (infopath_size
+= (2 * len
) + 2));
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
);
370 /* Make INFOPATH have absolutely nothing in it. */
377 infopath
= (char *)NULL
;
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. */
386 filesys_read_info_file (pathname
, filesize
, finfo
)
393 *filesize
= filesys_error_number
= 0;
395 if (compressed_filename_p (pathname
))
396 return (filesys_read_compressed (pathname
, filesize
, finfo
));
402 descriptor
= open (pathname
, O_RDONLY
, 0666);
404 /* If the file couldn't be opened, give up. */
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
;
419 return ((char *)NULL
);
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)
436 filesys_read_compressed (pathname
, filesize
, finfo
)
442 char *command
, *decompressor
;
443 char *contents
= (char *)NULL
;
445 *filesize
= filesys_error_number
= 0;
447 decompressor
= filesys_decompressor_for_file (pathname
);
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
)
460 temp
= (char *)xmalloc (5 + strlen (command
));
461 sprintf (temp
, "%s...", command
);
462 message_in_echo_area ("%s", temp
);
465 #endif /* !BUILDING_LIBRARY */
467 stream
= popen (command
, "r");
470 /* Read chunks from this file until there are none left to read. */
477 chunk
= (char *)xmalloc (FILESYS_PIPE_BUFFER_SIZE
);
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
)
497 contents
= (char *)xrealloc (contents
, offset
+ 1);
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 */
512 /* Return non-zero if FILENAME belongs to a compressed file. */
514 compressed_filename_p (filename
)
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
);
529 /* Return the command string that would be used to decompress FILENAME. */
531 filesys_decompressor_for_file (filename
)
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
;
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;
565 filesys_error_string (filename
, error_num
)
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
);