filename.c revision 161475
160786Sps/* 2161475Sdelphij * Copyright (C) 1984-2005 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 { 198161475Sdelphij SNPRINTF3(newstr, len, "%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; 229161475Sdelphij int len; 23060786Sps int f; 23160786Sps 23260786Sps if (dirname == NULL || *dirname == '\0') 23360786Sps return (NULL); 23460786Sps /* 23560786Sps * Construct the full pathname. 23660786Sps */ 237161475Sdelphij len= strlen(dirname) + strlen(filename) + 2; 238161475Sdelphij pathname = (char *) calloc(len, sizeof(char)); 23960786Sps if (pathname == NULL) 24060786Sps return (NULL); 241161475Sdelphij SNPRINTF3(pathname, len, "%s%s%s", dirname, PATHNAME_SEP, filename); 24260786Sps /* 24360786Sps * Make sure the file exists. 24460786Sps */ 245128345Stjr qpathname = shell_unquote(pathname); 24660786Sps f = open(qpathname, OPEN_READ); 24760786Sps if (f < 0) 24860786Sps { 24960786Sps free(pathname); 25060786Sps pathname = NULL; 25160786Sps } else 25260786Sps { 25360786Sps close(f); 25460786Sps } 25560786Sps free(qpathname); 25660786Sps return (pathname); 25760786Sps} 25860786Sps 25960786Sps/* 26060786Sps * Return the full pathname of the given file in the "home directory". 26160786Sps */ 26260786Sps public char * 26360786Spshomefile(filename) 26460786Sps char *filename; 26560786Sps{ 26660786Sps register char *pathname; 26760786Sps 26860786Sps /* 26960786Sps * Try $HOME/filename. 27060786Sps */ 27160786Sps pathname = dirfile(lgetenv("HOME"), filename); 27260786Sps if (pathname != NULL) 27360786Sps return (pathname); 27460786Sps#if OS2 27560786Sps /* 27660786Sps * Try $INIT/filename. 27760786Sps */ 27860786Sps pathname = dirfile(lgetenv("INIT"), filename); 27960786Sps if (pathname != NULL) 28060786Sps return (pathname); 28160786Sps#endif 28260786Sps#if MSDOS_COMPILER || OS2 28360786Sps /* 28460786Sps * Look for the file anywhere on search path. 28560786Sps */ 28660786Sps pathname = (char *) calloc(_MAX_PATH, sizeof(char)); 28760786Sps#if MSDOS_COMPILER==DJGPPC 28860786Sps { 28960786Sps char *res = searchpath(filename); 29060786Sps if (res == 0) 29160786Sps *pathname = '\0'; 29260786Sps else 29360786Sps strcpy(pathname, res); 29460786Sps } 29560786Sps#else 29660786Sps _searchenv(filename, "PATH", pathname); 29760786Sps#endif 29860786Sps if (*pathname != '\0') 29960786Sps return (pathname); 30060786Sps free(pathname); 30160786Sps#endif 30260786Sps return (NULL); 30360786Sps} 30460786Sps 30560786Sps/* 30660786Sps * Expand a string, substituting any "%" with the current filename, 30760786Sps * and any "#" with the previous filename. 30860786Sps * But a string of N "%"s is just replaced with N-1 "%"s. 30960786Sps * Likewise for a string of N "#"s. 31060786Sps * {{ This is a lot of work just to support % and #. }} 31160786Sps */ 31260786Sps public char * 31360786Spsfexpand(s) 31460786Sps char *s; 31560786Sps{ 31660786Sps register char *fr, *to; 31760786Sps register int n; 31860786Sps register char *e; 31960786Sps IFILE ifile; 32060786Sps 32160786Sps#define fchar_ifile(c) \ 32260786Sps ((c) == '%' ? curr_ifile : \ 32360786Sps (c) == '#' ? old_ifile : NULL_IFILE) 32460786Sps 32560786Sps /* 32660786Sps * Make one pass to see how big a buffer we 32760786Sps * need to allocate for the expanded string. 32860786Sps */ 32960786Sps n = 0; 33060786Sps for (fr = s; *fr != '\0'; fr++) 33160786Sps { 33260786Sps switch (*fr) 33360786Sps { 33460786Sps case '%': 33560786Sps case '#': 33660786Sps if (fr > s && fr[-1] == *fr) 33760786Sps { 33860786Sps /* 33960786Sps * Second (or later) char in a string 34060786Sps * of identical chars. Treat as normal. 34160786Sps */ 34260786Sps n++; 34360786Sps } else if (fr[1] != *fr) 34460786Sps { 34560786Sps /* 34660786Sps * Single char (not repeated). Treat specially. 34760786Sps */ 34860786Sps ifile = fchar_ifile(*fr); 34960786Sps if (ifile == NULL_IFILE) 35060786Sps n++; 35160786Sps else 35260786Sps n += strlen(get_filename(ifile)); 35360786Sps } 35460786Sps /* 35560786Sps * Else it is the first char in a string of 35660786Sps * identical chars. Just discard it. 35760786Sps */ 35860786Sps break; 35960786Sps default: 36060786Sps n++; 36160786Sps break; 36260786Sps } 36360786Sps } 36460786Sps 36560786Sps e = (char *) ecalloc(n+1, sizeof(char)); 36660786Sps 36760786Sps /* 36860786Sps * Now copy the string, expanding any "%" or "#". 36960786Sps */ 37060786Sps to = e; 37160786Sps for (fr = s; *fr != '\0'; fr++) 37260786Sps { 37360786Sps switch (*fr) 37460786Sps { 37560786Sps case '%': 37660786Sps case '#': 37760786Sps if (fr > s && fr[-1] == *fr) 37860786Sps { 37960786Sps *to++ = *fr; 38060786Sps } else if (fr[1] != *fr) 38160786Sps { 38260786Sps ifile = fchar_ifile(*fr); 38360786Sps if (ifile == NULL_IFILE) 38460786Sps *to++ = *fr; 38560786Sps else 38660786Sps { 38760786Sps strcpy(to, get_filename(ifile)); 38860786Sps to += strlen(to); 38960786Sps } 39060786Sps } 39160786Sps break; 39260786Sps default: 39360786Sps *to++ = *fr; 39460786Sps break; 39560786Sps } 39660786Sps } 39760786Sps *to = '\0'; 39860786Sps return (e); 39960786Sps} 40060786Sps 40160786Sps#if TAB_COMPLETE_FILENAME 40260786Sps 40360786Sps/* 40460786Sps * Return a blank-separated list of filenames which "complete" 40560786Sps * the given string. 40660786Sps */ 40760786Sps public char * 40860786Spsfcomplete(s) 40960786Sps char *s; 41060786Sps{ 41160786Sps char *fpat; 412128345Stjr char *qs; 41360786Sps 41460786Sps if (secure) 41560786Sps return (NULL); 41660786Sps /* 41760786Sps * Complete the filename "s" by globbing "s*". 41860786Sps */ 41960786Sps#if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC) 42060786Sps /* 42160786Sps * But in DOS, we have to glob "s*.*". 42260786Sps * But if the final component of the filename already has 42360786Sps * a dot in it, just do "s*". 42460786Sps * (Thus, "FILE" is globbed as "FILE*.*", 42560786Sps * but "FILE.A" is globbed as "FILE.A*"). 42660786Sps */ 42760786Sps { 42860786Sps char *slash; 429161475Sdelphij int len; 43060786Sps for (slash = s+strlen(s)-1; slash > s; slash--) 43160786Sps if (*slash == *PATHNAME_SEP || *slash == '/') 43260786Sps break; 433161475Sdelphij len = strlen(s) + 4; 434161475Sdelphij fpat = (char *) ecalloc(len, sizeof(char)); 43560786Sps if (strchr(slash, '.') == NULL) 436161475Sdelphij SNPRINTF1(fpat, len, "%s*.*", s); 43760786Sps else 438161475Sdelphij SNPRINTF1(fpat, len, "%s*", s); 43960786Sps } 44060786Sps#else 441161475Sdelphij { 442161475Sdelphij int len = strlen(s) + 2; 443161475Sdelphij fpat = (char *) ecalloc(len, sizeof(char)); 444161475Sdelphij SNPRINTF1(fpat, len, "%s*", s); 445161475Sdelphij } 44660786Sps#endif 447128345Stjr qs = lglob(fpat); 448128345Stjr s = shell_unquote(qs); 44960786Sps if (strcmp(s,fpat) == 0) 45060786Sps { 45160786Sps /* 45260786Sps * The filename didn't expand. 45360786Sps */ 454128345Stjr free(qs); 455128345Stjr qs = NULL; 45660786Sps } 457128345Stjr free(s); 45860786Sps free(fpat); 459128345Stjr return (qs); 46060786Sps} 46160786Sps#endif 46260786Sps 46360786Sps/* 46460786Sps * Try to determine if a file is "binary". 46560786Sps * This is just a guess, and we need not try too hard to make it accurate. 46660786Sps */ 46760786Sps public int 46860786Spsbin_file(f) 46960786Sps int f; 47060786Sps{ 47160786Sps int i; 47260786Sps int n; 47360786Sps unsigned char data[64]; 47460786Sps 47560786Sps if (!seekable(f)) 47660786Sps return (0); 47760786Sps if (lseek(f, (off_t)0, 0) == BAD_LSEEK) 47860786Sps return (0); 47960786Sps n = read(f, data, sizeof(data)); 48060786Sps for (i = 0; i < n; i++) 48160786Sps if (binary_char(data[i])) 48260786Sps return (1); 48360786Sps return (0); 48460786Sps} 48560786Sps 48660786Sps/* 48760786Sps * Try to determine the size of a file by seeking to the end. 48860786Sps */ 48960786Sps static POSITION 49060786Spsseek_filesize(f) 49160786Sps int f; 49260786Sps{ 49360786Sps off_t spos; 49460786Sps 49560786Sps spos = lseek(f, (off_t)0, 2); 49660786Sps if (spos == BAD_LSEEK) 49760786Sps return (NULL_POSITION); 49860786Sps return ((POSITION) spos); 49960786Sps} 50060786Sps 50160786Sps/* 50260786Sps * Read a string from a file. 50360786Sps * Return a pointer to the string in memory. 50460786Sps */ 50560786Sps static char * 50660786Spsreadfd(fd) 50760786Sps FILE *fd; 50860786Sps{ 50960786Sps int len; 51060786Sps int ch; 51160786Sps char *buf; 51260786Sps char *p; 51360786Sps 51460786Sps /* 51560786Sps * Make a guess about how many chars in the string 51660786Sps * and allocate a buffer to hold it. 51760786Sps */ 51860786Sps len = 100; 51960786Sps buf = (char *) ecalloc(len, sizeof(char)); 52060786Sps for (p = buf; ; p++) 52160786Sps { 52260786Sps if ((ch = getc(fd)) == '\n' || ch == EOF) 52360786Sps break; 52460786Sps if (p - buf >= len-1) 52560786Sps { 52660786Sps /* 52760786Sps * The string is too big to fit in the buffer we have. 52860786Sps * Allocate a new buffer, twice as big. 52960786Sps */ 53060786Sps len *= 2; 53160786Sps *p = '\0'; 53260786Sps p = (char *) ecalloc(len, sizeof(char)); 53360786Sps strcpy(p, buf); 53460786Sps free(buf); 53560786Sps buf = p; 53660786Sps p = buf + strlen(buf); 53760786Sps } 53860786Sps *p = ch; 53960786Sps } 54060786Sps *p = '\0'; 54160786Sps return (buf); 54260786Sps} 54360786Sps 54460786Sps 54560786Sps 54660786Sps#if HAVE_POPEN 54760786Sps 54860786SpsFILE *popen(); 54960786Sps 55060786Sps/* 55160786Sps * Execute a shell command. 55260786Sps * Return a pointer to a pipe connected to the shell command's standard output. 55360786Sps */ 55460786Sps static FILE * 55560786Spsshellcmd(cmd) 55660786Sps char *cmd; 55760786Sps{ 55860786Sps FILE *fd; 55960786Sps 56060786Sps#if HAVE_SHELL 56160786Sps char *shell; 56260786Sps 56360786Sps shell = lgetenv("SHELL"); 56460786Sps if (shell != NULL && *shell != '\0') 56560786Sps { 56660786Sps char *scmd; 56760786Sps char *esccmd; 56860786Sps 56960786Sps /* 570128345Stjr * Read the output of <$SHELL -c cmd>. 571128345Stjr * Escape any metacharacters in the command. 57260786Sps */ 573128345Stjr esccmd = shell_quote(cmd); 574128345Stjr if (esccmd == NULL) 57560786Sps { 576128345Stjr fd = popen(cmd, "r"); 57760786Sps } else 57860786Sps { 579161475Sdelphij int len = strlen(shell) + strlen(esccmd) + 5; 580161475Sdelphij scmd = (char *) ecalloc(len, sizeof(char)); 581161475Sdelphij SNPRINTF3(scmd, len, "%s %s %s", shell, shell_coption(), esccmd); 58260786Sps free(esccmd); 583128345Stjr fd = popen(scmd, "r"); 584128345Stjr free(scmd); 58560786Sps } 58660786Sps } else 58760786Sps#endif 58860786Sps { 58960786Sps fd = popen(cmd, "r"); 59060786Sps } 591128345Stjr /* 592128345Stjr * Redirection in `popen' might have messed with the 593128345Stjr * standard devices. Restore binary input mode. 594128345Stjr */ 595128345Stjr SET_BINARY(0); 59660786Sps return (fd); 59760786Sps} 59860786Sps 59960786Sps#endif /* HAVE_POPEN */ 60060786Sps 60160786Sps 60260786Sps/* 60360786Sps * Expand a filename, doing any system-specific metacharacter substitutions. 60460786Sps */ 60560786Sps public char * 60660786Spslglob(filename) 60760786Sps char *filename; 60860786Sps{ 60960786Sps char *gfilename; 61060786Sps char *ofilename; 61160786Sps 61260786Sps ofilename = fexpand(filename); 61360786Sps if (secure) 61460786Sps return (ofilename); 615128345Stjr filename = shell_unquote(ofilename); 61660786Sps 61760786Sps#ifdef DECL_GLOB_LIST 61860786Sps{ 61960786Sps /* 62060786Sps * The globbing function returns a list of names. 62160786Sps */ 62260786Sps int length; 62360786Sps char *p; 624128345Stjr char *qfilename; 62560786Sps DECL_GLOB_LIST(list) 62660786Sps 62760786Sps GLOB_LIST(filename, list); 62860786Sps if (GLOB_LIST_FAILED(list)) 62960786Sps { 63060786Sps free(filename); 63160786Sps return (ofilename); 63260786Sps } 63360786Sps length = 1; /* Room for trailing null byte */ 63460786Sps for (SCAN_GLOB_LIST(list, p)) 63560786Sps { 63660786Sps INIT_GLOB_LIST(list, p); 637128345Stjr qfilename = shell_quote(p); 638128345Stjr if (qfilename != NULL) 639128345Stjr { 640128345Stjr length += strlen(qfilename) + 1; 641128345Stjr free(qfilename); 642128345Stjr } 64360786Sps } 64460786Sps gfilename = (char *) ecalloc(length, sizeof(char)); 64560786Sps for (SCAN_GLOB_LIST(list, p)) 64660786Sps { 64760786Sps INIT_GLOB_LIST(list, p); 648128345Stjr qfilename = shell_quote(p); 649128345Stjr if (qfilename != NULL) 650128345Stjr { 651128345Stjr sprintf(gfilename + strlen(gfilename), "%s ", qfilename); 652128345Stjr free(qfilename); 653128345Stjr } 65460786Sps } 65560786Sps /* 65660786Sps * Overwrite the final trailing space with a null terminator. 65760786Sps */ 65860786Sps *--p = '\0'; 65960786Sps GLOB_LIST_DONE(list); 66060786Sps} 66160786Sps#else 66260786Sps#ifdef DECL_GLOB_NAME 66360786Sps{ 66460786Sps /* 66560786Sps * The globbing function returns a single name, and 66660786Sps * is called multiple times to walk thru all names. 66760786Sps */ 66860786Sps register char *p; 66960786Sps register int len; 67060786Sps register int n; 671128345Stjr char *pathname; 672128345Stjr char *qpathname; 67360786Sps DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) 67460786Sps 67560786Sps GLOB_FIRST_NAME(filename, &fnd, handle); 67660786Sps if (GLOB_FIRST_FAILED(handle)) 67760786Sps { 67860786Sps free(filename); 67960786Sps return (ofilename); 68060786Sps } 68160786Sps 68260786Sps _splitpath(filename, drive, dir, fname, ext); 68360786Sps len = 100; 68460786Sps gfilename = (char *) ecalloc(len, sizeof(char)); 68560786Sps p = gfilename; 68660786Sps do { 68760786Sps n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1; 688128345Stjr pathname = (char *) ecalloc(n, sizeof(char)); 689161475Sdelphij SNPRINTF3(pathname, n, "%s%s%s", drive, dir, fnd.GLOB_NAME); 690128345Stjr qpathname = shell_quote(pathname); 691128345Stjr free(pathname); 692128345Stjr if (qpathname != NULL) 69360786Sps { 694128345Stjr n = strlen(qpathname); 695128345Stjr while (p - gfilename + n + 2 >= len) 696128345Stjr { 697128345Stjr /* 698128345Stjr * No room in current buffer. 699128345Stjr * Allocate a bigger one. 700128345Stjr */ 701128345Stjr len *= 2; 702128345Stjr *p = '\0'; 703128345Stjr p = (char *) ecalloc(len, sizeof(char)); 704128345Stjr strcpy(p, gfilename); 705128345Stjr free(gfilename); 706128345Stjr gfilename = p; 707128345Stjr p = gfilename + strlen(gfilename); 708128345Stjr } 709128345Stjr strcpy(p, qpathname); 710128345Stjr free(qpathname); 711128345Stjr p += n; 712128345Stjr *p++ = ' '; 71360786Sps } 71460786Sps } while (GLOB_NEXT_NAME(handle, &fnd) == 0); 71560786Sps 71660786Sps /* 71760786Sps * Overwrite the final trailing space with a null terminator. 71860786Sps */ 71960786Sps *--p = '\0'; 72060786Sps GLOB_NAME_DONE(handle); 72160786Sps} 72260786Sps#else 72360786Sps#if HAVE_POPEN 72460786Sps{ 72560786Sps /* 72660786Sps * We get the shell to glob the filename for us by passing 72760786Sps * an "echo" command to the shell and reading its output. 72860786Sps */ 72960786Sps FILE *fd; 73060786Sps char *s; 73160786Sps char *lessecho; 73260786Sps char *cmd; 733128345Stjr char *esc; 734161475Sdelphij int len; 73560786Sps 736128345Stjr esc = get_meta_escape(); 737128345Stjr if (strlen(esc) == 0) 738128345Stjr esc = "-"; 739128345Stjr esc = shell_quote(esc); 740128345Stjr if (esc == NULL) 74160786Sps { 74260786Sps free(filename); 74360786Sps return (ofilename); 74460786Sps } 745128345Stjr lessecho = lgetenv("LESSECHO"); 746128345Stjr if (lessecho == NULL || *lessecho == '\0') 747128345Stjr lessecho = "lessecho"; 74860786Sps /* 74960786Sps * Invoke lessecho, and read its output (a globbed list of filenames). 75060786Sps */ 751161475Sdelphij len = strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24; 752161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 753161475Sdelphij SNPRINTF4(cmd, len, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote, closequote, esc); 754128345Stjr free(esc); 755128345Stjr for (s = metachars(); *s != '\0'; s++) 756128345Stjr sprintf(cmd + strlen(cmd), "-n0x%x ", *s); 757128345Stjr sprintf(cmd + strlen(cmd), "-- %s", ofilename); 75860786Sps fd = shellcmd(cmd); 75960786Sps free(cmd); 76060786Sps if (fd == NULL) 76160786Sps { 76260786Sps /* 76360786Sps * Cannot create the pipe. 76460786Sps * Just return the original (fexpanded) filename. 76560786Sps */ 76660786Sps free(filename); 76760786Sps return (ofilename); 76860786Sps } 76960786Sps gfilename = readfd(fd); 77060786Sps pclose(fd); 77160786Sps if (*gfilename == '\0') 77260786Sps { 77360786Sps free(gfilename); 77460786Sps free(filename); 77560786Sps return (ofilename); 77660786Sps } 77760786Sps} 77860786Sps#else 77960786Sps /* 78060786Sps * No globbing functions at all. Just use the fexpanded filename. 78160786Sps */ 78260786Sps gfilename = save(filename); 78360786Sps#endif 78460786Sps#endif 78560786Sps#endif 78660786Sps free(filename); 78760786Sps free(ofilename); 78860786Sps return (gfilename); 78960786Sps} 79060786Sps 79160786Sps/* 79260786Sps * See if we should open a "replacement file" 79360786Sps * instead of the file we're about to open. 79460786Sps */ 79560786Sps public char * 79660786Spsopen_altfile(filename, pf, pfd) 79760786Sps char *filename; 79860786Sps int *pf; 79960786Sps void **pfd; 80060786Sps{ 80160786Sps#if !HAVE_POPEN 80260786Sps return (NULL); 80360786Sps#else 80460786Sps char *lessopen; 80560786Sps char *cmd; 806161475Sdelphij int len; 80760786Sps FILE *fd; 80860786Sps#if HAVE_FILENO 80960786Sps int returnfd = 0; 81060786Sps#endif 81160786Sps 812128345Stjr if (!use_lessopen || secure) 81360786Sps return (NULL); 81460786Sps ch_ungetchar(-1); 81560786Sps if ((lessopen = lgetenv("LESSOPEN")) == NULL) 81660786Sps return (NULL); 81760786Sps if (strcmp(filename, "-") == 0) 81860786Sps return (NULL); 81960786Sps if (*lessopen == '|') 82060786Sps { 82160786Sps /* 82260786Sps * If LESSOPEN starts with a |, it indicates 82360786Sps * a "pipe preprocessor". 82460786Sps */ 82560786Sps#if HAVE_FILENO 82660786Sps lessopen++; 82760786Sps returnfd = 1; 82860786Sps#else 82960786Sps error("LESSOPEN pipe is not supported", NULL_PARG); 83060786Sps return (NULL); 83160786Sps#endif 83260786Sps } 83360786Sps 834161475Sdelphij len = strlen(lessopen) + strlen(filename) + 2; 835161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 836161475Sdelphij SNPRINTF1(cmd, len, lessopen, filename); 83760786Sps fd = shellcmd(cmd); 83860786Sps free(cmd); 83960786Sps if (fd == NULL) 84060786Sps { 84160786Sps /* 84260786Sps * Cannot create the pipe. 84360786Sps */ 84460786Sps return (NULL); 84560786Sps } 84660786Sps#if HAVE_FILENO 84760786Sps if (returnfd) 84860786Sps { 84960786Sps int f; 85060786Sps char c; 85160786Sps 85260786Sps /* 85360786Sps * Read one char to see if the pipe will produce any data. 85460786Sps * If it does, push the char back on the pipe. 85560786Sps */ 85660786Sps f = fileno(fd); 85760786Sps SET_BINARY(f); 85860786Sps if (read(f, &c, 1) != 1) 85960786Sps { 86060786Sps /* 86160786Sps * Pipe is empty. This means there is no alt file. 86260786Sps */ 86360786Sps pclose(fd); 86460786Sps return (NULL); 86560786Sps } 86660786Sps ch_ungetchar(c); 86760786Sps *pfd = (void *) fd; 86860786Sps *pf = f; 86960786Sps return (save("-")); 87060786Sps } 87160786Sps#endif 872128345Stjr cmd = readfd(fd); 87360786Sps pclose(fd); 874128345Stjr if (*cmd == '\0') 87560786Sps /* 87660786Sps * Pipe is empty. This means there is no alt file. 87760786Sps */ 87860786Sps return (NULL); 879128345Stjr return (cmd); 88060786Sps#endif /* HAVE_POPEN */ 88160786Sps} 88260786Sps 88360786Sps/* 88460786Sps * Close a replacement file. 88560786Sps */ 88660786Sps public void 88760786Spsclose_altfile(altfilename, filename, pipefd) 88860786Sps char *altfilename; 88960786Sps char *filename; 89060786Sps void *pipefd; 89160786Sps{ 89260786Sps#if HAVE_POPEN 89360786Sps char *lessclose; 89460786Sps FILE *fd; 89560786Sps char *cmd; 896161475Sdelphij int len; 89760786Sps 89860786Sps if (secure) 89960786Sps return; 90060786Sps if (pipefd != NULL) 90189019Sps { 90289019Sps#if OS2 90389019Sps /* 90489019Sps * The pclose function of OS/2 emx sometimes fails. 90589019Sps * Send SIGINT to the piped process before closing it. 90689019Sps */ 90789019Sps kill(((FILE*)pipefd)->_pid, SIGINT); 90889019Sps#endif 90960786Sps pclose((FILE*) pipefd); 91089019Sps } 91160786Sps if ((lessclose = lgetenv("LESSCLOSE")) == NULL) 91260786Sps return; 913161475Sdelphij len = strlen(lessclose) + strlen(filename) + strlen(altfilename) + 2; 914161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 915161475Sdelphij SNPRINTF2(cmd, len, lessclose, filename, altfilename); 91660786Sps fd = shellcmd(cmd); 91760786Sps free(cmd); 91860786Sps if (fd != NULL) 91960786Sps pclose(fd); 92060786Sps#endif 92160786Sps} 92260786Sps 92360786Sps/* 92460786Sps * Is the specified file a directory? 92560786Sps */ 92660786Sps public int 92760786Spsis_dir(filename) 92860786Sps char *filename; 92960786Sps{ 93060786Sps int isdir = 0; 93160786Sps 932128345Stjr filename = shell_unquote(filename); 93360786Sps#if HAVE_STAT 93460786Sps{ 93560786Sps int r; 93660786Sps struct stat statbuf; 93760786Sps 93860786Sps r = stat(filename, &statbuf); 93960786Sps isdir = (r >= 0 && S_ISDIR(statbuf.st_mode)); 94060786Sps} 94160786Sps#else 94260786Sps#ifdef _OSK 94360786Sps{ 94460786Sps register int f; 94560786Sps 94660786Sps f = open(filename, S_IREAD | S_IFDIR); 94760786Sps if (f >= 0) 94860786Sps close(f); 94960786Sps isdir = (f >= 0); 95060786Sps} 95160786Sps#endif 95260786Sps#endif 95360786Sps free(filename); 95460786Sps return (isdir); 95560786Sps} 95660786Sps 95760786Sps/* 95860786Sps * Returns NULL if the file can be opened and 95960786Sps * is an ordinary file, otherwise an error message 96060786Sps * (if it cannot be opened or is a directory, etc.) 96160786Sps */ 96260786Sps public char * 96360786Spsbad_file(filename) 96460786Sps char *filename; 96560786Sps{ 96660786Sps register char *m = NULL; 96760786Sps 968128345Stjr filename = shell_unquote(filename); 96960786Sps if (is_dir(filename)) 97060786Sps { 971128345Stjr static char is_a_dir[] = " is a directory"; 97260786Sps 973128345Stjr m = (char *) ecalloc(strlen(filename) + sizeof(is_a_dir), 97460786Sps sizeof(char)); 97560786Sps strcpy(m, filename); 976128345Stjr strcat(m, is_a_dir); 97760786Sps } else 97860786Sps { 97960786Sps#if HAVE_STAT 98060786Sps int r; 98160786Sps struct stat statbuf; 98260786Sps 98360786Sps r = stat(filename, &statbuf); 98460786Sps if (r < 0) 98560786Sps { 98660786Sps m = errno_message(filename); 98760786Sps } else if (force_open) 98860786Sps { 98960786Sps m = NULL; 99060786Sps } else if (!S_ISREG(statbuf.st_mode)) 99160786Sps { 99260786Sps static char not_reg[] = " is not a regular file (use -f to see it)"; 99360786Sps m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 99460786Sps sizeof(char)); 99560786Sps strcpy(m, filename); 99660786Sps strcat(m, not_reg); 99760786Sps } 99860786Sps#endif 99960786Sps } 100060786Sps free(filename); 100160786Sps return (m); 100260786Sps} 100360786Sps 100460786Sps/* 100560786Sps * Return the size of a file, as cheaply as possible. 100660786Sps * In Unix, we can stat the file. 100760786Sps */ 100860786Sps public POSITION 100960786Spsfilesize(f) 101060786Sps int f; 101160786Sps{ 101260786Sps#if HAVE_STAT 101360786Sps struct stat statbuf; 101460786Sps 101560786Sps if (fstat(f, &statbuf) >= 0) 101660786Sps return ((POSITION) statbuf.st_size); 101760786Sps#else 101860786Sps#ifdef _OSK 101960786Sps long size; 102060786Sps 102160786Sps if ((size = (long) _gs_size(f)) >= 0) 102260786Sps return ((POSITION) size); 102360786Sps#endif 102460786Sps#endif 102560786Sps return (seek_filesize(f)); 102660786Sps} 102760786Sps 1028128345Stjr/* 1029128345Stjr * 1030128345Stjr */ 1031128345Stjr public char * 1032128345Stjrshell_coption() 1033128345Stjr{ 1034128345Stjr return ("-c"); 1035128345Stjr} 1036