version 1.1.1.1, 1996/09/21 05:39:42 |
version 1.1.1.2, 2003/04/13 18:21:21 |
|
|
/* |
/* |
* Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman |
* Copyright (C) 1984-2002 Mark Nudelman |
* All rights reserved. |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* You may distribute under the terms of either the GNU General Public |
* modification, are permitted provided that the following conditions |
* License or the Less License, as specified in the README file. |
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice in the documentation and/or other materials provided with |
|
* the distribution. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY |
* For more information about less, or for information on how to |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* contact the author, see the README file. |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
*/ |
|
|
|
|
|
|
*/ |
*/ |
|
|
#include "less.h" |
#include "less.h" |
#if MSOFTC |
#include "lglob.h" |
|
#if MSDOS_COMPILER |
#include <dos.h> |
#include <dos.h> |
|
#if MSDOS_COMPILER==WIN32C && !defined(_MSC_VER) |
|
#include <dir.h> |
#endif |
#endif |
|
#if MSDOS_COMPILER==DJGPPC |
|
#include <glob.h> |
|
#include <dir.h> |
|
#define _MAX_PATH PATH_MAX |
|
#endif |
|
#endif |
|
#ifdef _OSK |
|
#include <rbf.h> |
|
#ifndef _OSK_MWC32 |
|
#include <modes.h> |
|
#endif |
|
#endif |
|
#if OS2 |
|
#include <signal.h> |
|
#endif |
|
|
|
#if HAVE_STAT |
|
#include <sys/stat.h> |
|
#ifndef S_ISDIR |
|
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
|
#endif |
|
#ifndef S_ISREG |
|
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) |
|
#endif |
|
#endif |
|
|
|
|
extern int force_open; |
extern int force_open; |
|
extern int secure; |
|
extern int use_lessopen; |
extern IFILE curr_ifile; |
extern IFILE curr_ifile; |
extern IFILE old_ifile; |
extern IFILE old_ifile; |
|
#if SPACES_IN_FILENAMES |
|
extern char openquote; |
|
extern char closequote; |
|
#endif |
|
|
/* |
/* |
|
* Remove quotes around a filename. |
|
*/ |
|
public char * |
|
shell_unquote(str) |
|
char *str; |
|
{ |
|
char *name; |
|
char *p; |
|
|
|
name = p = (char *) ecalloc(strlen(str)+1, sizeof(char)); |
|
if (*str == openquote) |
|
{ |
|
str++; |
|
while (*str != '\0') |
|
{ |
|
if (*str == closequote) |
|
{ |
|
if (str[1] != closequote) |
|
break; |
|
str++; |
|
} |
|
*p++ = *str++; |
|
} |
|
} else |
|
{ |
|
char *esc = get_meta_escape(); |
|
int esclen = strlen(esc); |
|
while (*str != '\0') |
|
{ |
|
if (esclen > 0 && strncmp(str, esc, esclen) == 0) |
|
str += esclen; |
|
*p++ = *str++; |
|
} |
|
} |
|
*p = '\0'; |
|
return (name); |
|
} |
|
|
|
/* |
|
* Get the shell's escape character. |
|
*/ |
|
public char * |
|
get_meta_escape() |
|
{ |
|
char *s; |
|
|
|
s = lgetenv("LESSMETAESCAPE"); |
|
if (s == NULL) |
|
s = DEF_METAESCAPE; |
|
return (s); |
|
} |
|
|
|
/* |
|
* Get the characters which the shell considers to be "metacharacters". |
|
*/ |
|
static char * |
|
metachars() |
|
{ |
|
static char *mchars = NULL; |
|
|
|
if (mchars == NULL) |
|
{ |
|
mchars = lgetenv("LESSMETACHARS"); |
|
if (mchars == NULL) |
|
mchars = DEF_METACHARS; |
|
} |
|
return (mchars); |
|
} |
|
|
|
/* |
|
* Is this a shell metacharacter? |
|
*/ |
|
static int |
|
metachar(c) |
|
char c; |
|
{ |
|
return (strchr(metachars(), c) != NULL); |
|
} |
|
|
|
/* |
|
* Insert a backslash before each metacharacter in a string. |
|
*/ |
|
public char * |
|
shell_quote(s) |
|
char *s; |
|
{ |
|
char *p; |
|
char *newstr; |
|
int len; |
|
char *esc = get_meta_escape(); |
|
int esclen = strlen(esc); |
|
int use_quotes = 0; |
|
int have_quotes = 0; |
|
|
|
/* |
|
* Determine how big a string we need to allocate. |
|
*/ |
|
len = 1; /* Trailing null byte */ |
|
for (p = s; *p != '\0'; p++) |
|
{ |
|
len++; |
|
if (*p == openquote || *p == closequote) |
|
have_quotes = 1; |
|
if (metachar(*p)) |
|
{ |
|
if (esclen == 0) |
|
{ |
|
/* |
|
* We've got a metachar, but this shell |
|
* doesn't support escape chars. Use quotes. |
|
*/ |
|
use_quotes = 1; |
|
} else |
|
{ |
|
/* |
|
* Allow space for the escape char. |
|
*/ |
|
len += esclen; |
|
} |
|
} |
|
} |
|
if (use_quotes) |
|
{ |
|
if (have_quotes) |
|
/* |
|
* We can't quote a string that contains quotes. |
|
*/ |
|
return (NULL); |
|
len = strlen(s) + 3; |
|
} |
|
/* |
|
* Allocate and construct the new string. |
|
*/ |
|
newstr = p = (char *) ecalloc(len, sizeof(char)); |
|
if (use_quotes) |
|
{ |
|
sprintf(newstr, "%c%s%c", openquote, s, closequote); |
|
} else |
|
{ |
|
while (*s != '\0') |
|
{ |
|
if (metachar(*s)) |
|
{ |
|
/* |
|
* Add the escape char. |
|
*/ |
|
strcpy(p, esc); |
|
p += esclen; |
|
} |
|
*p++ = *s++; |
|
} |
|
*p = '\0'; |
|
} |
|
return (newstr); |
|
} |
|
|
|
/* |
* Return a pathname that points to a specified file in a specified directory. |
* Return a pathname that points to a specified file in a specified directory. |
* Return NULL if the file does not exist in the directory. |
* Return NULL if the file does not exist in the directory. |
*/ |
*/ |
|
|
char *filename; |
char *filename; |
{ |
{ |
char *pathname; |
char *pathname; |
|
char *qpathname; |
int f; |
int f; |
|
|
if (dirname == NULL || *dirname == '\0') |
if (dirname == NULL || *dirname == '\0') |
|
|
sizeof(char)); |
sizeof(char)); |
if (pathname == NULL) |
if (pathname == NULL) |
return (NULL); |
return (NULL); |
#if MSOFTC || OS2 |
sprintf(pathname, "%s%s%s", dirname, PATHNAME_SEP, filename); |
sprintf(pathname, "%s\\%s", dirname, filename); |
|
#else |
|
sprintf(pathname, "%s/%s", dirname, filename); |
|
#endif |
|
/* |
/* |
* Make sure the file exists. |
* Make sure the file exists. |
*/ |
*/ |
f = open(pathname, OPEN_READ); |
qpathname = shell_unquote(pathname); |
|
f = open(qpathname, OPEN_READ); |
if (f < 0) |
if (f < 0) |
{ |
{ |
free(pathname); |
free(pathname); |
pathname = NULL; |
pathname = NULL; |
} else |
} else |
{ |
{ |
close (f); |
close(f); |
} |
} |
|
free(qpathname); |
return (pathname); |
return (pathname); |
} |
} |
|
|
|
|
/* |
/* |
* Try $HOME/filename. |
* Try $HOME/filename. |
*/ |
*/ |
pathname = dirfile(getenv("HOME"), filename); |
pathname = dirfile(lgetenv("HOME"), filename); |
if (pathname != NULL) |
if (pathname != NULL) |
return (pathname); |
return (pathname); |
#if OS2 |
#if OS2 |
/* |
/* |
* Try $INIT/filename. |
* Try $INIT/filename. |
*/ |
*/ |
pathname = dirfile(getenv("INIT"), filename); |
pathname = dirfile(lgetenv("INIT"), filename); |
if (pathname != NULL) |
if (pathname != NULL) |
return (pathname); |
return (pathname); |
#endif |
#endif |
#if MSOFTC || OS2 |
#if MSDOS_COMPILER || OS2 |
/* |
/* |
* Look for the file anywhere on search path. |
* Look for the file anywhere on search path. |
*/ |
*/ |
pathname = (char *) calloc(_MAX_PATH, sizeof(char)); |
pathname = (char *) calloc(_MAX_PATH, sizeof(char)); |
|
#if MSDOS_COMPILER==DJGPPC |
|
{ |
|
char *res = searchpath(filename); |
|
if (res == 0) |
|
*pathname = '\0'; |
|
else |
|
strcpy(pathname, res); |
|
} |
|
#else |
_searchenv(filename, "PATH", pathname); |
_searchenv(filename, "PATH", pathname); |
|
#endif |
if (*pathname != '\0') |
if (*pathname != '\0') |
return (pathname); |
return (pathname); |
free(pathname); |
free(pathname); |
|
|
} |
} |
|
|
/* |
/* |
* Find out where the help file is. |
|
*/ |
|
public char * |
|
find_helpfile() |
|
{ |
|
register char *helpfile; |
|
|
|
if ((helpfile = getenv("LESSHELP")) != NULL) |
|
return (save(helpfile)); |
|
#if MSOFTC || OS2 |
|
return (homefile(HELPFILE)); |
|
#else |
|
return (save(HELPFILE)); |
|
#endif |
|
} |
|
|
|
/* |
|
* Expand a string, substituting any "%" with the current filename, |
* Expand a string, substituting any "%" with the current filename, |
* and any "#" with the previous filename. |
* and any "#" with the previous filename. |
|
* But a string of N "%"s is just replaced with N-1 "%"s. |
|
* Likewise for a string of N "#"s. |
* {{ This is a lot of work just to support % and #. }} |
* {{ This is a lot of work just to support % and #. }} |
*/ |
*/ |
public char * |
public char * |
|
|
register char *fr, *to; |
register char *fr, *to; |
register int n; |
register int n; |
register char *e; |
register char *e; |
|
IFILE ifile; |
|
|
|
#define fchar_ifile(c) \ |
|
((c) == '%' ? curr_ifile : \ |
|
(c) == '#' ? old_ifile : NULL_IFILE) |
|
|
/* |
/* |
* Make one pass to see how big a buffer we |
* Make one pass to see how big a buffer we |
* need to allocate for the expanded string. |
* need to allocate for the expanded string. |
|
|
switch (*fr) |
switch (*fr) |
{ |
{ |
case '%': |
case '%': |
if (curr_ifile == NULL_IFILE) |
|
{ |
|
/* error("No current file", NULL_PARG); */ |
|
return (save(s)); |
|
} |
|
n += strlen(get_filename(curr_ifile)); |
|
break; |
|
case '#': |
case '#': |
if (old_ifile == NULL_IFILE) |
if (fr > s && fr[-1] == *fr) |
{ |
{ |
/* error("No previous file", NULL_PARG); */ |
/* |
return (save(s)); |
* Second (or later) char in a string |
|
* of identical chars. Treat as normal. |
|
*/ |
|
n++; |
|
} else if (fr[1] != *fr) |
|
{ |
|
/* |
|
* Single char (not repeated). Treat specially. |
|
*/ |
|
ifile = fchar_ifile(*fr); |
|
if (ifile == NULL_IFILE) |
|
n++; |
|
else |
|
n += strlen(get_filename(ifile)); |
} |
} |
n += strlen(get_filename(old_ifile)); |
/* |
|
* Else it is the first char in a string of |
|
* identical chars. Just discard it. |
|
*/ |
break; |
break; |
default: |
default: |
n++; |
n++; |
|
|
switch (*fr) |
switch (*fr) |
{ |
{ |
case '%': |
case '%': |
strcpy(to, get_filename(curr_ifile)); |
|
to += strlen(to); |
|
break; |
|
case '#': |
case '#': |
strcpy(to, get_filename(old_ifile)); |
if (fr > s && fr[-1] == *fr) |
to += strlen(to); |
{ |
|
*to++ = *fr; |
|
} else if (fr[1] != *fr) |
|
{ |
|
ifile = fchar_ifile(*fr); |
|
if (ifile == NULL_IFILE) |
|
*to++ = *fr; |
|
else |
|
{ |
|
strcpy(to, get_filename(ifile)); |
|
to += strlen(to); |
|
} |
|
} |
break; |
break; |
default: |
default: |
*to++ = *fr; |
*to++ = *fr; |
|
|
char *s; |
char *s; |
{ |
{ |
char *fpat; |
char *fpat; |
|
char *qs; |
|
|
|
if (secure) |
|
return (NULL); |
/* |
/* |
* Complete the filename "s" by globbing "s*". |
* Complete the filename "s" by globbing "s*". |
*/ |
*/ |
#if MSOFTC |
#if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC) |
/* |
/* |
* But in DOS, we have to glob "s*.*". |
* But in DOS, we have to glob "s*.*". |
* But if the final component of the filename already has |
* But if the final component of the filename already has |
|
|
* (Thus, "FILE" is globbed as "FILE*.*", |
* (Thus, "FILE" is globbed as "FILE*.*", |
* but "FILE.A" is globbed as "FILE.A*"). |
* but "FILE.A" is globbed as "FILE.A*"). |
*/ |
*/ |
char *slash; |
{ |
for (slash = s+strlen(s)-1; slash > s; slash--) |
char *slash; |
if (*slash == '/' || *slash == '\\') |
for (slash = s+strlen(s)-1; slash > s; slash--) |
break; |
if (*slash == *PATHNAME_SEP || *slash == '/') |
fpat = (char *) ecalloc(strlen(s)+4, sizeof(char)); |
break; |
if (strchr(slash, '.') == NULL) |
fpat = (char *) ecalloc(strlen(s)+4, sizeof(char)); |
sprintf(fpat, "%s*.*", s); |
if (strchr(slash, '.') == NULL) |
else |
sprintf(fpat, "%s*.*", s); |
sprintf(fpat, "%s*", s); |
else |
|
sprintf(fpat, "%s*", s); |
|
} |
#else |
#else |
fpat = (char *) ecalloc(strlen(s)+2, sizeof(char)); |
fpat = (char *) ecalloc(strlen(s)+2, sizeof(char)); |
sprintf(fpat, "%s*", s); |
sprintf(fpat, "%s*", s); |
#endif |
#endif |
s = glob(fpat); |
qs = lglob(fpat); |
|
s = shell_unquote(qs); |
if (strcmp(s,fpat) == 0) |
if (strcmp(s,fpat) == 0) |
{ |
{ |
/* |
/* |
* The filename didn't expand. |
* The filename didn't expand. |
*/ |
*/ |
free(s); |
free(qs); |
s = NULL; |
qs = NULL; |
} |
} |
|
free(s); |
free(fpat); |
free(fpat); |
return (s); |
return (qs); |
} |
} |
#endif |
#endif |
|
|
|
|
return ((POSITION) spos); |
return ((POSITION) spos); |
} |
} |
|
|
#if GLOB |
|
|
|
FILE *popen(); |
|
|
|
/* |
/* |
* Read a string from a file. |
* Read a string from a file. |
* Return a pointer to the string in memory. |
* Return a pointer to the string in memory. |
|
|
return (buf); |
return (buf); |
} |
} |
|
|
|
|
|
|
|
#if HAVE_POPEN |
|
|
|
FILE *popen(); |
|
|
/* |
/* |
* Execute a shell command. |
* Execute a shell command. |
* Return a pointer to a pipe connected to the shell command's standard output. |
* Return a pointer to a pipe connected to the shell command's standard output. |
*/ |
*/ |
static FILE * |
static FILE * |
shellcmd(cmd, s1, s2) |
shellcmd(cmd) |
char *cmd; |
char *cmd; |
char *s1; |
|
char *s2; |
|
{ |
{ |
char *scmd; |
|
char *scmd2; |
|
char *shell; |
|
FILE *fd; |
FILE *fd; |
int len; |
|
|
|
len = strlen(cmd) + |
|
(s1 == NULL ? 0 : strlen(s1)) + |
|
(s2 == NULL ? 0 : strlen(s2)) + 1; |
|
scmd = (char *) ecalloc(len, sizeof(char)); |
|
sprintf(scmd, cmd, s1, s2); |
|
#if HAVE_SHELL |
#if HAVE_SHELL |
shell = getenv("SHELL"); |
char *shell; |
|
|
|
shell = lgetenv("SHELL"); |
if (shell != NULL && *shell != '\0') |
if (shell != NULL && *shell != '\0') |
{ |
{ |
|
char *scmd; |
|
char *esccmd; |
|
|
/* |
/* |
* Read the output of <$SHELL -c "cmd">. |
* Read the output of <$SHELL -c cmd>. |
|
* Escape any metacharacters in the command. |
*/ |
*/ |
scmd2 = (char *) ecalloc(strlen(shell) + strlen(scmd) + 7, |
esccmd = shell_quote(cmd); |
sizeof(char)); |
if (esccmd == NULL) |
sprintf(scmd2, "%s -c \"%s\"", shell, scmd); |
{ |
free(scmd); |
fd = popen(cmd, "r"); |
scmd = scmd2; |
} else |
} |
{ |
|
scmd = (char *) ecalloc(strlen(shell) + strlen(esccmd) + 5, |
|
sizeof(char)); |
|
sprintf(scmd, "%s %s %s", shell, shell_coption(), esccmd); |
|
free(esccmd); |
|
fd = popen(scmd, "r"); |
|
free(scmd); |
|
} |
|
} else |
#endif |
#endif |
fd = popen(scmd, "r"); |
{ |
free(scmd); |
fd = popen(cmd, "r"); |
|
} |
|
/* |
|
* Redirection in `popen' might have messed with the |
|
* standard devices. Restore binary input mode. |
|
*/ |
|
SET_BINARY(0); |
return (fd); |
return (fd); |
} |
} |
|
|
|
#endif /* HAVE_POPEN */ |
|
|
|
|
/* |
/* |
* Expand a filename, doing any shell-level substitutions. |
* Expand a filename, doing any system-specific metacharacter substitutions. |
*/ |
*/ |
public char * |
public char * |
glob(filename) |
lglob(filename) |
char *filename; |
char *filename; |
{ |
{ |
char *gfilename; |
char *gfilename; |
|
char *ofilename; |
|
|
filename = fexpand(filename); |
ofilename = fexpand(filename); |
#if OS2 |
if (secure) |
|
return (ofilename); |
|
filename = shell_unquote(ofilename); |
|
|
|
#ifdef DECL_GLOB_LIST |
{ |
{ |
char **list; |
/* |
int cnt; |
* The globbing function returns a list of names. |
|
*/ |
int length; |
int length; |
|
char *p; |
|
char *qfilename; |
|
DECL_GLOB_LIST(list) |
|
|
list = _fnexplode(filename); |
GLOB_LIST(filename, list); |
if (list == NULL) |
if (GLOB_LIST_FAILED(list)) |
return (filename); |
{ |
length = 0; |
free(filename); |
for (cnt = 0; list[cnt] != NULL; cnt++) |
return (ofilename); |
length += strlen(list[cnt]) + 1; |
} |
|
length = 1; /* Room for trailing null byte */ |
|
for (SCAN_GLOB_LIST(list, p)) |
|
{ |
|
INIT_GLOB_LIST(list, p); |
|
qfilename = shell_quote(p); |
|
if (qfilename != NULL) |
|
{ |
|
length += strlen(qfilename) + 1; |
|
free(qfilename); |
|
} |
|
} |
gfilename = (char *) ecalloc(length, sizeof(char)); |
gfilename = (char *) ecalloc(length, sizeof(char)); |
for (cnt = 0; list[cnt] != NULL; cnt++) |
for (SCAN_GLOB_LIST(list, p)) |
{ |
{ |
strcat(gfilename, list[cnt]); |
INIT_GLOB_LIST(list, p); |
strcat(gfilename, " "); |
qfilename = shell_quote(p); |
|
if (qfilename != NULL) |
|
{ |
|
sprintf(gfilename + strlen(gfilename), "%s ", qfilename); |
|
free(qfilename); |
|
} |
} |
} |
_fnexplodefree(list); |
/* |
|
* Overwrite the final trailing space with a null terminator. |
|
*/ |
|
*--p = '\0'; |
|
GLOB_LIST_DONE(list); |
} |
} |
#else |
#else |
|
#ifdef DECL_GLOB_NAME |
{ |
{ |
FILE *fd; |
/* |
|
* The globbing function returns a single name, and |
|
* is called multiple times to walk thru all names. |
|
*/ |
|
register char *p; |
|
register int len; |
|
register int n; |
|
char *pathname; |
|
char *qpathname; |
|
DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) |
|
|
|
GLOB_FIRST_NAME(filename, &fnd, handle); |
|
if (GLOB_FIRST_FAILED(handle)) |
|
{ |
|
free(filename); |
|
return (ofilename); |
|
} |
|
|
|
_splitpath(filename, drive, dir, fname, ext); |
|
len = 100; |
|
gfilename = (char *) ecalloc(len, sizeof(char)); |
|
p = gfilename; |
|
do { |
|
n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1; |
|
pathname = (char *) ecalloc(n, sizeof(char)); |
|
sprintf(pathname, "%s%s%s", drive, dir, fnd.GLOB_NAME); |
|
qpathname = shell_quote(pathname); |
|
free(pathname); |
|
if (qpathname != NULL) |
|
{ |
|
n = strlen(qpathname); |
|
while (p - gfilename + n + 2 >= len) |
|
{ |
|
/* |
|
* No room in current buffer. |
|
* Allocate a bigger one. |
|
*/ |
|
len *= 2; |
|
*p = '\0'; |
|
p = (char *) ecalloc(len, sizeof(char)); |
|
strcpy(p, gfilename); |
|
free(gfilename); |
|
gfilename = p; |
|
p = gfilename + strlen(gfilename); |
|
} |
|
strcpy(p, qpathname); |
|
free(qpathname); |
|
p += n; |
|
*p++ = ' '; |
|
} |
|
} while (GLOB_NEXT_NAME(handle, &fnd) == 0); |
|
|
/* |
/* |
* We get the shell to expand the filename for us by passing |
* Overwrite the final trailing space with a null terminator. |
|
*/ |
|
*--p = '\0'; |
|
GLOB_NAME_DONE(handle); |
|
} |
|
#else |
|
#if HAVE_POPEN |
|
{ |
|
/* |
|
* We get the shell to glob the filename for us by passing |
* an "echo" command to the shell and reading its output. |
* an "echo" command to the shell and reading its output. |
*/ |
*/ |
fd = shellcmd("echo %s", filename, (char*)NULL); |
FILE *fd; |
|
char *s; |
|
char *lessecho; |
|
char *cmd; |
|
char *esc; |
|
|
|
esc = get_meta_escape(); |
|
if (strlen(esc) == 0) |
|
esc = "-"; |
|
esc = shell_quote(esc); |
|
if (esc == NULL) |
|
{ |
|
free(filename); |
|
return (ofilename); |
|
} |
|
lessecho = lgetenv("LESSECHO"); |
|
if (lessecho == NULL || *lessecho == '\0') |
|
lessecho = "lessecho"; |
|
/* |
|
* Invoke lessecho, and read its output (a globbed list of filenames). |
|
*/ |
|
cmd = (char *) ecalloc(strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24, sizeof(char)); |
|
sprintf(cmd, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote, closequote, esc); |
|
free(esc); |
|
for (s = metachars(); *s != '\0'; s++) |
|
sprintf(cmd + strlen(cmd), "-n0x%x ", *s); |
|
sprintf(cmd + strlen(cmd), "-- %s", ofilename); |
|
fd = shellcmd(cmd); |
|
free(cmd); |
if (fd == NULL) |
if (fd == NULL) |
{ |
{ |
/* |
/* |
* Cannot create the pipe. |
* Cannot create the pipe. |
* Just return the original (fexpanded) filename. |
* Just return the original (fexpanded) filename. |
*/ |
*/ |
return (filename); |
free(filename); |
|
return (ofilename); |
} |
} |
gfilename = readfd(fd); |
gfilename = readfd(fd); |
pclose(fd); |
pclose(fd); |
if (*gfilename == '\0') |
if (*gfilename == '\0') |
{ |
{ |
free(gfilename); |
free(gfilename); |
return (filename); |
free(filename); |
|
return (ofilename); |
} |
} |
free(filename); |
|
} |
} |
|
#else |
|
/* |
|
* No globbing functions at all. Just use the fexpanded filename. |
|
*/ |
|
gfilename = save(filename); |
#endif |
#endif |
|
#endif |
|
#endif |
|
free(filename); |
|
free(ofilename); |
return (gfilename); |
return (gfilename); |
} |
} |
|
|
|
|
int *pf; |
int *pf; |
void **pfd; |
void **pfd; |
{ |
{ |
|
#if !HAVE_POPEN |
|
return (NULL); |
|
#else |
char *lessopen; |
char *lessopen; |
char *gfilename; |
char *cmd; |
int returnfd = 0; |
|
FILE *fd; |
FILE *fd; |
|
#if HAVE_FILENO |
|
int returnfd = 0; |
|
#endif |
|
|
|
if (!use_lessopen || secure) |
|
return (NULL); |
ch_ungetchar(-1); |
ch_ungetchar(-1); |
if ((lessopen = getenv("LESSOPEN")) == NULL) |
if ((lessopen = lgetenv("LESSOPEN")) == NULL) |
return (NULL); |
return (NULL); |
if (strcmp(filename, "-") == 0) |
if (strcmp(filename, "-") == 0) |
return (NULL); |
return (NULL); |
|
|
* If LESSOPEN starts with a |, it indicates |
* If LESSOPEN starts with a |, it indicates |
* a "pipe preprocessor". |
* a "pipe preprocessor". |
*/ |
*/ |
|
#if HAVE_FILENO |
lessopen++; |
lessopen++; |
returnfd = 1; |
returnfd = 1; |
|
#else |
|
error("LESSOPEN pipe is not supported", NULL_PARG); |
|
return (NULL); |
|
#endif |
} |
} |
fd = shellcmd(lessopen, filename, (char*)NULL); |
|
|
cmd = (char *) ecalloc(strlen(lessopen) + strlen(filename) + 2, |
|
sizeof(char)); |
|
sprintf(cmd, lessopen, filename); |
|
fd = shellcmd(cmd); |
|
free(cmd); |
if (fd == NULL) |
if (fd == NULL) |
{ |
{ |
/* |
/* |
|
|
*/ |
*/ |
return (NULL); |
return (NULL); |
} |
} |
|
#if HAVE_FILENO |
if (returnfd) |
if (returnfd) |
{ |
{ |
#if HAVE_FILENO |
|
int f; |
int f; |
char c; |
char c; |
|
|
|
|
* If it does, push the char back on the pipe. |
* If it does, push the char back on the pipe. |
*/ |
*/ |
f = fileno(fd); |
f = fileno(fd); |
|
SET_BINARY(f); |
if (read(f, &c, 1) != 1) |
if (read(f, &c, 1) != 1) |
{ |
{ |
/* |
/* |
|
|
*pfd = (void *) fd; |
*pfd = (void *) fd; |
*pf = f; |
*pf = f; |
return (save("-")); |
return (save("-")); |
#else |
|
error("LESSOPEN pipe is not supported", NULL_PARG); |
|
return (NULL); |
|
#endif |
|
} |
} |
gfilename = readfd(fd); |
#endif |
|
cmd = readfd(fd); |
pclose(fd); |
pclose(fd); |
if (*gfilename == '\0') |
if (*cmd == '\0') |
/* |
/* |
* Pipe is empty. This means there is no alt file. |
* Pipe is empty. This means there is no alt file. |
*/ |
*/ |
return (NULL); |
return (NULL); |
return (gfilename); |
return (cmd); |
|
#endif /* HAVE_POPEN */ |
} |
} |
|
|
/* |
/* |
|
|
char *filename; |
char *filename; |
void *pipefd; |
void *pipefd; |
{ |
{ |
|
#if HAVE_POPEN |
char *lessclose; |
char *lessclose; |
FILE *fd; |
FILE *fd; |
|
char *cmd; |
|
|
|
if (secure) |
|
return; |
if (pipefd != NULL) |
if (pipefd != NULL) |
|
{ |
|
#if OS2 |
|
/* |
|
* The pclose function of OS/2 emx sometimes fails. |
|
* Send SIGINT to the piped process before closing it. |
|
*/ |
|
kill(((FILE*)pipefd)->_pid, SIGINT); |
|
#endif |
pclose((FILE*) pipefd); |
pclose((FILE*) pipefd); |
if ((lessclose = getenv("LESSCLOSE")) == NULL) |
} |
|
if ((lessclose = lgetenv("LESSCLOSE")) == NULL) |
return; |
return; |
fd = shellcmd(lessclose, filename, altfilename); |
cmd = (char *) ecalloc(strlen(lessclose) + strlen(filename) + |
pclose(fd); |
strlen(altfilename) + 2, sizeof(char)); |
|
sprintf(cmd, lessclose, filename, altfilename); |
|
fd = shellcmd(cmd); |
|
free(cmd); |
|
if (fd != NULL) |
|
pclose(fd); |
|
#endif |
} |
} |
|
|
#else |
/* |
#if MSOFTC |
* Is the specified file a directory? |
|
*/ |
public char * |
public int |
glob(filename) |
is_dir(filename) |
char *filename; |
char *filename; |
{ |
{ |
register char *gfilename; |
int isdir = 0; |
register char *p; |
|
register int len; |
|
register int n; |
|
struct find_t fnd; |
|
char drive[_MAX_DRIVE]; |
|
char dir[_MAX_DIR]; |
|
char fname[_MAX_FNAME]; |
|
char ext[_MAX_EXT]; |
|
|
|
filename = fexpand(filename); |
|
if (_dos_findfirst(filename, ~0, &fnd) != 0) |
|
return (filename); |
|
|
|
_splitpath(filename, drive, dir, fname, ext); |
|
len = 100; |
|
gfilename = (char *) ecalloc(len, sizeof(char)); |
|
p = gfilename; |
|
do { |
|
n = strlen(drive) + strlen(dir) + strlen(fnd.name); |
|
while (p - gfilename + n+2 >= len) |
|
{ |
|
len *= 2; |
|
*p = '\0'; |
|
p = (char *) ecalloc(len, sizeof(char)); |
|
strcpy(p, gfilename); |
|
free(gfilename); |
|
gfilename = p; |
|
p = gfilename + strlen(gfilename); |
|
} |
|
sprintf(p, "%s%s%s", drive, dir, fnd.name); |
|
p += n; |
|
*p++ = ' '; |
|
} while (_dos_findnext(&fnd) == 0); |
|
|
|
*--p = '\0'; |
|
return (gfilename); |
|
} |
|
|
|
public char * |
|
open_altfile(filename) |
|
char *filename; |
|
{ |
|
return (NULL); |
|
} |
|
|
|
public void |
filename = shell_unquote(filename); |
close_altfile(altfilename, filename) |
#if HAVE_STAT |
char *altfilename; |
|
char *filename; |
|
{ |
{ |
|
int r; |
|
struct stat statbuf; |
|
|
|
r = stat(filename, &statbuf); |
|
isdir = (r >= 0 && S_ISDIR(statbuf.st_mode)); |
} |
} |
|
|
#else |
#else |
|
#ifdef _OSK |
public char * |
|
glob(filename) |
|
char *filename; |
|
{ |
{ |
return (fexpand(filename)); |
register int f; |
} |
|
|
|
|
f = open(filename, S_IREAD | S_IFDIR); |
public char * |
if (f >= 0) |
open_altfile(filename) |
close(f); |
char *filename; |
isdir = (f >= 0); |
{ |
|
return (NULL); |
|
} |
} |
|
|
public void |
|
close_altfile(altfilename, filename) |
|
char *altfilename; |
|
char *filename; |
|
{ |
|
} |
|
|
|
#endif |
#endif |
#endif |
#endif |
|
free(filename); |
|
return (isdir); |
|
} |
|
|
|
|
#if HAVE_STAT |
|
|
|
#include <sys/stat.h> |
|
#ifndef S_ISDIR |
|
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
|
#endif |
|
#ifndef S_ISREG |
|
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) |
|
#endif |
|
|
|
/* |
/* |
* Returns NULL if the file can be opened and |
* Returns NULL if the file can be opened and |
* is an ordinary file, otherwise an error message |
* is an ordinary file, otherwise an error message |
|
|
bad_file(filename) |
bad_file(filename) |
char *filename; |
char *filename; |
{ |
{ |
register char *m; |
register char *m = NULL; |
struct stat statbuf; |
|
|
|
if (stat(filename, &statbuf) < 0) |
filename = shell_unquote(filename); |
return (errno_message(filename)); |
if (is_dir(filename)) |
|
|
if (force_open) |
|
return (NULL); |
|
|
|
if (S_ISDIR(statbuf.st_mode)) |
|
{ |
{ |
static char is_dir[] = " is a directory"; |
static char is_a_dir[] = " is a directory"; |
m = (char *) ecalloc(strlen(filename) + sizeof(is_dir), |
|
|
m = (char *) ecalloc(strlen(filename) + sizeof(is_a_dir), |
sizeof(char)); |
sizeof(char)); |
strcpy(m, filename); |
strcpy(m, filename); |
strcat(m, is_dir); |
strcat(m, is_a_dir); |
return (m); |
} else |
} |
|
if (!S_ISREG(statbuf.st_mode)) |
|
{ |
{ |
static char not_reg[] = " is not a regular file"; |
#if HAVE_STAT |
m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), |
int r; |
sizeof(char)); |
struct stat statbuf; |
strcpy(m, filename); |
|
strcat(m, not_reg); |
|
return (m); |
|
} |
|
|
|
return (NULL); |
r = stat(filename, &statbuf); |
|
if (r < 0) |
|
{ |
|
m = errno_message(filename); |
|
} else if (force_open) |
|
{ |
|
m = NULL; |
|
} else if (!S_ISREG(statbuf.st_mode)) |
|
{ |
|
static char not_reg[] = " is not a regular file (use -f to see it)"; |
|
m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), |
|
sizeof(char)); |
|
strcpy(m, filename); |
|
strcat(m, not_reg); |
|
} |
|
#endif |
|
} |
|
free(filename); |
|
return (m); |
} |
} |
|
|
/* |
/* |
|
|
filesize(f) |
filesize(f) |
int f; |
int f; |
{ |
{ |
|
#if HAVE_STAT |
struct stat statbuf; |
struct stat statbuf; |
|
|
if (fstat(f, &statbuf) < 0) |
if (fstat(f, &statbuf) >= 0) |
/* |
return ((POSITION) statbuf.st_size); |
* Can't stat; try seeking to the end. |
#else |
*/ |
#ifdef _OSK |
return (seek_filesize(f)); |
long size; |
|
|
return ((POSITION) statbuf.st_size); |
if ((size = (long) _gs_size(f)) >= 0) |
|
return ((POSITION) size); |
|
#endif |
|
#endif |
|
return (seek_filesize(f)); |
} |
} |
|
|
#else |
|
|
|
/* |
/* |
* If we have no way to find out, just say the file is good. |
* |
*/ |
*/ |
public char * |
public char * |
bad_file(filename) |
shell_coption() |
char *filename; |
|
{ |
{ |
return (NULL); |
return ("-c"); |
} |
} |
|
|
/* |
|
* We can find the file size by seeking. |
|
*/ |
|
public POSITION |
|
filesize(f) |
|
int f; |
|
{ |
|
return (seek_filesize(f)); |
|
} |
|
|
|
#endif |
|