gno/bin/less/filename.c

370 lines
6.4 KiB
C
Raw Normal View History

/*
* Routines to mess around with filenames (and files).
* Much of this is very OS dependent.
*/
#pragma noroot
#include <stdio.h>
#include <string.h>
#include "less.h"
#include <fcntl.h>
#ifdef _ORCAC_
segment "LoadSegONE";
#endif
extern char *getenv(char *);
extern int force_open;
extern IFILE curr_ifile;
extern IFILE old_ifile;
static POSITION seek_filesize(int f);
/*
* Return the full pathname of the given file in the "home directory".
*/
public char *
homefile(filename)
char *filename;
{
register char *pathname;
register char *homedir;
homedir = getenv("HOME");
#if __MSDOS__
/*
* Most MSDOS users do not have $HOME defined,
* so if no $HOME then look for "_less" anywhere
* on search path (always begins at current directory).
*/
if (homedir == NULL)
{
extern char *searchpath();
pathname = searchpath(filename);
if (pathname == NULL)
return (NULL);
pathname = save(pathname);
} else
{
pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2,
sizeof(char));
if (pathname == NULL)
return (NULL);
sprintf(pathname, "%s\\%s", homedir, filename);
}
#else
if (homedir == NULL)
return (NULL);
pathname = (char *) calloc(strlen(homedir)+strlen(filename)+2,
sizeof(char));
if (pathname == NULL)
return (NULL);
sprintf(pathname, "%s/%s", homedir, filename);
#endif
return (pathname);
}
/*
* Find out where the help file is.
*/
public char *
find_helpfile(void)
{
register char *helpfile;
#if __MSDOS__
extern char *searchpath();
/*
* Look in current directory.
*/
if (access(HELPFILE,0) == 0)
return (HELPFILE);
/*
* Find the basename of HELPFILE,
* and look for it in each directory in the search path.
*/
if ((helpfile = strrchr(HELPFILE, '\\')) == NULL)
helpfile = HELPFILE;
else
helpfile++;
return (save(searchpath(helpfile)));
#else
if ((helpfile = getenv("LESSHELP")) != NULL)
return (save(helpfile));
return (save(HELPFILE));
#endif
}
/*
* Expand a string, substituting any "%" with the current filename,
* and any "#" with the previous filename.
*/
public char *
fexpand(s)
char *s;
{
register char *fr, *to;
register int n;
register char *e;
/*
* Make one pass to see how big a buffer we
* need to allocate for the expanded string.
*/
n = 0;
for (fr = s; *fr != '\0'; fr++)
{
switch (*fr)
{
case '%':
n += strlen(get_filename(curr_ifile));
break;
case '#':
if (old_ifile == NULL_IFILE)
{
error("No previous file", NULL_PARG);
return (NULL);
}
n += strlen(get_filename(old_ifile));
break;
default:
n++;
break;
}
}
e = (char *) ecalloc(n+1, sizeof(char));
/*
* Now copy the string, expanding any "%" or "#".
*/
to = e;
for (fr = s; *fr != '\0'; fr++)
{
switch (*fr)
{
case '%':
strcpy(to, get_filename(curr_ifile));
to += strlen(to);
break;
case '#':
strcpy(to, get_filename(old_ifile));
to += strlen(to);
break;
default:
*to++ = *fr;
break;
}
}
*to = '\0';
return (e);
}
/*
* Try to determine if a file is "binary".
* This is just a guess, and we need not try too hard to make it accurate.
*/
int
bin_file(f)
int f;
{
int i;
int n;
char data[64];
n = read(f, data, sizeof(data));
for (i = 0; i < n; i++)
if (binary_char((int) data[i]))
return (1);
return (0);
}
/*
* Try to determine the size of a file by seeking to the end.
*/
static POSITION
seek_filesize(f)
int f;
{
offset_t spos;
spos = lseek(f, (offset_t)0, 2);
if (spos == BAD_LSEEK)
return (NULL_POSITION);
return ((POSITION) spos);
}
/*
* Expand a filename, substituting any environment variables, etc.
*/
#if GLOB
FILE *popen(char *command, char *type);
public char *
glob(filename)
char *filename;
{
FILE *f;
char *p;
int ch;
int len;
char *cmd;
char *gfilename;
filename = fexpand(filename);
if (filename == NULL)
return (NULL);
/*
* We get the shell to expand the filename for us by passing
* an "echo" command to the shell and reading its output.
*/
p = getenv("SHELL");
if (p == NULL || *p == '\0')
{
/*
* Read the output of <echo filename>.
*/
cmd = (char *) ecalloc(strlen(filename)+6, sizeof(char));
sprintf(cmd, "echo %s", filename);
} else
{
/*
* Read the output of <$SHELL -c "echo filename">.
*/
cmd = (char *) ecalloc(strlen(p)+strlen(filename)+12, sizeof(char));
sprintf(cmd, "%s -c \"echo %s\"", p, filename);
}
f = popen(cmd, "r");
free(cmd);
if (f == NULL)
return (filename);
free(filename);
len = 100;
gfilename = (char *) ecalloc(len, sizeof(char));
for (p = gfilename; ; p++)
{
if ((ch = getc(f)) == '\n' || ch == EOF)
break;
if (p - gfilename >= len-1)
{
len *= 2;
*p = '\0';
p = (char *) ecalloc(len, sizeof(char));
strcpy(p, gfilename);
free(gfilename);
gfilename = p;
p = gfilename + strlen(gfilename);
}
*p = ch;
}
*p = '\0';
pclose(f);
if (*gfilename == '\0')
return (NULL);
return (gfilename);
}
#else
public char *
glob(filename)
char *filename;
{
return (fexpand(filename));
}
#endif
#if STAT
#include <sys/types.h>
#include <sys/stat.h>
/*
* Returns NULL if the file can be opened and
* is an ordinary file, otherwise an error message
* (if it cannot be opened or is a directory, etc.)
*/
public char *
bad_file(filename)
char *filename;
{
register char *m;
struct stat statbuf;
if (stat(filename, &statbuf) < 0)
return (errno_message(filename));
if (force_open)
return (NULL);
if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
{
static char is_dir[] = " is a directory";
m = (char *) ecalloc(strlen(filename) + sizeof(is_dir),
sizeof(char));
strcpy(m, filename);
strcat(m, is_dir);
return (m);
}
if ((statbuf.st_mode & S_IFMT) != S_IFREG)
{
static char not_reg[] = " is not a regular file";
m = (char *) ecalloc(strlen(filename) + sizeof(not_reg),
sizeof(char));
strcpy(m, filename);
strcat(m, not_reg);
return (m);
}
return (NULL);
}
/*
* Return the size of a file, as cheaply as possible.
* In Unix, we can stat the file.
*/
public POSITION
filesize(f)
int f;
{
struct stat statbuf;
if (fstat(f, &statbuf) < 0)
/*
* Can't stat; try seeking to the end.
*/
return (seek_filesize(f));
return ((POSITION) statbuf.st_size);
}
#else
/*
* If we have no way to find out, just say the file is good.
*/
public char *
bad_file(filename)
char *filename;
{
return (NULL);
}
/*
* We can find the file size by seeking.
*/
public POSITION
filesize(f)
int f;
{
return (seek_filesize(f));
}
#endif