#include "info.h"
#include "tilde.h"
#include "filesys.h"
static char *info_file_in_path (), *lookup_info_filename ();
static void remember_info_filename (), maybe_initialize_infopath ();
typedef struct
{
char *suffix;
char *decompressor;
} COMPRESSION_ALIST;
static char *info_suffixes[] = {
"",
".info",
"-info",
"/index",
(char *)NULL
};
static COMPRESSION_ALIST compress_suffixes[] = {
{ ".Z", "uncompress" },
{ ".Y", "unyabba" },
{ ".z", "gunzip" },
{ ".gz", "gunzip" },
{ (char *)NULL, (char *)NULL }
};
char *infopath = (char *)NULL;
static int infopath_size = 0;
static char *local_temp_filename = (char *)NULL;
static int local_temp_filename_size = 0;
char *
info_find_fullpath (partial)
char *partial;
{
int initial_character;
char *temp;
filesys_error_number = 0;
maybe_initialize_infopath ();
if (partial && (initial_character = *partial))
{
char *expansion;
expansion = lookup_info_filename (partial);
if (expansion)
return (expansion);
if (initial_character == '/')
temp = info_file_in_path (partial + 1, "/");
else if (initial_character == '~')
{
expansion = tilde_expand_word (partial);
if (*expansion == '/')
{
temp = info_file_in_path (expansion + 1, "/");
free (expansion);
}
else
temp = expansion;
}
else if (initial_character == '.' &&
(partial[1] == '/' || (partial[1] == '.' && partial[2] == '/')))
{
if (local_temp_filename_size < 1024)
local_temp_filename = (char *)xrealloc
(local_temp_filename, (local_temp_filename_size = 1024));
#if defined (HAVE_GETCWD)
if (!getcwd (local_temp_filename, local_temp_filename_size))
#else
if (!getwd (local_temp_filename))
#endif
{
filesys_error_number = errno;
return (partial);
}
strcat (local_temp_filename, "/");
strcat (local_temp_filename, partial);
return (local_temp_filename);
}
else
temp = info_file_in_path (partial, infopath);
if (temp)
{
remember_info_filename (partial, temp);
if (strlen (temp) > local_temp_filename_size)
local_temp_filename = (char *) xrealloc
(local_temp_filename,
(local_temp_filename_size = (50 + strlen (temp))));
strcpy (local_temp_filename, temp);
free (temp);
return (local_temp_filename);
}
}
return (partial);
}
static char *
info_file_in_path (filename, path)
char *filename, *path;
{
struct stat finfo;
char *temp_dirname;
int statable, dirname_index;
dirname_index = 0;
while ((temp_dirname = extract_colon_unit (path, &dirname_index)))
{
register int i, pre_suffix_length;
char *temp;
if (*temp_dirname == '~')
{
char *expanded_dirname;
expanded_dirname = tilde_expand_word (temp_dirname);
free (temp_dirname);
temp_dirname = expanded_dirname;
}
temp = (char *)xmalloc (30 + strlen (temp_dirname) + strlen (filename));
strcpy (temp, temp_dirname);
if (temp[(strlen (temp)) - 1] != '/')
strcat (temp, "/");
strcat (temp, filename);
pre_suffix_length = strlen (temp);
free (temp_dirname);
for (i = 0; info_suffixes[i]; i++)
{
strcpy (temp + pre_suffix_length, info_suffixes[i]);
statable = (stat (temp, &finfo) == 0);
if (statable)
{
if (S_ISREG (finfo.st_mode))
{
return (temp);
}
else if (S_ISDIR (finfo.st_mode))
{
char *newpath, *filename_only, *newtemp;
newpath = xstrdup (temp);
filename_only = filename_non_directory (filename);
newtemp = info_file_in_path (filename_only, newpath);
free (newpath);
if (newtemp)
{
free (temp);
return (newtemp);
}
}
}
else
{
register int j, pre_compress_suffix_length;
pre_compress_suffix_length = strlen (temp);
for (j = 0; compress_suffixes[j].suffix; j++)
{
strcpy (temp + pre_compress_suffix_length,
compress_suffixes[j].suffix);
statable = (stat (temp, &finfo) == 0);
if (statable && (S_ISREG (finfo.st_mode)))
return (temp);
}
}
}
free (temp);
}
return ((char *)NULL);
}
char *
extract_colon_unit (string, idx)
char *string;
int *idx;
{
register int i, start;
i = start = *idx;
if ((i >= strlen (string)) || !string)
return ((char *) NULL);
while (string[i] && string[i] != ':')
i++;
if (i == start)
{
return ((char *) NULL);
}
else
{
char *value;
value = (char *) xmalloc (1 + (i - start));
strncpy (value, &string[start], (i - start));
value[i - start] = '\0';
if (string[i])
++i;
*idx = i;
return (value);
}
}
typedef struct {
char *filename;
char *expansion;
} FILENAME_LIST;
static FILENAME_LIST **names_and_files = (FILENAME_LIST **)NULL;
static int names_and_files_index = 0;
static int names_and_files_slots = 0;
static char *
lookup_info_filename (filename)
char *filename;
{
if (filename && names_and_files)
{
register int i;
for (i = 0; names_and_files[i]; i++)
{
if (strcmp (names_and_files[i]->filename, filename) == 0)
return (names_and_files[i]->expansion);
}
}
return (char *)NULL;;
}
static void
remember_info_filename (filename, expansion)
char *filename, *expansion;
{
FILENAME_LIST *new;
if (names_and_files_index + 2 > names_and_files_slots)
{
int alloc_size;
names_and_files_slots += 10;
alloc_size = names_and_files_slots * sizeof (FILENAME_LIST *);
names_and_files =
(FILENAME_LIST **) xrealloc (names_and_files, alloc_size);
}
new = (FILENAME_LIST *)xmalloc (sizeof (FILENAME_LIST));
new->filename = xstrdup (filename);
new->expansion = expansion ? xstrdup (expansion) : (char *)NULL;
names_and_files[names_and_files_index++] = new;
names_and_files[names_and_files_index] = (FILENAME_LIST *)NULL;
}
static void
maybe_initialize_infopath ()
{
if (!infopath_size)
{
infopath = (char *)
xmalloc (infopath_size = (1 + strlen (DEFAULT_INFOPATH)));
strcpy (infopath, DEFAULT_INFOPATH);
}
}
void
info_add_path (path, where)
char *path;
int where;
{
int len;
if (!infopath)
{
infopath = (char *)xmalloc (infopath_size = 200 + strlen (path));
infopath[0] = '\0';
}
len = strlen (path) + strlen (infopath);
if (len + 2 >= infopath_size)
infopath = (char *)xrealloc (infopath, (infopath_size += (2 * len) + 2));
if (!*infopath)
strcpy (infopath, path);
else if (where == INFOPATH_APPEND)
{
strcat (infopath, ":");
strcat (infopath, path);
}
else if (where == INFOPATH_PREPEND)
{
char *temp = xstrdup (infopath);
strcpy (infopath, path);
strcat (infopath, ":");
strcat (infopath, temp);
free (temp);
}
}
void
zap_infopath ()
{
if (infopath)
free (infopath);
infopath = (char *)NULL;
infopath_size = 0;
}
char *
filesys_read_info_file (pathname, filesize, finfo)
char *pathname;
long *filesize;
struct stat *finfo;
{
long st_size;
*filesize = filesys_error_number = 0;
if (compressed_filename_p (pathname))
return (filesys_read_compressed (pathname, filesize, finfo));
else
{
int descriptor;
char *contents;
descriptor = open (pathname, O_RDONLY, 0666);
if (descriptor < 0)
{
filesys_error_number = errno;
return ((char *)NULL);
}
st_size = (long) finfo->st_size;
contents = (char *)xmalloc (1 + st_size);
if ((read (descriptor, contents, st_size)) != st_size)
{
filesys_error_number = errno;
close (descriptor);
free (contents);
return ((char *)NULL);
}
close (descriptor);
*filesize = st_size;
return (contents);
}
}
#define BASIC_PIPE_BUFFER (4 * 1024)
#define FILESYS_PIPE_BUFFER_SIZE (16 * BASIC_PIPE_BUFFER)
char *
filesys_read_compressed (pathname, filesize, finfo)
char *pathname;
long *filesize;
struct stat *finfo;
{
FILE *stream;
char *command, *decompressor;
char *contents = (char *)NULL;
*filesize = filesys_error_number = 0;
decompressor = filesys_decompressor_for_file (pathname);
if (!decompressor)
return ((char *)NULL);
command = (char *)xmalloc (10 + strlen (pathname) + strlen (decompressor));
sprintf (command, "%s < %s", decompressor, pathname);
#if !defined (BUILDING_LIBRARY)
if (info_windows_initialized_p)
{
char *temp;
temp = (char *)xmalloc (5 + strlen (command));
sprintf (temp, "%s...", command);
message_in_echo_area ("%s", temp);
free (temp);
}
#endif
stream = popen (command, "r");
free (command);
if (stream)
{
int offset, size;
char *chunk;
offset = size = 0;
chunk = (char *)xmalloc (FILESYS_PIPE_BUFFER_SIZE);
while (1)
{
int bytes_read;
bytes_read = fread (chunk, 1, FILESYS_PIPE_BUFFER_SIZE, stream);
if (bytes_read + offset >= size)
contents = (char *)xrealloc
(contents, size += (2 * FILESYS_PIPE_BUFFER_SIZE));
memcpy (contents + offset, chunk, bytes_read);
offset += bytes_read;
if (bytes_read != FILESYS_PIPE_BUFFER_SIZE)
break;
}
free (chunk);
pclose (stream);
contents = (char *)xrealloc (contents, offset + 1);
*filesize = offset;
}
else
{
filesys_error_number = errno;
}
#if !defined (BUILDING_LIBARARY)
if (info_windows_initialized_p)
unmessage_in_echo_area ();
#endif
return (contents);
}
int
compressed_filename_p (filename)
char *filename;
{
char *decompressor;
decompressor = filesys_decompressor_for_file (filename);
if (decompressor)
return (1);
else
return (0);
}
char *
filesys_decompressor_for_file (filename)
char *filename;
{
register int i;
char *extension = (char *)NULL;
for (i = strlen (filename) - 1; i > 0; i--)
if (filename[i] == '.')
{
extension = filename + i;
break;
}
if (!extension)
return ((char *)NULL);
for (i = 0; compress_suffixes[i].suffix; i++)
if (strcmp (extension, compress_suffixes[i].suffix) == 0)
return (compress_suffixes[i].decompressor);
return ((char *)NULL);
}
int filesys_error_number = 0;
static char *errmsg_buf = (char *)NULL;
static int errmsg_buf_size = 0;
char *
filesys_error_string (filename, error_num)
char *filename;
int error_num;
{
int len;
char *result;
if (error_num == 0)
return ((char *)NULL);
result = strerror (error_num);
len = 4 + strlen (filename) + strlen (result);
if (len >= errmsg_buf_size)
errmsg_buf = (char *)xrealloc (errmsg_buf, (errmsg_buf_size = 2 + len));
sprintf (errmsg_buf, "%s: %s", filename, result);
return (errmsg_buf);
}