156160Sru/* filesys.c -- filesystem specific functions. 2146515Sru $Id: filesys.c,v 1.6 2004/07/30 17:17:40 karl Exp $ 321495Sjmacd 4146515Sru Copyright (C) 1993, 1997, 1998, 2000, 2002, 2003, 2004 Free Software 5114472Sru Foundation, Inc. 621495Sjmacd 721495Sjmacd This program is free software; you can redistribute it and/or modify 821495Sjmacd it under the terms of the GNU General Public License as published by 921495Sjmacd the Free Software Foundation; either version 2, or (at your option) 1021495Sjmacd any later version. 1121495Sjmacd 1221495Sjmacd This program is distributed in the hope that it will be useful, 1321495Sjmacd but WITHOUT ANY WARRANTY; without even the implied warranty of 1421495Sjmacd MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1521495Sjmacd GNU General Public License for more details. 1621495Sjmacd 1721495Sjmacd You should have received a copy of the GNU General Public License 1821495Sjmacd along with this program; if not, write to the Free Software 1921495Sjmacd Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 2021495Sjmacd 2121495Sjmacd Written by Brian Fox (bfox@ai.mit.edu). */ 2221495Sjmacd 2342660Smarkm#include "info.h" 2442660Smarkm 2521495Sjmacd#include "tilde.h" 2621495Sjmacd#include "filesys.h" 2721495Sjmacd 2821495Sjmacd/* Local to this file. */ 29146515Srustatic char *info_file_in_path (char *filename, char *path); 30146515Srustatic char *lookup_info_filename (char *filename); 31146515Srustatic char *info_absolute_file (char *fname); 3221495Sjmacd 33146515Srustatic void remember_info_filename (char *filename, char *expansion); 34146515Srustatic void maybe_initialize_infopath (void); 35146515Sru 3642660Smarkmtypedef struct 3742660Smarkm{ 3821495Sjmacd char *suffix; 3921495Sjmacd char *decompressor; 4021495Sjmacd} COMPRESSION_ALIST; 4121495Sjmacd 4221495Sjmacdstatic char *info_suffixes[] = { 4321495Sjmacd ".info", 4421495Sjmacd "-info", 4542660Smarkm "/index", 4656160Sru ".inf", /* 8+3 file on filesystem which supports long file names */ 4756160Sru#ifdef __MSDOS__ 4856160Sru /* 8+3 file names strike again... */ 4956160Sru ".in", /* for .inz, .igz etc. */ 5056160Sru ".i", 5156160Sru#endif 5256160Sru "", 5356160Sru NULL 5421495Sjmacd}; 5521495Sjmacd 5621495Sjmacdstatic COMPRESSION_ALIST compress_suffixes[] = { 5756160Sru { ".gz", "gunzip" }, 5856160Sru { ".bz2", "bunzip2" }, 5956160Sru { ".z", "gunzip" }, 6021495Sjmacd { ".Z", "uncompress" }, 6121495Sjmacd { ".Y", "unyabba" }, 6256160Sru#ifdef __MSDOS__ 6356160Sru { "gz", "gunzip" }, 6456160Sru { "z", "gunzip" }, 6556160Sru#endif 6621495Sjmacd { (char *)NULL, (char *)NULL } 6721495Sjmacd}; 6821495Sjmacd 6921495Sjmacd/* The path on which we look for info files. You can initialize this 7021495Sjmacd from the environment variable INFOPATH if there is one, or you can 7121495Sjmacd call info_add_path () to add paths to the beginning or end of it. 7221495Sjmacd You can call zap_infopath () to make the path go away. */ 7321495Sjmacdchar *infopath = (char *)NULL; 7421495Sjmacdstatic int infopath_size = 0; 7521495Sjmacd 7621495Sjmacd/* Expand the filename in PARTIAL to make a real name for this operating 7721495Sjmacd system. This looks in INFO_PATHS in order to find the correct file. 7821495Sjmacd If it can't find the file, it returns NULL. */ 7921495Sjmacdstatic char *local_temp_filename = (char *)NULL; 8021495Sjmacdstatic int local_temp_filename_size = 0; 8121495Sjmacd 8221495Sjmacdchar * 83146515Sruinfo_find_fullpath (char *partial) 8421495Sjmacd{ 8521495Sjmacd int initial_character; 8621495Sjmacd char *temp; 8721495Sjmacd 8821495Sjmacd filesys_error_number = 0; 8921495Sjmacd 9021495Sjmacd maybe_initialize_infopath (); 9121495Sjmacd 9221495Sjmacd if (partial && (initial_character = *partial)) 9321495Sjmacd { 9421495Sjmacd char *expansion; 9521495Sjmacd 9621495Sjmacd expansion = lookup_info_filename (partial); 9721495Sjmacd 9821495Sjmacd if (expansion) 9942660Smarkm return (expansion); 10021495Sjmacd 10121495Sjmacd /* If we have the full path to this file, we still may have to add 10242660Smarkm various extensions to it. I guess we have to stat this file 10342660Smarkm after all. */ 10456160Sru if (IS_ABSOLUTE (partial)) 10556160Sru temp = info_absolute_file (partial); 10621495Sjmacd else if (initial_character == '~') 10742660Smarkm { 10842660Smarkm expansion = tilde_expand_word (partial); 10956160Sru if (IS_ABSOLUTE (expansion)) 11042660Smarkm { 11156160Sru temp = info_absolute_file (expansion); 11242660Smarkm free (expansion); 11342660Smarkm } 11442660Smarkm else 11542660Smarkm temp = expansion; 11642660Smarkm } 11721495Sjmacd else if (initial_character == '.' && 11856160Sru (IS_SLASH (partial[1]) || 11956160Sru (partial[1] == '.' && IS_SLASH (partial[2])))) 12042660Smarkm { 12142660Smarkm if (local_temp_filename_size < 1024) 12242660Smarkm local_temp_filename = (char *)xrealloc 12342660Smarkm (local_temp_filename, (local_temp_filename_size = 1024)); 12421495Sjmacd#if defined (HAVE_GETCWD) 12542660Smarkm if (!getcwd (local_temp_filename, local_temp_filename_size)) 12621495Sjmacd#else /* !HAVE_GETCWD */ 12742660Smarkm if (!getwd (local_temp_filename)) 12821495Sjmacd#endif /* !HAVE_GETCWD */ 12942660Smarkm { 13042660Smarkm filesys_error_number = errno; 13142660Smarkm return (partial); 13242660Smarkm } 13321495Sjmacd 13442660Smarkm strcat (local_temp_filename, "/"); 13542660Smarkm strcat (local_temp_filename, partial); 13656160Sru temp = info_absolute_file (local_temp_filename); /* try extensions */ 13756160Sru if (!temp) 13856160Sru partial = local_temp_filename; 13942660Smarkm } 14021495Sjmacd else 14142660Smarkm temp = info_file_in_path (partial, infopath); 14221495Sjmacd 14321495Sjmacd if (temp) 14442660Smarkm { 14542660Smarkm remember_info_filename (partial, temp); 146146515Sru if (strlen (temp) > (unsigned int) local_temp_filename_size) 14742660Smarkm local_temp_filename = (char *) xrealloc 14842660Smarkm (local_temp_filename, 14942660Smarkm (local_temp_filename_size = (50 + strlen (temp)))); 15042660Smarkm strcpy (local_temp_filename, temp); 15142660Smarkm free (temp); 15242660Smarkm return (local_temp_filename); 15342660Smarkm } 15421495Sjmacd } 15521495Sjmacd return (partial); 15621495Sjmacd} 15721495Sjmacd 15821495Sjmacd/* Scan the list of directories in PATH looking for FILENAME. If we find 15921495Sjmacd one that is a regular file, return it as a new string. Otherwise, return 16021495Sjmacd a NULL pointer. */ 16121495Sjmacdstatic char * 162146515Sruinfo_file_in_path (char *filename, char *path) 16321495Sjmacd{ 16421495Sjmacd struct stat finfo; 16521495Sjmacd char *temp_dirname; 16621495Sjmacd int statable, dirname_index; 16721495Sjmacd 16893139Sru /* Reject ridiculous cases up front, to prevent infinite recursion 16993139Sru later on. E.g., someone might say "info '(.)foo'"... */ 17093139Sru if (!*filename || STREQ (filename, ".") || STREQ (filename, "..")) 17193139Sru return NULL; 17293139Sru 17321495Sjmacd dirname_index = 0; 17421495Sjmacd 17542660Smarkm while ((temp_dirname = extract_colon_unit (path, &dirname_index))) 17621495Sjmacd { 17721495Sjmacd register int i, pre_suffix_length; 17821495Sjmacd char *temp; 17921495Sjmacd 18021495Sjmacd /* Expand a leading tilde if one is present. */ 18121495Sjmacd if (*temp_dirname == '~') 18242660Smarkm { 18342660Smarkm char *expanded_dirname; 18421495Sjmacd 18542660Smarkm expanded_dirname = tilde_expand_word (temp_dirname); 18642660Smarkm free (temp_dirname); 18742660Smarkm temp_dirname = expanded_dirname; 18842660Smarkm } 18921495Sjmacd 19021495Sjmacd temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename)); 19121495Sjmacd strcpy (temp, temp_dirname); 19256160Sru if (!IS_SLASH (temp[(strlen (temp)) - 1])) 19342660Smarkm strcat (temp, "/"); 19421495Sjmacd strcat (temp, filename); 19521495Sjmacd 19621495Sjmacd pre_suffix_length = strlen (temp); 19721495Sjmacd 19821495Sjmacd free (temp_dirname); 19921495Sjmacd 20021495Sjmacd for (i = 0; info_suffixes[i]; i++) 20142660Smarkm { 20242660Smarkm strcpy (temp + pre_suffix_length, info_suffixes[i]); 20321495Sjmacd 20442660Smarkm statable = (stat (temp, &finfo) == 0); 20521495Sjmacd 20642660Smarkm /* If we have found a regular file, then use that. Else, if we 20742660Smarkm have found a directory, look in that directory for this file. */ 20842660Smarkm if (statable) 20942660Smarkm { 21042660Smarkm if (S_ISREG (finfo.st_mode)) 21142660Smarkm { 21242660Smarkm return (temp); 21342660Smarkm } 21442660Smarkm else if (S_ISDIR (finfo.st_mode)) 21542660Smarkm { 21642660Smarkm char *newpath, *filename_only, *newtemp; 21721495Sjmacd 21842660Smarkm newpath = xstrdup (temp); 21942660Smarkm filename_only = filename_non_directory (filename); 22042660Smarkm newtemp = info_file_in_path (filename_only, newpath); 22121495Sjmacd 22242660Smarkm free (newpath); 22342660Smarkm if (newtemp) 22442660Smarkm { 22542660Smarkm free (temp); 22642660Smarkm return (newtemp); 22742660Smarkm } 22842660Smarkm } 22942660Smarkm } 23042660Smarkm else 23142660Smarkm { 23242660Smarkm /* Add various compression suffixes to the name to see if 23342660Smarkm the file is present in compressed format. */ 23442660Smarkm register int j, pre_compress_suffix_length; 23521495Sjmacd 23642660Smarkm pre_compress_suffix_length = strlen (temp); 23721495Sjmacd 23842660Smarkm for (j = 0; compress_suffixes[j].suffix; j++) 23942660Smarkm { 24042660Smarkm strcpy (temp + pre_compress_suffix_length, 24142660Smarkm compress_suffixes[j].suffix); 24221495Sjmacd 24342660Smarkm statable = (stat (temp, &finfo) == 0); 24442660Smarkm if (statable && (S_ISREG (finfo.st_mode))) 24542660Smarkm return (temp); 24642660Smarkm } 24742660Smarkm } 24842660Smarkm } 24921495Sjmacd free (temp); 25021495Sjmacd } 25121495Sjmacd return ((char *)NULL); 25221495Sjmacd} 25321495Sjmacd 25456160Sru/* Assume FNAME is an absolute file name, and check whether it is 25556160Sru a regular file. If it is, return it as a new string; otherwise 25656160Sru return a NULL pointer. We do it by taking the file name apart 25756160Sru into its directory and basename parts, and calling info_file_in_path.*/ 25856160Srustatic char * 259146515Sruinfo_absolute_file (char *fname) 26056160Sru{ 26156160Sru char *containing_dir = xstrdup (fname); 26256160Sru char *base = filename_non_directory (containing_dir); 26356160Sru 26456160Sru if (base > containing_dir) 26556160Sru base[-1] = '\0'; 26656160Sru 26756160Sru return info_file_in_path (filename_non_directory (fname), containing_dir); 26856160Sru} 26956160Sru 270114472Sru 271114472Sru/* Given a string containing units of information separated by the 272114472Sru PATH_SEP character, return the next one after IDX, or NULL if there 273114472Sru are no more. Advance IDX to the character after the colon. */ 274114472Sru 27521495Sjmacdchar * 276146515Sruextract_colon_unit (char *string, int *idx) 27721495Sjmacd{ 278146515Sru unsigned int i = (unsigned int) *idx; 279146515Sru unsigned int start = i; 28021495Sjmacd 281114472Sru if (!string || i >= strlen (string)) 282114472Sru return NULL; 28321495Sjmacd 284146515Sru if (!string[i]) /* end of string */ 285146515Sru return NULL; 286146515Sru 287114472Sru /* Advance to next PATH_SEP. */ 28856160Sru while (string[i] && string[i] != PATH_SEP[0]) 28921495Sjmacd i++; 29021495Sjmacd 291114472Sru { 292114472Sru char *value = xmalloc ((i - start) + 1); 293114472Sru strncpy (value, &string[start], (i - start)); 294114472Sru value[i - start] = 0; 295114472Sru 296114472Sru i++; /* move past PATH_SEP */ 297114472Sru *idx = i; 298114472Sru return value; 299114472Sru } 30021495Sjmacd} 30121495Sjmacd 30221495Sjmacd/* A structure which associates a filename with its expansion. */ 303114472Srutypedef struct 304114472Sru{ 30521495Sjmacd char *filename; 30621495Sjmacd char *expansion; 30721495Sjmacd} FILENAME_LIST; 30821495Sjmacd 30921495Sjmacd/* An array of remembered arguments and results. */ 31021495Sjmacdstatic FILENAME_LIST **names_and_files = (FILENAME_LIST **)NULL; 31121495Sjmacdstatic int names_and_files_index = 0; 31221495Sjmacdstatic int names_and_files_slots = 0; 31321495Sjmacd 31421495Sjmacd/* Find the result for having already called info_find_fullpath () with 31521495Sjmacd FILENAME. */ 31621495Sjmacdstatic char * 317146515Srulookup_info_filename (char *filename) 31821495Sjmacd{ 31921495Sjmacd if (filename && names_and_files) 32021495Sjmacd { 32121495Sjmacd register int i; 32221495Sjmacd for (i = 0; names_and_files[i]; i++) 32342660Smarkm { 32456160Sru if (FILENAME_CMP (names_and_files[i]->filename, filename) == 0) 32542660Smarkm return (names_and_files[i]->expansion); 32642660Smarkm } 32721495Sjmacd } 32821495Sjmacd return (char *)NULL;; 32921495Sjmacd} 33021495Sjmacd 33121495Sjmacd/* Add a filename and its expansion to our list. */ 33221495Sjmacdstatic void 333146515Sruremember_info_filename (char *filename, char *expansion) 33421495Sjmacd{ 33521495Sjmacd FILENAME_LIST *new; 33621495Sjmacd 33721495Sjmacd if (names_and_files_index + 2 > names_and_files_slots) 33821495Sjmacd { 33921495Sjmacd int alloc_size; 34021495Sjmacd names_and_files_slots += 10; 34121495Sjmacd 34221495Sjmacd alloc_size = names_and_files_slots * sizeof (FILENAME_LIST *); 34321495Sjmacd 34421495Sjmacd names_and_files = 34542660Smarkm (FILENAME_LIST **) xrealloc (names_and_files, alloc_size); 34621495Sjmacd } 34721495Sjmacd 34821495Sjmacd new = (FILENAME_LIST *)xmalloc (sizeof (FILENAME_LIST)); 34942660Smarkm new->filename = xstrdup (filename); 35042660Smarkm new->expansion = expansion ? xstrdup (expansion) : (char *)NULL; 35121495Sjmacd 35221495Sjmacd names_and_files[names_and_files_index++] = new; 35321495Sjmacd names_and_files[names_and_files_index] = (FILENAME_LIST *)NULL; 35421495Sjmacd} 35521495Sjmacd 35621495Sjmacdstatic void 357146515Srumaybe_initialize_infopath (void) 35821495Sjmacd{ 35921495Sjmacd if (!infopath_size) 36021495Sjmacd { 36121495Sjmacd infopath = (char *) 36242660Smarkm xmalloc (infopath_size = (1 + strlen (DEFAULT_INFOPATH))); 36321495Sjmacd 36421495Sjmacd strcpy (infopath, DEFAULT_INFOPATH); 36521495Sjmacd } 36621495Sjmacd} 36721495Sjmacd 36821495Sjmacd/* Add PATH to the list of paths found in INFOPATH. 2nd argument says 36921495Sjmacd whether to put PATH at the front or end of INFOPATH. */ 37021495Sjmacdvoid 371146515Sruinfo_add_path (char *path, int where) 37221495Sjmacd{ 37321495Sjmacd int len; 37421495Sjmacd 37521495Sjmacd if (!infopath) 37621495Sjmacd { 37721495Sjmacd infopath = (char *)xmalloc (infopath_size = 200 + strlen (path)); 37821495Sjmacd infopath[0] = '\0'; 37921495Sjmacd } 38021495Sjmacd 38121495Sjmacd len = strlen (path) + strlen (infopath); 38221495Sjmacd 38321495Sjmacd if (len + 2 >= infopath_size) 38421495Sjmacd infopath = (char *)xrealloc (infopath, (infopath_size += (2 * len) + 2)); 38521495Sjmacd 38621495Sjmacd if (!*infopath) 38721495Sjmacd strcpy (infopath, path); 38821495Sjmacd else if (where == INFOPATH_APPEND) 38921495Sjmacd { 39056160Sru strcat (infopath, PATH_SEP); 39121495Sjmacd strcat (infopath, path); 39221495Sjmacd } 39321495Sjmacd else if (where == INFOPATH_PREPEND) 39421495Sjmacd { 39542660Smarkm char *temp = xstrdup (infopath); 39621495Sjmacd strcpy (infopath, path); 39756160Sru strcat (infopath, PATH_SEP); 39821495Sjmacd strcat (infopath, temp); 39921495Sjmacd free (temp); 40021495Sjmacd } 40121495Sjmacd} 40221495Sjmacd 40321495Sjmacd/* Make INFOPATH have absolutely nothing in it. */ 40421495Sjmacdvoid 405146515Sruzap_infopath (void) 40621495Sjmacd{ 40721495Sjmacd if (infopath) 40821495Sjmacd free (infopath); 40921495Sjmacd 41021495Sjmacd infopath = (char *)NULL; 41121495Sjmacd infopath_size = 0; 41221495Sjmacd} 41321495Sjmacd 41456160Sru/* Given a chunk of text and its length, convert all CRLF pairs at every 41556160Sru end-of-line into a single Newline character. Return the length of 41656160Sru produced text. 41756160Sru 41856160Sru This is required because the rest of code is too entrenched in having 41956160Sru a single newline at each EOL; in particular, searching for various 42056160Sru Info headers and cookies can become extremely tricky if that assumption 42156160Sru breaks. 42256160Sru 42356160Sru FIXME: this could also support Mac-style text files with a single CR 42456160Sru at the EOL, but what about random CR characters in non-Mac files? Can 42556160Sru we afford converting them into newlines as well? Maybe implement some 42656160Sru heuristics here, like in Emacs 20. 42756160Sru 42856160Sru FIXME: is it a good idea to show the EOL type on the modeline? */ 42956160Srulong 430146515Sruconvert_eols (char *text, long int textlen) 43156160Sru{ 43256160Sru register char *s = text; 43356160Sru register char *d = text; 43456160Sru 43556160Sru while (textlen--) 43656160Sru { 43756160Sru if (*s == '\r' && textlen && s[1] == '\n') 43856160Sru { 43956160Sru s++; 44056160Sru textlen--; 44156160Sru } 44256160Sru *d++ = *s++; 44356160Sru } 44456160Sru 44556160Sru return (long)(d - text); 44656160Sru} 44756160Sru 44821495Sjmacd/* Read the contents of PATHNAME, returning a buffer with the contents of 44921495Sjmacd that file in it, and returning the size of that buffer in FILESIZE. 45021495Sjmacd FINFO is a stat struct which has already been filled in by the caller. 45156160Sru If the file turns out to be compressed, set IS_COMPRESSED to non-zero. 45221495Sjmacd If the file cannot be read, return a NULL pointer. */ 45321495Sjmacdchar * 454146515Srufilesys_read_info_file (char *pathname, long int *filesize, 455146515Sru struct stat *finfo, int *is_compressed) 45621495Sjmacd{ 45721495Sjmacd long st_size; 45821495Sjmacd 45921495Sjmacd *filesize = filesys_error_number = 0; 46021495Sjmacd 46121495Sjmacd if (compressed_filename_p (pathname)) 46256160Sru { 46356160Sru *is_compressed = 1; 464146515Sru return (filesys_read_compressed (pathname, filesize)); 46556160Sru } 46621495Sjmacd else 46721495Sjmacd { 46821495Sjmacd int descriptor; 46921495Sjmacd char *contents; 47021495Sjmacd 47156160Sru *is_compressed = 0; 47256160Sru descriptor = open (pathname, O_RDONLY | O_BINARY, 0666); 47321495Sjmacd 47421495Sjmacd /* If the file couldn't be opened, give up. */ 47521495Sjmacd if (descriptor < 0) 47642660Smarkm { 47742660Smarkm filesys_error_number = errno; 47842660Smarkm return ((char *)NULL); 47942660Smarkm } 48021495Sjmacd 48121495Sjmacd /* Try to read the contents of this file. */ 48221495Sjmacd st_size = (long) finfo->st_size; 48321495Sjmacd contents = (char *)xmalloc (1 + st_size); 48421495Sjmacd if ((read (descriptor, contents, st_size)) != st_size) 48542660Smarkm { 48656160Sru filesys_error_number = errno; 48756160Sru close (descriptor); 48856160Sru free (contents); 48956160Sru return ((char *)NULL); 49042660Smarkm } 49121495Sjmacd 49221495Sjmacd close (descriptor); 49321495Sjmacd 49456160Sru /* Convert any DOS-style CRLF EOLs into Unix-style NL. 49556160Sru Seems like a good idea to have even on Unix, in case the Info 49656160Sru files are coming from some Windows system across a network. */ 49756160Sru *filesize = convert_eols (contents, st_size); 49856160Sru 49956160Sru /* EOL conversion can shrink the text quite a bit. We don't 50056160Sru want to waste storage. */ 50156160Sru if (*filesize < st_size) 50256160Sru contents = (char *)xrealloc (contents, 1 + *filesize); 503100513Sru contents[*filesize] = '\0'; 50456160Sru 50521495Sjmacd return (contents); 50621495Sjmacd } 50721495Sjmacd} 50821495Sjmacd 50921495Sjmacd/* Typically, pipe buffers are 4k. */ 51021495Sjmacd#define BASIC_PIPE_BUFFER (4 * 1024) 51121495Sjmacd 51221495Sjmacd/* We use some large multiple of that. */ 51321495Sjmacd#define FILESYS_PIPE_BUFFER_SIZE (16 * BASIC_PIPE_BUFFER) 51421495Sjmacd 51521495Sjmacdchar * 516146515Srufilesys_read_compressed (char *pathname, long int *filesize) 51721495Sjmacd{ 51821495Sjmacd FILE *stream; 51921495Sjmacd char *command, *decompressor; 52021495Sjmacd char *contents = (char *)NULL; 52121495Sjmacd 52221495Sjmacd *filesize = filesys_error_number = 0; 52321495Sjmacd 52421495Sjmacd decompressor = filesys_decompressor_for_file (pathname); 52521495Sjmacd 52621495Sjmacd if (!decompressor) 52721495Sjmacd return ((char *)NULL); 52821495Sjmacd 52956160Sru command = (char *)xmalloc (15 + strlen (pathname) + strlen (decompressor)); 53056160Sru /* Explicit .exe suffix makes the diagnostics of `popen' 53156160Sru better on systems where COMMAND.COM is the stock shell. */ 53256160Sru sprintf (command, "%s%s < %s", 53356160Sru decompressor, STRIP_DOT_EXE ? ".exe" : "", pathname); 53421495Sjmacd 53521495Sjmacd#if !defined (BUILDING_LIBRARY) 53621495Sjmacd if (info_windows_initialized_p) 53721495Sjmacd { 53821495Sjmacd char *temp; 53921495Sjmacd 54021495Sjmacd temp = (char *)xmalloc (5 + strlen (command)); 54121495Sjmacd sprintf (temp, "%s...", command); 542146515Sru message_in_echo_area ("%s", temp, NULL); 54321495Sjmacd free (temp); 54421495Sjmacd } 54521495Sjmacd#endif /* !BUILDING_LIBRARY */ 54621495Sjmacd 54756160Sru stream = popen (command, FOPEN_RBIN); 54821495Sjmacd free (command); 54921495Sjmacd 55021495Sjmacd /* Read chunks from this file until there are none left to read. */ 55121495Sjmacd if (stream) 55221495Sjmacd { 55393139Sru long offset, size; 55421495Sjmacd char *chunk; 55521495Sjmacd 55621495Sjmacd offset = size = 0; 55721495Sjmacd chunk = (char *)xmalloc (FILESYS_PIPE_BUFFER_SIZE); 55821495Sjmacd 55921495Sjmacd while (1) 56042660Smarkm { 56142660Smarkm int bytes_read; 56221495Sjmacd 56342660Smarkm bytes_read = fread (chunk, 1, FILESYS_PIPE_BUFFER_SIZE, stream); 56421495Sjmacd 56542660Smarkm if (bytes_read + offset >= size) 56642660Smarkm contents = (char *)xrealloc 56742660Smarkm (contents, size += (2 * FILESYS_PIPE_BUFFER_SIZE)); 56821495Sjmacd 56942660Smarkm memcpy (contents + offset, chunk, bytes_read); 57042660Smarkm offset += bytes_read; 57142660Smarkm if (bytes_read != FILESYS_PIPE_BUFFER_SIZE) 57242660Smarkm break; 57342660Smarkm } 57421495Sjmacd 57521495Sjmacd free (chunk); 57656160Sru if (pclose (stream) == -1) 57756160Sru { 57856160Sru if (contents) 57956160Sru free (contents); 58056160Sru contents = (char *)NULL; 58156160Sru filesys_error_number = errno; 58256160Sru } 58356160Sru else 58456160Sru { 58556160Sru *filesize = convert_eols (contents, offset); 58656160Sru contents = (char *)xrealloc (contents, 1 + *filesize); 587100513Sru contents[*filesize] = '\0'; 58856160Sru } 58921495Sjmacd } 59021495Sjmacd else 59121495Sjmacd { 59221495Sjmacd filesys_error_number = errno; 59321495Sjmacd } 59421495Sjmacd 59521495Sjmacd#if !defined (BUILDING_LIBARARY) 59621495Sjmacd if (info_windows_initialized_p) 59721495Sjmacd unmessage_in_echo_area (); 59821495Sjmacd#endif /* !BUILDING_LIBRARY */ 59921495Sjmacd return (contents); 60021495Sjmacd} 60121495Sjmacd 60221495Sjmacd/* Return non-zero if FILENAME belongs to a compressed file. */ 60321495Sjmacdint 604146515Srucompressed_filename_p (char *filename) 60521495Sjmacd{ 60621495Sjmacd char *decompressor; 60721495Sjmacd 60821495Sjmacd /* Find the final extension of this filename, and see if it matches one 60921495Sjmacd of our known ones. */ 61021495Sjmacd decompressor = filesys_decompressor_for_file (filename); 61121495Sjmacd 61221495Sjmacd if (decompressor) 61321495Sjmacd return (1); 61421495Sjmacd else 61521495Sjmacd return (0); 61621495Sjmacd} 61721495Sjmacd 61821495Sjmacd/* Return the command string that would be used to decompress FILENAME. */ 61921495Sjmacdchar * 620146515Srufilesys_decompressor_for_file (char *filename) 62121495Sjmacd{ 62221495Sjmacd register int i; 62321495Sjmacd char *extension = (char *)NULL; 62421495Sjmacd 62521495Sjmacd /* Find the final extension of FILENAME, and see if it appears in our 62621495Sjmacd list of known compression extensions. */ 62721495Sjmacd for (i = strlen (filename) - 1; i > 0; i--) 62821495Sjmacd if (filename[i] == '.') 62921495Sjmacd { 63042660Smarkm extension = filename + i; 63142660Smarkm break; 63221495Sjmacd } 63321495Sjmacd 63421495Sjmacd if (!extension) 63521495Sjmacd return ((char *)NULL); 63621495Sjmacd 63721495Sjmacd for (i = 0; compress_suffixes[i].suffix; i++) 63856160Sru if (FILENAME_CMP (extension, compress_suffixes[i].suffix) == 0) 63921495Sjmacd return (compress_suffixes[i].decompressor); 64021495Sjmacd 64156160Sru#if defined (__MSDOS__) 64256160Sru /* If no other suffix matched, allow any extension which ends 64356160Sru with `z' to be decompressed by gunzip. Due to limited 8+3 DOS 64456160Sru file namespace, we can expect many such cases, and supporting 64556160Sru every weird suffix thus produced would be a pain. */ 64656160Sru if (extension[strlen (extension) - 1] == 'z' || 64756160Sru extension[strlen (extension) - 1] == 'Z') 64856160Sru return "gunzip"; 64956160Sru#endif 65056160Sru 65121495Sjmacd return ((char *)NULL); 65221495Sjmacd} 65321495Sjmacd 65421495Sjmacd/* The number of the most recent file system error. */ 65521495Sjmacdint filesys_error_number = 0; 65621495Sjmacd 65721495Sjmacd/* A function which returns a pointer to a static buffer containing 65821495Sjmacd an error message for FILENAME and ERROR_NUM. */ 65921495Sjmacdstatic char *errmsg_buf = (char *)NULL; 66021495Sjmacdstatic int errmsg_buf_size = 0; 66121495Sjmacd 66221495Sjmacdchar * 663146515Srufilesys_error_string (char *filename, int error_num) 66421495Sjmacd{ 66521495Sjmacd int len; 66621495Sjmacd char *result; 66721495Sjmacd 66821495Sjmacd if (error_num == 0) 66921495Sjmacd return ((char *)NULL); 67021495Sjmacd 67121495Sjmacd result = strerror (error_num); 67221495Sjmacd 67321495Sjmacd len = 4 + strlen (filename) + strlen (result); 67421495Sjmacd if (len >= errmsg_buf_size) 67521495Sjmacd errmsg_buf = (char *)xrealloc (errmsg_buf, (errmsg_buf_size = 2 + len)); 67621495Sjmacd 67721495Sjmacd sprintf (errmsg_buf, "%s: %s", filename, result); 67821495Sjmacd return (errmsg_buf); 67921495Sjmacd} 68021495Sjmacd 68156160Sru 68293139Sru/* Check for "dir" with all the possible info and compression suffixes, 68393139Sru in combination. */ 68456160Sru 68556160Sruint 686146515Sruis_dir_name (char *filename) 68756160Sru{ 68856160Sru unsigned i; 68993139Sru 69093139Sru for (i = 0; info_suffixes[i]; i++) 69156160Sru { 69293139Sru unsigned c; 69393139Sru char trydir[50]; 69493139Sru strcpy (trydir, "dir"); 69593139Sru strcat (trydir, info_suffixes[i]); 69693139Sru 69793139Sru if (strcasecmp (filename, trydir) == 0) 69856160Sru return 1; 69993139Sru 70093139Sru for (c = 0; compress_suffixes[c].suffix; c++) 70193139Sru { 70293139Sru char dir_compressed[50]; /* can be short */ 70393139Sru strcpy (dir_compressed, trydir); 70493139Sru strcat (dir_compressed, compress_suffixes[c].suffix); 70593139Sru if (strcasecmp (filename, dir_compressed) == 0) 70693139Sru return 1; 70793139Sru } 70893139Sru } 70993139Sru 71056160Sru return 0; 71156160Sru} 712