gno/bin/less/filename.c
gdr-ftp 784e3de7cd Initial checkin of aroff, binprint, center, less, ls, make, makemake,
passwd, ps, purge, shutdown, stty, upper, and vi.  These sources are
for the versions of the utils shipped with GNO v2.0.4.
1998-03-09 08:30:21 +00:00

370 lines
6.4 KiB
C

/*
* 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