filename.c revision 128345
160786Sps/* 2128345Stjr * Copyright (C) 1984-2002 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 760786Sps * For more information about less, or for information on how to 860786Sps * contact the author, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * Routines to mess around with filenames (and files). 1460786Sps * Much of this is very OS dependent. 1560786Sps */ 1660786Sps 1760786Sps#include "less.h" 1860786Sps#include "lglob.h" 1960786Sps#if MSDOS_COMPILER 2060786Sps#include <dos.h> 2160786Sps#if MSDOS_COMPILER==WIN32C && !defined(_MSC_VER) 2260786Sps#include <dir.h> 2360786Sps#endif 2460786Sps#if MSDOS_COMPILER==DJGPPC 2560786Sps#include <glob.h> 2660786Sps#include <dir.h> 2760786Sps#define _MAX_PATH PATH_MAX 2860786Sps#endif 2960786Sps#endif 3060786Sps#ifdef _OSK 3160786Sps#include <rbf.h> 3260786Sps#ifndef _OSK_MWC32 3360786Sps#include <modes.h> 3460786Sps#endif 3560786Sps#endif 3689019Sps#if OS2 3789019Sps#include <signal.h> 3889019Sps#endif 3960786Sps 4060786Sps#if HAVE_STAT 4160786Sps#include <sys/stat.h> 4260786Sps#ifndef S_ISDIR 4360786Sps#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 4460786Sps#endif 4560786Sps#ifndef S_ISREG 4660786Sps#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 4760786Sps#endif 4860786Sps#endif 4960786Sps 5060786Sps 5160786Spsextern int force_open; 5260786Spsextern int secure; 53128345Stjrextern int use_lessopen; 5460786Spsextern IFILE curr_ifile; 5560786Spsextern IFILE old_ifile; 5660786Sps#if SPACES_IN_FILENAMES 5760786Spsextern char openquote; 5860786Spsextern char closequote; 5960786Sps#endif 6060786Sps 6160786Sps/* 6260786Sps * Remove quotes around a filename. 6360786Sps */ 6460786Sps public char * 65128345Stjrshell_unquote(str) 6660786Sps char *str; 6760786Sps{ 6860786Sps char *name; 6960786Sps char *p; 7060786Sps 71128345Stjr name = p = (char *) ecalloc(strlen(str)+1, sizeof(char)); 72128345Stjr if (*str == openquote) 73128345Stjr { 74128345Stjr str++; 75128345Stjr while (*str != '\0') 76128345Stjr { 77128345Stjr if (*str == closequote) 78128345Stjr { 79128345Stjr if (str[1] != closequote) 80128345Stjr break; 81128345Stjr str++; 82128345Stjr } 83128345Stjr *p++ = *str++; 84128345Stjr } 85128345Stjr } else 86128345Stjr { 87128345Stjr char *esc = get_meta_escape(); 88128345Stjr int esclen = strlen(esc); 89128345Stjr while (*str != '\0') 90128345Stjr { 91128345Stjr if (esclen > 0 && strncmp(str, esc, esclen) == 0) 92128345Stjr str += esclen; 93128345Stjr *p++ = *str++; 94128345Stjr } 95128345Stjr } 96128345Stjr *p = '\0'; 9760786Sps return (name); 9860786Sps} 9960786Sps 10060786Sps/* 101128345Stjr * Get the shell's escape character. 102128345Stjr */ 103128345Stjr public char * 104128345Stjrget_meta_escape() 105128345Stjr{ 106128345Stjr char *s; 107128345Stjr 108128345Stjr s = lgetenv("LESSMETAESCAPE"); 109128345Stjr if (s == NULL) 110128345Stjr s = DEF_METAESCAPE; 111128345Stjr return (s); 112128345Stjr} 113128345Stjr 114128345Stjr/* 115128345Stjr * Get the characters which the shell considers to be "metacharacters". 116128345Stjr */ 117128345Stjr static char * 118128345Stjrmetachars() 119128345Stjr{ 120128345Stjr static char *mchars = NULL; 121128345Stjr 122128345Stjr if (mchars == NULL) 123128345Stjr { 124128345Stjr mchars = lgetenv("LESSMETACHARS"); 125128345Stjr if (mchars == NULL) 126128345Stjr mchars = DEF_METACHARS; 127128345Stjr } 128128345Stjr return (mchars); 129128345Stjr} 130128345Stjr 131128345Stjr/* 132128345Stjr * Is this a shell metacharacter? 133128345Stjr */ 134128345Stjr static int 135128345Stjrmetachar(c) 136128345Stjr char c; 137128345Stjr{ 138128345Stjr return (strchr(metachars(), c) != NULL); 139128345Stjr} 140128345Stjr 141128345Stjr/* 142128345Stjr * Insert a backslash before each metacharacter in a string. 143128345Stjr */ 144128345Stjr public char * 145128345Stjrshell_quote(s) 146128345Stjr char *s; 147128345Stjr{ 148128345Stjr char *p; 149128345Stjr char *newstr; 150128345Stjr int len; 151128345Stjr char *esc = get_meta_escape(); 152128345Stjr int esclen = strlen(esc); 153128345Stjr int use_quotes = 0; 154128345Stjr int have_quotes = 0; 155128345Stjr 156128345Stjr /* 157128345Stjr * Determine how big a string we need to allocate. 158128345Stjr */ 159128345Stjr len = 1; /* Trailing null byte */ 160128345Stjr for (p = s; *p != '\0'; p++) 161128345Stjr { 162128345Stjr len++; 163128345Stjr if (*p == openquote || *p == closequote) 164128345Stjr have_quotes = 1; 165128345Stjr if (metachar(*p)) 166128345Stjr { 167128345Stjr if (esclen == 0) 168128345Stjr { 169128345Stjr /* 170128345Stjr * We've got a metachar, but this shell 171128345Stjr * doesn't support escape chars. Use quotes. 172128345Stjr */ 173128345Stjr use_quotes = 1; 174128345Stjr } else 175128345Stjr { 176128345Stjr /* 177128345Stjr * Allow space for the escape char. 178128345Stjr */ 179128345Stjr len += esclen; 180128345Stjr } 181128345Stjr } 182128345Stjr } 183128345Stjr if (use_quotes) 184128345Stjr { 185128345Stjr if (have_quotes) 186128345Stjr /* 187128345Stjr * We can't quote a string that contains quotes. 188128345Stjr */ 189128345Stjr return (NULL); 190128345Stjr len = strlen(s) + 3; 191128345Stjr } 192128345Stjr /* 193128345Stjr * Allocate and construct the new string. 194128345Stjr */ 195128345Stjr newstr = p = (char *) ecalloc(len, sizeof(char)); 196128345Stjr if (use_quotes) 197128345Stjr { 198128345Stjr sprintf(newstr, "%c%s%c", openquote, s, closequote); 199128345Stjr } else 200128345Stjr { 201128345Stjr while (*s != '\0') 202128345Stjr { 203128345Stjr if (metachar(*s)) 204128345Stjr { 205128345Stjr /* 206128345Stjr * Add the escape char. 207128345Stjr */ 208128345Stjr strcpy(p, esc); 209128345Stjr p += esclen; 210128345Stjr } 211128345Stjr *p++ = *s++; 212128345Stjr } 213128345Stjr *p = '\0'; 214128345Stjr } 215128345Stjr return (newstr); 216128345Stjr} 217128345Stjr 218128345Stjr/* 21960786Sps * Return a pathname that points to a specified file in a specified directory. 22060786Sps * Return NULL if the file does not exist in the directory. 22160786Sps */ 22260786Sps static char * 22360786Spsdirfile(dirname, filename) 22460786Sps char *dirname; 22560786Sps char *filename; 22660786Sps{ 22760786Sps char *pathname; 22860786Sps char *qpathname; 22960786Sps int f; 23060786Sps 23160786Sps if (dirname == NULL || *dirname == '\0') 23260786Sps return (NULL); 23360786Sps /* 23460786Sps * Construct the full pathname. 23560786Sps */ 23660786Sps pathname = (char *) calloc(strlen(dirname) + strlen(filename) + 2, 23760786Sps sizeof(char)); 23860786Sps if (pathname == NULL) 23960786Sps return (NULL); 24060786Sps sprintf(pathname, "%s%s%s", dirname, PATHNAME_SEP, filename); 24160786Sps /* 24260786Sps * Make sure the file exists. 24360786Sps */ 244128345Stjr qpathname = shell_unquote(pathname); 24560786Sps f = open(qpathname, OPEN_READ); 24660786Sps if (f < 0) 24760786Sps { 24860786Sps free(pathname); 24960786Sps pathname = NULL; 25060786Sps } else 25160786Sps { 25260786Sps close(f); 25360786Sps } 25460786Sps free(qpathname); 25560786Sps return (pathname); 25660786Sps} 25760786Sps 25860786Sps/* 25960786Sps * Return the full pathname of the given file in the "home directory". 26060786Sps */ 26160786Sps public char * 26260786Spshomefile(filename) 26360786Sps char *filename; 26460786Sps{ 26560786Sps register char *pathname; 26660786Sps 26760786Sps /* 26860786Sps * Try $HOME/filename. 26960786Sps */ 27060786Sps pathname = dirfile(lgetenv("HOME"), filename); 27160786Sps if (pathname != NULL) 27260786Sps return (pathname); 27360786Sps#if OS2 27460786Sps /* 27560786Sps * Try $INIT/filename. 27660786Sps */ 27760786Sps pathname = dirfile(lgetenv("INIT"), filename); 27860786Sps if (pathname != NULL) 27960786Sps return (pathname); 28060786Sps#endif 28160786Sps#if MSDOS_COMPILER || OS2 28260786Sps /* 28360786Sps * Look for the file anywhere on search path. 28460786Sps */ 28560786Sps pathname = (char *) calloc(_MAX_PATH, sizeof(char)); 28660786Sps#if MSDOS_COMPILER==DJGPPC 28760786Sps { 28860786Sps char *res = searchpath(filename); 28960786Sps if (res == 0) 29060786Sps *pathname = '\0'; 29160786Sps else 29260786Sps strcpy(pathname, res); 29360786Sps } 29460786Sps#else 29560786Sps _searchenv(filename, "PATH", pathname); 29660786Sps#endif 29760786Sps if (*pathname != '\0') 29860786Sps return (pathname); 29960786Sps free(pathname); 30060786Sps#endif 30160786Sps return (NULL); 30260786Sps} 30360786Sps 30460786Sps/* 30560786Sps * Expand a string, substituting any "%" with the current filename, 30660786Sps * and any "#" with the previous filename. 30760786Sps * But a string of N "%"s is just replaced with N-1 "%"s. 30860786Sps * Likewise for a string of N "#"s. 30960786Sps * {{ This is a lot of work just to support % and #. }} 31060786Sps */ 31160786Sps public char * 31260786Spsfexpand(s) 31360786Sps char *s; 31460786Sps{ 31560786Sps register char *fr, *to; 31660786Sps register int n; 31760786Sps register char *e; 31860786Sps IFILE ifile; 31960786Sps 32060786Sps#define fchar_ifile(c) \ 32160786Sps ((c) == '%' ? curr_ifile : \ 32260786Sps (c) == '#' ? old_ifile : NULL_IFILE) 32360786Sps 32460786Sps /* 32560786Sps * Make one pass to see how big a buffer we 32660786Sps * need to allocate for the expanded string. 32760786Sps */ 32860786Sps n = 0; 32960786Sps for (fr = s; *fr != '\0'; fr++) 33060786Sps { 33160786Sps switch (*fr) 33260786Sps { 33360786Sps case '%': 33460786Sps case '#': 33560786Sps if (fr > s && fr[-1] == *fr) 33660786Sps { 33760786Sps /* 33860786Sps * Second (or later) char in a string 33960786Sps * of identical chars. Treat as normal. 34060786Sps */ 34160786Sps n++; 34260786Sps } else if (fr[1] != *fr) 34360786Sps { 34460786Sps /* 34560786Sps * Single char (not repeated). Treat specially. 34660786Sps */ 34760786Sps ifile = fchar_ifile(*fr); 34860786Sps if (ifile == NULL_IFILE) 34960786Sps n++; 35060786Sps else 35160786Sps n += strlen(get_filename(ifile)); 35260786Sps } 35360786Sps /* 35460786Sps * Else it is the first char in a string of 35560786Sps * identical chars. Just discard it. 35660786Sps */ 35760786Sps break; 35860786Sps default: 35960786Sps n++; 36060786Sps break; 36160786Sps } 36260786Sps } 36360786Sps 36460786Sps e = (char *) ecalloc(n+1, sizeof(char)); 36560786Sps 36660786Sps /* 36760786Sps * Now copy the string, expanding any "%" or "#". 36860786Sps */ 36960786Sps to = e; 37060786Sps for (fr = s; *fr != '\0'; fr++) 37160786Sps { 37260786Sps switch (*fr) 37360786Sps { 37460786Sps case '%': 37560786Sps case '#': 37660786Sps if (fr > s && fr[-1] == *fr) 37760786Sps { 37860786Sps *to++ = *fr; 37960786Sps } else if (fr[1] != *fr) 38060786Sps { 38160786Sps ifile = fchar_ifile(*fr); 38260786Sps if (ifile == NULL_IFILE) 38360786Sps *to++ = *fr; 38460786Sps else 38560786Sps { 38660786Sps strcpy(to, get_filename(ifile)); 38760786Sps to += strlen(to); 38860786Sps } 38960786Sps } 39060786Sps break; 39160786Sps default: 39260786Sps *to++ = *fr; 39360786Sps break; 39460786Sps } 39560786Sps } 39660786Sps *to = '\0'; 39760786Sps return (e); 39860786Sps} 39960786Sps 40060786Sps#if TAB_COMPLETE_FILENAME 40160786Sps 40260786Sps/* 40360786Sps * Return a blank-separated list of filenames which "complete" 40460786Sps * the given string. 40560786Sps */ 40660786Sps public char * 40760786Spsfcomplete(s) 40860786Sps char *s; 40960786Sps{ 41060786Sps char *fpat; 411128345Stjr char *qs; 41260786Sps 41360786Sps if (secure) 41460786Sps return (NULL); 41560786Sps /* 41660786Sps * Complete the filename "s" by globbing "s*". 41760786Sps */ 41860786Sps#if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC) 41960786Sps /* 42060786Sps * But in DOS, we have to glob "s*.*". 42160786Sps * But if the final component of the filename already has 42260786Sps * a dot in it, just do "s*". 42360786Sps * (Thus, "FILE" is globbed as "FILE*.*", 42460786Sps * but "FILE.A" is globbed as "FILE.A*"). 42560786Sps */ 42660786Sps { 42760786Sps char *slash; 42860786Sps for (slash = s+strlen(s)-1; slash > s; slash--) 42960786Sps if (*slash == *PATHNAME_SEP || *slash == '/') 43060786Sps break; 43160786Sps fpat = (char *) ecalloc(strlen(s)+4, sizeof(char)); 43260786Sps if (strchr(slash, '.') == NULL) 43360786Sps sprintf(fpat, "%s*.*", s); 43460786Sps else 43560786Sps sprintf(fpat, "%s*", s); 43660786Sps } 43760786Sps#else 43860786Sps fpat = (char *) ecalloc(strlen(s)+2, sizeof(char)); 43960786Sps sprintf(fpat, "%s*", s); 44060786Sps#endif 441128345Stjr qs = lglob(fpat); 442128345Stjr s = shell_unquote(qs); 44360786Sps if (strcmp(s,fpat) == 0) 44460786Sps { 44560786Sps /* 44660786Sps * The filename didn't expand. 44760786Sps */ 448128345Stjr free(qs); 449128345Stjr qs = NULL; 45060786Sps } 451128345Stjr free(s); 45260786Sps free(fpat); 453128345Stjr return (qs); 45460786Sps} 45560786Sps#endif 45660786Sps 45760786Sps/* 45860786Sps * Try to determine if a file is "binary". 45960786Sps * This is just a guess, and we need not try too hard to make it accurate. 46060786Sps */ 46160786Sps public int 46260786Spsbin_file(f) 46360786Sps int f; 46460786Sps{ 46560786Sps int i; 46660786Sps int n; 46760786Sps unsigned char data[64]; 46860786Sps 46960786Sps if (!seekable(f)) 47060786Sps return (0); 47160786Sps if (lseek(f, (off_t)0, 0) == BAD_LSEEK) 47260786Sps return (0); 47360786Sps n = read(f, data, sizeof(data)); 47460786Sps for (i = 0; i < n; i++) 47560786Sps if (binary_char(data[i])) 47660786Sps return (1); 47760786Sps return (0); 47860786Sps} 47960786Sps 48060786Sps/* 48160786Sps * Try to determine the size of a file by seeking to the end. 48260786Sps */ 48360786Sps static POSITION 48460786Spsseek_filesize(f) 48560786Sps int f; 48660786Sps{ 48760786Sps off_t spos; 48860786Sps 48960786Sps spos = lseek(f, (off_t)0, 2); 49060786Sps if (spos == BAD_LSEEK) 49160786Sps return (NULL_POSITION); 49260786Sps return ((POSITION) spos); 49360786Sps} 49460786Sps 49560786Sps/* 49660786Sps * Read a string from a file. 49760786Sps * Return a pointer to the string in memory. 49860786Sps */ 49960786Sps static char * 50060786Spsreadfd(fd) 50160786Sps FILE *fd; 50260786Sps{ 50360786Sps int len; 50460786Sps int ch; 50560786Sps char *buf; 50660786Sps char *p; 50760786Sps 50860786Sps /* 50960786Sps * Make a guess about how many chars in the string 51060786Sps * and allocate a buffer to hold it. 51160786Sps */ 51260786Sps len = 100; 51360786Sps buf = (char *) ecalloc(len, sizeof(char)); 51460786Sps for (p = buf; ; p++) 51560786Sps { 51660786Sps if ((ch = getc(fd)) == '\n' || ch == EOF) 51760786Sps break; 51860786Sps if (p - buf >= len-1) 51960786Sps { 52060786Sps /* 52160786Sps * The string is too big to fit in the buffer we have. 52260786Sps * Allocate a new buffer, twice as big. 52360786Sps */ 52460786Sps len *= 2; 52560786Sps *p = '\0'; 52660786Sps p = (char *) ecalloc(len, sizeof(char)); 52760786Sps strcpy(p, buf); 52860786Sps free(buf); 52960786Sps buf = p; 53060786Sps p = buf + strlen(buf); 53160786Sps } 53260786Sps *p = ch; 53360786Sps } 53460786Sps *p = '\0'; 53560786Sps return (buf); 53660786Sps} 53760786Sps 53860786Sps 53960786Sps 54060786Sps#if HAVE_POPEN 54160786Sps 54260786SpsFILE *popen(); 54360786Sps 54460786Sps/* 54560786Sps * Execute a shell command. 54660786Sps * Return a pointer to a pipe connected to the shell command's standard output. 54760786Sps */ 54860786Sps static FILE * 54960786Spsshellcmd(cmd) 55060786Sps char *cmd; 55160786Sps{ 55260786Sps FILE *fd; 55360786Sps 55460786Sps#if HAVE_SHELL 55560786Sps char *shell; 55660786Sps 55760786Sps shell = lgetenv("SHELL"); 55860786Sps if (shell != NULL && *shell != '\0') 55960786Sps { 56060786Sps char *scmd; 56160786Sps char *esccmd; 56260786Sps 56360786Sps /* 564128345Stjr * Read the output of <$SHELL -c cmd>. 565128345Stjr * Escape any metacharacters in the command. 56660786Sps */ 567128345Stjr esccmd = shell_quote(cmd); 568128345Stjr if (esccmd == NULL) 56960786Sps { 570128345Stjr fd = popen(cmd, "r"); 57160786Sps } else 57260786Sps { 57360786Sps scmd = (char *) ecalloc(strlen(shell) + strlen(esccmd) + 5, 57460786Sps sizeof(char)); 575128345Stjr sprintf(scmd, "%s %s %s", shell, shell_coption(), esccmd); 57660786Sps free(esccmd); 577128345Stjr fd = popen(scmd, "r"); 578128345Stjr free(scmd); 57960786Sps } 58060786Sps } else 58160786Sps#endif 58260786Sps { 58360786Sps fd = popen(cmd, "r"); 58460786Sps } 585128345Stjr /* 586128345Stjr * Redirection in `popen' might have messed with the 587128345Stjr * standard devices. Restore binary input mode. 588128345Stjr */ 589128345Stjr SET_BINARY(0); 59060786Sps return (fd); 59160786Sps} 59260786Sps 59360786Sps#endif /* HAVE_POPEN */ 59460786Sps 59560786Sps 59660786Sps/* 59760786Sps * Expand a filename, doing any system-specific metacharacter substitutions. 59860786Sps */ 59960786Sps public char * 60060786Spslglob(filename) 60160786Sps char *filename; 60260786Sps{ 60360786Sps char *gfilename; 60460786Sps char *ofilename; 60560786Sps 60660786Sps ofilename = fexpand(filename); 60760786Sps if (secure) 60860786Sps return (ofilename); 609128345Stjr filename = shell_unquote(ofilename); 61060786Sps 61160786Sps#ifdef DECL_GLOB_LIST 61260786Sps{ 61360786Sps /* 61460786Sps * The globbing function returns a list of names. 61560786Sps */ 61660786Sps int length; 61760786Sps char *p; 618128345Stjr char *qfilename; 61960786Sps DECL_GLOB_LIST(list) 62060786Sps 62160786Sps GLOB_LIST(filename, list); 62260786Sps if (GLOB_LIST_FAILED(list)) 62360786Sps { 62460786Sps free(filename); 62560786Sps return (ofilename); 62660786Sps } 62760786Sps length = 1; /* Room for trailing null byte */ 62860786Sps for (SCAN_GLOB_LIST(list, p)) 62960786Sps { 63060786Sps INIT_GLOB_LIST(list, p); 631128345Stjr qfilename = shell_quote(p); 632128345Stjr if (qfilename != NULL) 633128345Stjr { 634128345Stjr length += strlen(qfilename) + 1; 635128345Stjr free(qfilename); 636128345Stjr } 63760786Sps } 63860786Sps gfilename = (char *) ecalloc(length, sizeof(char)); 63960786Sps for (SCAN_GLOB_LIST(list, p)) 64060786Sps { 64160786Sps INIT_GLOB_LIST(list, p); 642128345Stjr qfilename = shell_quote(p); 643128345Stjr if (qfilename != NULL) 644128345Stjr { 645128345Stjr sprintf(gfilename + strlen(gfilename), "%s ", qfilename); 646128345Stjr free(qfilename); 647128345Stjr } 64860786Sps } 64960786Sps /* 65060786Sps * Overwrite the final trailing space with a null terminator. 65160786Sps */ 65260786Sps *--p = '\0'; 65360786Sps GLOB_LIST_DONE(list); 65460786Sps} 65560786Sps#else 65660786Sps#ifdef DECL_GLOB_NAME 65760786Sps{ 65860786Sps /* 65960786Sps * The globbing function returns a single name, and 66060786Sps * is called multiple times to walk thru all names. 66160786Sps */ 66260786Sps register char *p; 66360786Sps register int len; 66460786Sps register int n; 665128345Stjr char *pathname; 666128345Stjr char *qpathname; 66760786Sps DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) 66860786Sps 66960786Sps GLOB_FIRST_NAME(filename, &fnd, handle); 67060786Sps if (GLOB_FIRST_FAILED(handle)) 67160786Sps { 67260786Sps free(filename); 67360786Sps return (ofilename); 67460786Sps } 67560786Sps 67660786Sps _splitpath(filename, drive, dir, fname, ext); 67760786Sps len = 100; 67860786Sps gfilename = (char *) ecalloc(len, sizeof(char)); 67960786Sps p = gfilename; 68060786Sps do { 68160786Sps n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1; 682128345Stjr pathname = (char *) ecalloc(n, sizeof(char)); 683128345Stjr sprintf(pathname, "%s%s%s", drive, dir, fnd.GLOB_NAME); 684128345Stjr qpathname = shell_quote(pathname); 685128345Stjr free(pathname); 686128345Stjr if (qpathname != NULL) 68760786Sps { 688128345Stjr n = strlen(qpathname); 689128345Stjr while (p - gfilename + n + 2 >= len) 690128345Stjr { 691128345Stjr /* 692128345Stjr * No room in current buffer. 693128345Stjr * Allocate a bigger one. 694128345Stjr */ 695128345Stjr len *= 2; 696128345Stjr *p = '\0'; 697128345Stjr p = (char *) ecalloc(len, sizeof(char)); 698128345Stjr strcpy(p, gfilename); 699128345Stjr free(gfilename); 700128345Stjr gfilename = p; 701128345Stjr p = gfilename + strlen(gfilename); 702128345Stjr } 703128345Stjr strcpy(p, qpathname); 704128345Stjr free(qpathname); 705128345Stjr p += n; 706128345Stjr *p++ = ' '; 70760786Sps } 70860786Sps } while (GLOB_NEXT_NAME(handle, &fnd) == 0); 70960786Sps 71060786Sps /* 71160786Sps * Overwrite the final trailing space with a null terminator. 71260786Sps */ 71360786Sps *--p = '\0'; 71460786Sps GLOB_NAME_DONE(handle); 71560786Sps} 71660786Sps#else 71760786Sps#if HAVE_POPEN 71860786Sps{ 71960786Sps /* 72060786Sps * We get the shell to glob the filename for us by passing 72160786Sps * an "echo" command to the shell and reading its output. 72260786Sps */ 72360786Sps FILE *fd; 72460786Sps char *s; 72560786Sps char *lessecho; 72660786Sps char *cmd; 727128345Stjr char *esc; 72860786Sps 729128345Stjr esc = get_meta_escape(); 730128345Stjr if (strlen(esc) == 0) 731128345Stjr esc = "-"; 732128345Stjr esc = shell_quote(esc); 733128345Stjr if (esc == NULL) 73460786Sps { 73560786Sps free(filename); 73660786Sps return (ofilename); 73760786Sps } 738128345Stjr lessecho = lgetenv("LESSECHO"); 739128345Stjr if (lessecho == NULL || *lessecho == '\0') 740128345Stjr lessecho = "lessecho"; 74160786Sps /* 74260786Sps * Invoke lessecho, and read its output (a globbed list of filenames). 74360786Sps */ 744128345Stjr cmd = (char *) ecalloc(strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24, sizeof(char)); 745128345Stjr sprintf(cmd, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote, closequote, esc); 746128345Stjr free(esc); 747128345Stjr for (s = metachars(); *s != '\0'; s++) 748128345Stjr sprintf(cmd + strlen(cmd), "-n0x%x ", *s); 749128345Stjr sprintf(cmd + strlen(cmd), "-- %s", ofilename); 75060786Sps fd = shellcmd(cmd); 75160786Sps free(cmd); 75260786Sps if (fd == NULL) 75360786Sps { 75460786Sps /* 75560786Sps * Cannot create the pipe. 75660786Sps * Just return the original (fexpanded) filename. 75760786Sps */ 75860786Sps free(filename); 75960786Sps return (ofilename); 76060786Sps } 76160786Sps gfilename = readfd(fd); 76260786Sps pclose(fd); 76360786Sps if (*gfilename == '\0') 76460786Sps { 76560786Sps free(gfilename); 76660786Sps free(filename); 76760786Sps return (ofilename); 76860786Sps } 76960786Sps} 77060786Sps#else 77160786Sps /* 77260786Sps * No globbing functions at all. Just use the fexpanded filename. 77360786Sps */ 77460786Sps gfilename = save(filename); 77560786Sps#endif 77660786Sps#endif 77760786Sps#endif 77860786Sps free(filename); 77960786Sps free(ofilename); 78060786Sps return (gfilename); 78160786Sps} 78260786Sps 78360786Sps/* 78460786Sps * See if we should open a "replacement file" 78560786Sps * instead of the file we're about to open. 78660786Sps */ 78760786Sps public char * 78860786Spsopen_altfile(filename, pf, pfd) 78960786Sps char *filename; 79060786Sps int *pf; 79160786Sps void **pfd; 79260786Sps{ 79360786Sps#if !HAVE_POPEN 79460786Sps return (NULL); 79560786Sps#else 79660786Sps char *lessopen; 79760786Sps char *cmd; 79860786Sps FILE *fd; 79960786Sps#if HAVE_FILENO 80060786Sps int returnfd = 0; 80160786Sps#endif 80260786Sps 803128345Stjr if (!use_lessopen || secure) 80460786Sps return (NULL); 80560786Sps ch_ungetchar(-1); 80660786Sps if ((lessopen = lgetenv("LESSOPEN")) == NULL) 80760786Sps return (NULL); 80860786Sps if (strcmp(filename, "-") == 0) 80960786Sps return (NULL); 81060786Sps if (*lessopen == '|') 81160786Sps { 81260786Sps /* 81360786Sps * If LESSOPEN starts with a |, it indicates 81460786Sps * a "pipe preprocessor". 81560786Sps */ 81660786Sps#if HAVE_FILENO 81760786Sps lessopen++; 81860786Sps returnfd = 1; 81960786Sps#else 82060786Sps error("LESSOPEN pipe is not supported", NULL_PARG); 82160786Sps return (NULL); 82260786Sps#endif 82360786Sps } 82460786Sps 825128345Stjr cmd = (char *) ecalloc(strlen(lessopen) + strlen(filename) + 2, 82660786Sps sizeof(char)); 827128345Stjr sprintf(cmd, lessopen, filename); 82860786Sps fd = shellcmd(cmd); 82960786Sps free(cmd); 83060786Sps if (fd == NULL) 83160786Sps { 83260786Sps /* 83360786Sps * Cannot create the pipe. 83460786Sps */ 83560786Sps return (NULL); 83660786Sps } 83760786Sps#if HAVE_FILENO 83860786Sps if (returnfd) 83960786Sps { 84060786Sps int f; 84160786Sps char c; 84260786Sps 84360786Sps /* 84460786Sps * Read one char to see if the pipe will produce any data. 84560786Sps * If it does, push the char back on the pipe. 84660786Sps */ 84760786Sps f = fileno(fd); 84860786Sps SET_BINARY(f); 84960786Sps if (read(f, &c, 1) != 1) 85060786Sps { 85160786Sps /* 85260786Sps * Pipe is empty. This means there is no alt file. 85360786Sps */ 85460786Sps pclose(fd); 85560786Sps return (NULL); 85660786Sps } 85760786Sps ch_ungetchar(c); 85860786Sps *pfd = (void *) fd; 85960786Sps *pf = f; 86060786Sps return (save("-")); 86160786Sps } 86260786Sps#endif 863128345Stjr cmd = readfd(fd); 86460786Sps pclose(fd); 865128345Stjr if (*cmd == '\0') 86660786Sps /* 86760786Sps * Pipe is empty. This means there is no alt file. 86860786Sps */ 86960786Sps return (NULL); 870128345Stjr return (cmd); 87160786Sps#endif /* HAVE_POPEN */ 87260786Sps} 87360786Sps 87460786Sps/* 87560786Sps * Close a replacement file. 87660786Sps */ 87760786Sps public void 87860786Spsclose_altfile(altfilename, filename, pipefd) 87960786Sps char *altfilename; 88060786Sps char *filename; 88160786Sps void *pipefd; 88260786Sps{ 88360786Sps#if HAVE_POPEN 88460786Sps char *lessclose; 88560786Sps FILE *fd; 88660786Sps char *cmd; 88760786Sps 88860786Sps if (secure) 88960786Sps return; 89060786Sps if (pipefd != NULL) 89189019Sps { 89289019Sps#if OS2 89389019Sps /* 89489019Sps * The pclose function of OS/2 emx sometimes fails. 89589019Sps * Send SIGINT to the piped process before closing it. 89689019Sps */ 89789019Sps kill(((FILE*)pipefd)->_pid, SIGINT); 89889019Sps#endif 89960786Sps pclose((FILE*) pipefd); 90089019Sps } 90160786Sps if ((lessclose = lgetenv("LESSCLOSE")) == NULL) 90260786Sps return; 903128345Stjr cmd = (char *) ecalloc(strlen(lessclose) + strlen(filename) + 904128345Stjr strlen(altfilename) + 2, sizeof(char)); 905128345Stjr sprintf(cmd, lessclose, filename, altfilename); 90660786Sps fd = shellcmd(cmd); 90760786Sps free(cmd); 90860786Sps if (fd != NULL) 90960786Sps pclose(fd); 91060786Sps#endif 91160786Sps} 91260786Sps 91360786Sps/* 91460786Sps * Is the specified file a directory? 91560786Sps */ 91660786Sps public int 91760786Spsis_dir(filename) 91860786Sps char *filename; 91960786Sps{ 92060786Sps int isdir = 0; 92160786Sps 922128345Stjr filename = shell_unquote(filename); 92360786Sps#if HAVE_STAT 92460786Sps{ 92560786Sps int r; 92660786Sps struct stat statbuf; 92760786Sps 92860786Sps r = stat(filename, &statbuf); 92960786Sps isdir = (r >= 0 && S_ISDIR(statbuf.st_mode)); 93060786Sps} 93160786Sps#else 93260786Sps#ifdef _OSK 93360786Sps{ 93460786Sps register int f; 93560786Sps 93660786Sps f = open(filename, S_IREAD | S_IFDIR); 93760786Sps if (f >= 0) 93860786Sps close(f); 93960786Sps isdir = (f >= 0); 94060786Sps} 94160786Sps#endif 94260786Sps#endif 94360786Sps free(filename); 94460786Sps return (isdir); 94560786Sps} 94660786Sps 94760786Sps/* 94860786Sps * Returns NULL if the file can be opened and 94960786Sps * is an ordinary file, otherwise an error message 95060786Sps * (if it cannot be opened or is a directory, etc.) 95160786Sps */ 95260786Sps public char * 95360786Spsbad_file(filename) 95460786Sps char *filename; 95560786Sps{ 95660786Sps register char *m = NULL; 95760786Sps 958128345Stjr filename = shell_unquote(filename); 95960786Sps if (is_dir(filename)) 96060786Sps { 961128345Stjr static char is_a_dir[] = " is a directory"; 96260786Sps 963128345Stjr m = (char *) ecalloc(strlen(filename) + sizeof(is_a_dir), 96460786Sps sizeof(char)); 96560786Sps strcpy(m, filename); 966128345Stjr strcat(m, is_a_dir); 96760786Sps } else 96860786Sps { 96960786Sps#if HAVE_STAT 97060786Sps int r; 97160786Sps struct stat statbuf; 97260786Sps 97360786Sps r = stat(filename, &statbuf); 97460786Sps if (r < 0) 97560786Sps { 97660786Sps m = errno_message(filename); 97760786Sps } else if (force_open) 97860786Sps { 97960786Sps m = NULL; 98060786Sps } else if (!S_ISREG(statbuf.st_mode)) 98160786Sps { 98260786Sps static char not_reg[] = " is not a regular file (use -f to see it)"; 98360786Sps m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 98460786Sps sizeof(char)); 98560786Sps strcpy(m, filename); 98660786Sps strcat(m, not_reg); 98760786Sps } 98860786Sps#endif 98960786Sps } 99060786Sps free(filename); 99160786Sps return (m); 99260786Sps} 99360786Sps 99460786Sps/* 99560786Sps * Return the size of a file, as cheaply as possible. 99660786Sps * In Unix, we can stat the file. 99760786Sps */ 99860786Sps public POSITION 99960786Spsfilesize(f) 100060786Sps int f; 100160786Sps{ 100260786Sps#if HAVE_STAT 100360786Sps struct stat statbuf; 100460786Sps 100560786Sps if (fstat(f, &statbuf) >= 0) 100660786Sps return ((POSITION) statbuf.st_size); 100760786Sps#else 100860786Sps#ifdef _OSK 100960786Sps long size; 101060786Sps 101160786Sps if ((size = (long) _gs_size(f)) >= 0) 101260786Sps return ((POSITION) size); 101360786Sps#endif 101460786Sps#endif 101560786Sps return (seek_filesize(f)); 101660786Sps} 101760786Sps 1018128345Stjr/* 1019128345Stjr * 1020128345Stjr */ 1021128345Stjr public char * 1022128345Stjrshell_coption() 1023128345Stjr{ 1024128345Stjr return ("-c"); 1025128345Stjr} 1026