filename.c revision 170256
160786Sps/* 2170256Sdelphij * Copyright (C) 1984-2007 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; 54170256Sdelphijextern int ctldisp; 5560786Spsextern IFILE curr_ifile; 5660786Spsextern IFILE old_ifile; 5760786Sps#if SPACES_IN_FILENAMES 5860786Spsextern char openquote; 5960786Spsextern char closequote; 6060786Sps#endif 6160786Sps 6260786Sps/* 6360786Sps * Remove quotes around a filename. 6460786Sps */ 6560786Sps public char * 66128345Stjrshell_unquote(str) 6760786Sps char *str; 6860786Sps{ 6960786Sps char *name; 7060786Sps char *p; 7160786Sps 72128345Stjr name = p = (char *) ecalloc(strlen(str)+1, sizeof(char)); 73128345Stjr if (*str == openquote) 74128345Stjr { 75128345Stjr str++; 76128345Stjr while (*str != '\0') 77128345Stjr { 78128345Stjr if (*str == closequote) 79128345Stjr { 80128345Stjr if (str[1] != closequote) 81128345Stjr break; 82128345Stjr str++; 83128345Stjr } 84128345Stjr *p++ = *str++; 85128345Stjr } 86128345Stjr } else 87128345Stjr { 88128345Stjr char *esc = get_meta_escape(); 89128345Stjr int esclen = strlen(esc); 90128345Stjr while (*str != '\0') 91128345Stjr { 92128345Stjr if (esclen > 0 && strncmp(str, esc, esclen) == 0) 93128345Stjr str += esclen; 94128345Stjr *p++ = *str++; 95128345Stjr } 96128345Stjr } 97128345Stjr *p = '\0'; 9860786Sps return (name); 9960786Sps} 10060786Sps 10160786Sps/* 102128345Stjr * Get the shell's escape character. 103128345Stjr */ 104128345Stjr public char * 105128345Stjrget_meta_escape() 106128345Stjr{ 107128345Stjr char *s; 108128345Stjr 109128345Stjr s = lgetenv("LESSMETAESCAPE"); 110128345Stjr if (s == NULL) 111128345Stjr s = DEF_METAESCAPE; 112128345Stjr return (s); 113128345Stjr} 114128345Stjr 115128345Stjr/* 116128345Stjr * Get the characters which the shell considers to be "metacharacters". 117128345Stjr */ 118128345Stjr static char * 119128345Stjrmetachars() 120128345Stjr{ 121128345Stjr static char *mchars = NULL; 122128345Stjr 123128345Stjr if (mchars == NULL) 124128345Stjr { 125128345Stjr mchars = lgetenv("LESSMETACHARS"); 126128345Stjr if (mchars == NULL) 127128345Stjr mchars = DEF_METACHARS; 128128345Stjr } 129128345Stjr return (mchars); 130128345Stjr} 131128345Stjr 132128345Stjr/* 133128345Stjr * Is this a shell metacharacter? 134128345Stjr */ 135128345Stjr static int 136128345Stjrmetachar(c) 137128345Stjr char c; 138128345Stjr{ 139128345Stjr return (strchr(metachars(), c) != NULL); 140128345Stjr} 141128345Stjr 142128345Stjr/* 143128345Stjr * Insert a backslash before each metacharacter in a string. 144128345Stjr */ 145128345Stjr public char * 146128345Stjrshell_quote(s) 147128345Stjr char *s; 148128345Stjr{ 149128345Stjr char *p; 150128345Stjr char *newstr; 151128345Stjr int len; 152128345Stjr char *esc = get_meta_escape(); 153128345Stjr int esclen = strlen(esc); 154128345Stjr int use_quotes = 0; 155128345Stjr int have_quotes = 0; 156128345Stjr 157128345Stjr /* 158128345Stjr * Determine how big a string we need to allocate. 159128345Stjr */ 160128345Stjr len = 1; /* Trailing null byte */ 161128345Stjr for (p = s; *p != '\0'; p++) 162128345Stjr { 163128345Stjr len++; 164128345Stjr if (*p == openquote || *p == closequote) 165128345Stjr have_quotes = 1; 166128345Stjr if (metachar(*p)) 167128345Stjr { 168128345Stjr if (esclen == 0) 169128345Stjr { 170128345Stjr /* 171128345Stjr * We've got a metachar, but this shell 172128345Stjr * doesn't support escape chars. Use quotes. 173128345Stjr */ 174128345Stjr use_quotes = 1; 175128345Stjr } else 176128345Stjr { 177128345Stjr /* 178128345Stjr * Allow space for the escape char. 179128345Stjr */ 180128345Stjr len += esclen; 181128345Stjr } 182128345Stjr } 183128345Stjr } 184128345Stjr if (use_quotes) 185128345Stjr { 186128345Stjr if (have_quotes) 187128345Stjr /* 188128345Stjr * We can't quote a string that contains quotes. 189128345Stjr */ 190128345Stjr return (NULL); 191128345Stjr len = strlen(s) + 3; 192128345Stjr } 193128345Stjr /* 194128345Stjr * Allocate and construct the new string. 195128345Stjr */ 196128345Stjr newstr = p = (char *) ecalloc(len, sizeof(char)); 197128345Stjr if (use_quotes) 198128345Stjr { 199161475Sdelphij SNPRINTF3(newstr, len, "%c%s%c", openquote, s, closequote); 200128345Stjr } else 201128345Stjr { 202128345Stjr while (*s != '\0') 203128345Stjr { 204128345Stjr if (metachar(*s)) 205128345Stjr { 206128345Stjr /* 207128345Stjr * Add the escape char. 208128345Stjr */ 209128345Stjr strcpy(p, esc); 210128345Stjr p += esclen; 211128345Stjr } 212128345Stjr *p++ = *s++; 213128345Stjr } 214128345Stjr *p = '\0'; 215128345Stjr } 216128345Stjr return (newstr); 217128345Stjr} 218128345Stjr 219128345Stjr/* 22060786Sps * Return a pathname that points to a specified file in a specified directory. 22160786Sps * Return NULL if the file does not exist in the directory. 22260786Sps */ 22360786Sps static char * 22460786Spsdirfile(dirname, filename) 22560786Sps char *dirname; 22660786Sps char *filename; 22760786Sps{ 22860786Sps char *pathname; 22960786Sps char *qpathname; 230161475Sdelphij int len; 23160786Sps int f; 23260786Sps 23360786Sps if (dirname == NULL || *dirname == '\0') 23460786Sps return (NULL); 23560786Sps /* 23660786Sps * Construct the full pathname. 23760786Sps */ 238161475Sdelphij len= strlen(dirname) + strlen(filename) + 2; 239161475Sdelphij pathname = (char *) calloc(len, sizeof(char)); 24060786Sps if (pathname == NULL) 24160786Sps return (NULL); 242161475Sdelphij SNPRINTF3(pathname, len, "%s%s%s", dirname, PATHNAME_SEP, filename); 24360786Sps /* 24460786Sps * Make sure the file exists. 24560786Sps */ 246128345Stjr qpathname = shell_unquote(pathname); 24760786Sps f = open(qpathname, OPEN_READ); 24860786Sps if (f < 0) 24960786Sps { 25060786Sps free(pathname); 25160786Sps pathname = NULL; 25260786Sps } else 25360786Sps { 25460786Sps close(f); 25560786Sps } 25660786Sps free(qpathname); 25760786Sps return (pathname); 25860786Sps} 25960786Sps 26060786Sps/* 26160786Sps * Return the full pathname of the given file in the "home directory". 26260786Sps */ 26360786Sps public char * 26460786Spshomefile(filename) 26560786Sps char *filename; 26660786Sps{ 26760786Sps register char *pathname; 26860786Sps 26960786Sps /* 27060786Sps * Try $HOME/filename. 27160786Sps */ 27260786Sps pathname = dirfile(lgetenv("HOME"), filename); 27360786Sps if (pathname != NULL) 27460786Sps return (pathname); 27560786Sps#if OS2 27660786Sps /* 27760786Sps * Try $INIT/filename. 27860786Sps */ 27960786Sps pathname = dirfile(lgetenv("INIT"), filename); 28060786Sps if (pathname != NULL) 28160786Sps return (pathname); 28260786Sps#endif 28360786Sps#if MSDOS_COMPILER || OS2 28460786Sps /* 28560786Sps * Look for the file anywhere on search path. 28660786Sps */ 28760786Sps pathname = (char *) calloc(_MAX_PATH, sizeof(char)); 28860786Sps#if MSDOS_COMPILER==DJGPPC 28960786Sps { 29060786Sps char *res = searchpath(filename); 29160786Sps if (res == 0) 29260786Sps *pathname = '\0'; 29360786Sps else 29460786Sps strcpy(pathname, res); 29560786Sps } 29660786Sps#else 29760786Sps _searchenv(filename, "PATH", pathname); 29860786Sps#endif 29960786Sps if (*pathname != '\0') 30060786Sps return (pathname); 30160786Sps free(pathname); 30260786Sps#endif 30360786Sps return (NULL); 30460786Sps} 30560786Sps 30660786Sps/* 30760786Sps * Expand a string, substituting any "%" with the current filename, 30860786Sps * and any "#" with the previous filename. 30960786Sps * But a string of N "%"s is just replaced with N-1 "%"s. 31060786Sps * Likewise for a string of N "#"s. 31160786Sps * {{ This is a lot of work just to support % and #. }} 31260786Sps */ 31360786Sps public char * 31460786Spsfexpand(s) 31560786Sps char *s; 31660786Sps{ 31760786Sps register char *fr, *to; 31860786Sps register int n; 31960786Sps register char *e; 32060786Sps IFILE ifile; 32160786Sps 32260786Sps#define fchar_ifile(c) \ 32360786Sps ((c) == '%' ? curr_ifile : \ 32460786Sps (c) == '#' ? old_ifile : NULL_IFILE) 32560786Sps 32660786Sps /* 32760786Sps * Make one pass to see how big a buffer we 32860786Sps * need to allocate for the expanded string. 32960786Sps */ 33060786Sps n = 0; 33160786Sps for (fr = s; *fr != '\0'; fr++) 33260786Sps { 33360786Sps switch (*fr) 33460786Sps { 33560786Sps case '%': 33660786Sps case '#': 33760786Sps if (fr > s && fr[-1] == *fr) 33860786Sps { 33960786Sps /* 34060786Sps * Second (or later) char in a string 34160786Sps * of identical chars. Treat as normal. 34260786Sps */ 34360786Sps n++; 34460786Sps } else if (fr[1] != *fr) 34560786Sps { 34660786Sps /* 34760786Sps * Single char (not repeated). Treat specially. 34860786Sps */ 34960786Sps ifile = fchar_ifile(*fr); 35060786Sps if (ifile == NULL_IFILE) 35160786Sps n++; 35260786Sps else 35360786Sps n += strlen(get_filename(ifile)); 35460786Sps } 35560786Sps /* 35660786Sps * Else it is the first char in a string of 35760786Sps * identical chars. Just discard it. 35860786Sps */ 35960786Sps break; 36060786Sps default: 36160786Sps n++; 36260786Sps break; 36360786Sps } 36460786Sps } 36560786Sps 36660786Sps e = (char *) ecalloc(n+1, sizeof(char)); 36760786Sps 36860786Sps /* 36960786Sps * Now copy the string, expanding any "%" or "#". 37060786Sps */ 37160786Sps to = e; 37260786Sps for (fr = s; *fr != '\0'; fr++) 37360786Sps { 37460786Sps switch (*fr) 37560786Sps { 37660786Sps case '%': 37760786Sps case '#': 37860786Sps if (fr > s && fr[-1] == *fr) 37960786Sps { 38060786Sps *to++ = *fr; 38160786Sps } else if (fr[1] != *fr) 38260786Sps { 38360786Sps ifile = fchar_ifile(*fr); 38460786Sps if (ifile == NULL_IFILE) 38560786Sps *to++ = *fr; 38660786Sps else 38760786Sps { 38860786Sps strcpy(to, get_filename(ifile)); 38960786Sps to += strlen(to); 39060786Sps } 39160786Sps } 39260786Sps break; 39360786Sps default: 39460786Sps *to++ = *fr; 39560786Sps break; 39660786Sps } 39760786Sps } 39860786Sps *to = '\0'; 39960786Sps return (e); 40060786Sps} 40160786Sps 40260786Sps#if TAB_COMPLETE_FILENAME 40360786Sps 40460786Sps/* 40560786Sps * Return a blank-separated list of filenames which "complete" 40660786Sps * the given string. 40760786Sps */ 40860786Sps public char * 40960786Spsfcomplete(s) 41060786Sps char *s; 41160786Sps{ 41260786Sps char *fpat; 413128345Stjr char *qs; 41460786Sps 41560786Sps if (secure) 41660786Sps return (NULL); 41760786Sps /* 41860786Sps * Complete the filename "s" by globbing "s*". 41960786Sps */ 42060786Sps#if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC) 42160786Sps /* 42260786Sps * But in DOS, we have to glob "s*.*". 42360786Sps * But if the final component of the filename already has 42460786Sps * a dot in it, just do "s*". 42560786Sps * (Thus, "FILE" is globbed as "FILE*.*", 42660786Sps * but "FILE.A" is globbed as "FILE.A*"). 42760786Sps */ 42860786Sps { 42960786Sps char *slash; 430161475Sdelphij int len; 43160786Sps for (slash = s+strlen(s)-1; slash > s; slash--) 43260786Sps if (*slash == *PATHNAME_SEP || *slash == '/') 43360786Sps break; 434161475Sdelphij len = strlen(s) + 4; 435161475Sdelphij fpat = (char *) ecalloc(len, sizeof(char)); 43660786Sps if (strchr(slash, '.') == NULL) 437161475Sdelphij SNPRINTF1(fpat, len, "%s*.*", s); 43860786Sps else 439161475Sdelphij SNPRINTF1(fpat, len, "%s*", s); 44060786Sps } 44160786Sps#else 442161475Sdelphij { 443161475Sdelphij int len = strlen(s) + 2; 444161475Sdelphij fpat = (char *) ecalloc(len, sizeof(char)); 445161475Sdelphij SNPRINTF1(fpat, len, "%s*", s); 446161475Sdelphij } 44760786Sps#endif 448128345Stjr qs = lglob(fpat); 449128345Stjr s = shell_unquote(qs); 45060786Sps if (strcmp(s,fpat) == 0) 45160786Sps { 45260786Sps /* 45360786Sps * The filename didn't expand. 45460786Sps */ 455128345Stjr free(qs); 456128345Stjr qs = NULL; 45760786Sps } 458128345Stjr free(s); 45960786Sps free(fpat); 460128345Stjr return (qs); 46160786Sps} 46260786Sps#endif 46360786Sps 46460786Sps/* 46560786Sps * Try to determine if a file is "binary". 46660786Sps * This is just a guess, and we need not try too hard to make it accurate. 46760786Sps */ 46860786Sps public int 46960786Spsbin_file(f) 47060786Sps int f; 47160786Sps{ 47260786Sps int i; 47360786Sps int n; 474170256Sdelphij int bin_count = 0; 475170256Sdelphij unsigned char data[256]; 47660786Sps 47760786Sps if (!seekable(f)) 47860786Sps return (0); 47960786Sps if (lseek(f, (off_t)0, 0) == BAD_LSEEK) 48060786Sps return (0); 48160786Sps n = read(f, data, sizeof(data)); 48260786Sps for (i = 0; i < n; i++) 483170256Sdelphij { 484170256Sdelphij char c = data[i]; 485170256Sdelphij if (ctldisp == OPT_ONPLUS && c == ESC) 486170256Sdelphij { 487170256Sdelphij while (++i < n && is_ansi_middle(data[i])) 488170256Sdelphij continue; 489170256Sdelphij } else if (binary_char(c)) 490170256Sdelphij bin_count++; 491170256Sdelphij } 492170256Sdelphij /* 493170256Sdelphij * Call it a binary file if there are more than 5 binary characters 494170256Sdelphij * in the first 256 bytes of the file. 495170256Sdelphij */ 496170256Sdelphij return (bin_count > 5); 49760786Sps} 49860786Sps 49960786Sps/* 50060786Sps * Try to determine the size of a file by seeking to the end. 50160786Sps */ 50260786Sps static POSITION 50360786Spsseek_filesize(f) 50460786Sps int f; 50560786Sps{ 50660786Sps off_t spos; 50760786Sps 50860786Sps spos = lseek(f, (off_t)0, 2); 50960786Sps if (spos == BAD_LSEEK) 51060786Sps return (NULL_POSITION); 51160786Sps return ((POSITION) spos); 51260786Sps} 51360786Sps 51460786Sps/* 51560786Sps * Read a string from a file. 51660786Sps * Return a pointer to the string in memory. 51760786Sps */ 51860786Sps static char * 51960786Spsreadfd(fd) 52060786Sps FILE *fd; 52160786Sps{ 52260786Sps int len; 52360786Sps int ch; 52460786Sps char *buf; 52560786Sps char *p; 52660786Sps 52760786Sps /* 52860786Sps * Make a guess about how many chars in the string 52960786Sps * and allocate a buffer to hold it. 53060786Sps */ 53160786Sps len = 100; 53260786Sps buf = (char *) ecalloc(len, sizeof(char)); 53360786Sps for (p = buf; ; p++) 53460786Sps { 53560786Sps if ((ch = getc(fd)) == '\n' || ch == EOF) 53660786Sps break; 53760786Sps if (p - buf >= len-1) 53860786Sps { 53960786Sps /* 54060786Sps * The string is too big to fit in the buffer we have. 54160786Sps * Allocate a new buffer, twice as big. 54260786Sps */ 54360786Sps len *= 2; 54460786Sps *p = '\0'; 54560786Sps p = (char *) ecalloc(len, sizeof(char)); 54660786Sps strcpy(p, buf); 54760786Sps free(buf); 54860786Sps buf = p; 54960786Sps p = buf + strlen(buf); 55060786Sps } 55160786Sps *p = ch; 55260786Sps } 55360786Sps *p = '\0'; 55460786Sps return (buf); 55560786Sps} 55660786Sps 55760786Sps 55860786Sps 55960786Sps#if HAVE_POPEN 56060786Sps 56160786SpsFILE *popen(); 56260786Sps 56360786Sps/* 56460786Sps * Execute a shell command. 56560786Sps * Return a pointer to a pipe connected to the shell command's standard output. 56660786Sps */ 56760786Sps static FILE * 56860786Spsshellcmd(cmd) 56960786Sps char *cmd; 57060786Sps{ 57160786Sps FILE *fd; 57260786Sps 57360786Sps#if HAVE_SHELL 57460786Sps char *shell; 57560786Sps 57660786Sps shell = lgetenv("SHELL"); 57760786Sps if (shell != NULL && *shell != '\0') 57860786Sps { 57960786Sps char *scmd; 58060786Sps char *esccmd; 58160786Sps 58260786Sps /* 583128345Stjr * Read the output of <$SHELL -c cmd>. 584128345Stjr * Escape any metacharacters in the command. 58560786Sps */ 586128345Stjr esccmd = shell_quote(cmd); 587128345Stjr if (esccmd == NULL) 58860786Sps { 589128345Stjr fd = popen(cmd, "r"); 59060786Sps } else 59160786Sps { 592161475Sdelphij int len = strlen(shell) + strlen(esccmd) + 5; 593161475Sdelphij scmd = (char *) ecalloc(len, sizeof(char)); 594161475Sdelphij SNPRINTF3(scmd, len, "%s %s %s", shell, shell_coption(), esccmd); 59560786Sps free(esccmd); 596128345Stjr fd = popen(scmd, "r"); 597128345Stjr free(scmd); 59860786Sps } 59960786Sps } else 60060786Sps#endif 60160786Sps { 60260786Sps fd = popen(cmd, "r"); 60360786Sps } 604128345Stjr /* 605128345Stjr * Redirection in `popen' might have messed with the 606128345Stjr * standard devices. Restore binary input mode. 607128345Stjr */ 608128345Stjr SET_BINARY(0); 60960786Sps return (fd); 61060786Sps} 61160786Sps 61260786Sps#endif /* HAVE_POPEN */ 61360786Sps 61460786Sps 61560786Sps/* 61660786Sps * Expand a filename, doing any system-specific metacharacter substitutions. 61760786Sps */ 61860786Sps public char * 61960786Spslglob(filename) 62060786Sps char *filename; 62160786Sps{ 62260786Sps char *gfilename; 62360786Sps char *ofilename; 62460786Sps 62560786Sps ofilename = fexpand(filename); 62660786Sps if (secure) 62760786Sps return (ofilename); 628128345Stjr filename = shell_unquote(ofilename); 62960786Sps 63060786Sps#ifdef DECL_GLOB_LIST 63160786Sps{ 63260786Sps /* 63360786Sps * The globbing function returns a list of names. 63460786Sps */ 63560786Sps int length; 63660786Sps char *p; 637128345Stjr char *qfilename; 63860786Sps DECL_GLOB_LIST(list) 63960786Sps 64060786Sps GLOB_LIST(filename, list); 64160786Sps if (GLOB_LIST_FAILED(list)) 64260786Sps { 64360786Sps free(filename); 64460786Sps return (ofilename); 64560786Sps } 64660786Sps length = 1; /* Room for trailing null byte */ 64760786Sps for (SCAN_GLOB_LIST(list, p)) 64860786Sps { 64960786Sps INIT_GLOB_LIST(list, p); 650128345Stjr qfilename = shell_quote(p); 651128345Stjr if (qfilename != NULL) 652128345Stjr { 653128345Stjr length += strlen(qfilename) + 1; 654128345Stjr free(qfilename); 655128345Stjr } 65660786Sps } 65760786Sps gfilename = (char *) ecalloc(length, sizeof(char)); 65860786Sps for (SCAN_GLOB_LIST(list, p)) 65960786Sps { 66060786Sps INIT_GLOB_LIST(list, p); 661128345Stjr qfilename = shell_quote(p); 662128345Stjr if (qfilename != NULL) 663128345Stjr { 664128345Stjr sprintf(gfilename + strlen(gfilename), "%s ", qfilename); 665128345Stjr free(qfilename); 666128345Stjr } 66760786Sps } 66860786Sps /* 66960786Sps * Overwrite the final trailing space with a null terminator. 67060786Sps */ 67160786Sps *--p = '\0'; 67260786Sps GLOB_LIST_DONE(list); 67360786Sps} 67460786Sps#else 67560786Sps#ifdef DECL_GLOB_NAME 67660786Sps{ 67760786Sps /* 67860786Sps * The globbing function returns a single name, and 67960786Sps * is called multiple times to walk thru all names. 68060786Sps */ 68160786Sps register char *p; 68260786Sps register int len; 68360786Sps register int n; 684128345Stjr char *pathname; 685128345Stjr char *qpathname; 68660786Sps DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) 68760786Sps 68860786Sps GLOB_FIRST_NAME(filename, &fnd, handle); 68960786Sps if (GLOB_FIRST_FAILED(handle)) 69060786Sps { 69160786Sps free(filename); 69260786Sps return (ofilename); 69360786Sps } 69460786Sps 69560786Sps _splitpath(filename, drive, dir, fname, ext); 69660786Sps len = 100; 69760786Sps gfilename = (char *) ecalloc(len, sizeof(char)); 69860786Sps p = gfilename; 69960786Sps do { 70060786Sps n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1; 701128345Stjr pathname = (char *) ecalloc(n, sizeof(char)); 702161475Sdelphij SNPRINTF3(pathname, n, "%s%s%s", drive, dir, fnd.GLOB_NAME); 703128345Stjr qpathname = shell_quote(pathname); 704128345Stjr free(pathname); 705128345Stjr if (qpathname != NULL) 70660786Sps { 707128345Stjr n = strlen(qpathname); 708128345Stjr while (p - gfilename + n + 2 >= len) 709128345Stjr { 710128345Stjr /* 711128345Stjr * No room in current buffer. 712128345Stjr * Allocate a bigger one. 713128345Stjr */ 714128345Stjr len *= 2; 715128345Stjr *p = '\0'; 716128345Stjr p = (char *) ecalloc(len, sizeof(char)); 717128345Stjr strcpy(p, gfilename); 718128345Stjr free(gfilename); 719128345Stjr gfilename = p; 720128345Stjr p = gfilename + strlen(gfilename); 721128345Stjr } 722128345Stjr strcpy(p, qpathname); 723128345Stjr free(qpathname); 724128345Stjr p += n; 725128345Stjr *p++ = ' '; 72660786Sps } 72760786Sps } while (GLOB_NEXT_NAME(handle, &fnd) == 0); 72860786Sps 72960786Sps /* 73060786Sps * Overwrite the final trailing space with a null terminator. 73160786Sps */ 73260786Sps *--p = '\0'; 73360786Sps GLOB_NAME_DONE(handle); 73460786Sps} 73560786Sps#else 73660786Sps#if HAVE_POPEN 73760786Sps{ 73860786Sps /* 73960786Sps * We get the shell to glob the filename for us by passing 74060786Sps * an "echo" command to the shell and reading its output. 74160786Sps */ 74260786Sps FILE *fd; 74360786Sps char *s; 74460786Sps char *lessecho; 74560786Sps char *cmd; 746128345Stjr char *esc; 747161475Sdelphij int len; 74860786Sps 749128345Stjr esc = get_meta_escape(); 750128345Stjr if (strlen(esc) == 0) 751128345Stjr esc = "-"; 752128345Stjr esc = shell_quote(esc); 753128345Stjr if (esc == NULL) 75460786Sps { 75560786Sps free(filename); 75660786Sps return (ofilename); 75760786Sps } 758128345Stjr lessecho = lgetenv("LESSECHO"); 759128345Stjr if (lessecho == NULL || *lessecho == '\0') 760128345Stjr lessecho = "lessecho"; 76160786Sps /* 76260786Sps * Invoke lessecho, and read its output (a globbed list of filenames). 76360786Sps */ 764161475Sdelphij len = strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24; 765161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 766161475Sdelphij SNPRINTF4(cmd, len, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote, closequote, esc); 767128345Stjr free(esc); 768128345Stjr for (s = metachars(); *s != '\0'; s++) 769128345Stjr sprintf(cmd + strlen(cmd), "-n0x%x ", *s); 770128345Stjr sprintf(cmd + strlen(cmd), "-- %s", ofilename); 77160786Sps fd = shellcmd(cmd); 77260786Sps free(cmd); 77360786Sps if (fd == NULL) 77460786Sps { 77560786Sps /* 77660786Sps * Cannot create the pipe. 77760786Sps * Just return the original (fexpanded) filename. 77860786Sps */ 77960786Sps free(filename); 78060786Sps return (ofilename); 78160786Sps } 78260786Sps gfilename = readfd(fd); 78360786Sps pclose(fd); 78460786Sps if (*gfilename == '\0') 78560786Sps { 78660786Sps free(gfilename); 78760786Sps free(filename); 78860786Sps return (ofilename); 78960786Sps } 79060786Sps} 79160786Sps#else 79260786Sps /* 79360786Sps * No globbing functions at all. Just use the fexpanded filename. 79460786Sps */ 79560786Sps gfilename = save(filename); 79660786Sps#endif 79760786Sps#endif 79860786Sps#endif 79960786Sps free(filename); 80060786Sps free(ofilename); 80160786Sps return (gfilename); 80260786Sps} 80360786Sps 80460786Sps/* 80560786Sps * See if we should open a "replacement file" 80660786Sps * instead of the file we're about to open. 80760786Sps */ 80860786Sps public char * 80960786Spsopen_altfile(filename, pf, pfd) 81060786Sps char *filename; 81160786Sps int *pf; 81260786Sps void **pfd; 81360786Sps{ 81460786Sps#if !HAVE_POPEN 81560786Sps return (NULL); 81660786Sps#else 81760786Sps char *lessopen; 81860786Sps char *cmd; 819161475Sdelphij int len; 82060786Sps FILE *fd; 82160786Sps#if HAVE_FILENO 82260786Sps int returnfd = 0; 82360786Sps#endif 82460786Sps 825128345Stjr if (!use_lessopen || secure) 82660786Sps return (NULL); 82760786Sps ch_ungetchar(-1); 82860786Sps if ((lessopen = lgetenv("LESSOPEN")) == NULL) 82960786Sps return (NULL); 83060786Sps if (strcmp(filename, "-") == 0) 83160786Sps return (NULL); 83260786Sps if (*lessopen == '|') 83360786Sps { 83460786Sps /* 83560786Sps * If LESSOPEN starts with a |, it indicates 83660786Sps * a "pipe preprocessor". 83760786Sps */ 83860786Sps#if HAVE_FILENO 83960786Sps lessopen++; 84060786Sps returnfd = 1; 84160786Sps#else 84260786Sps error("LESSOPEN pipe is not supported", NULL_PARG); 84360786Sps return (NULL); 84460786Sps#endif 84560786Sps } 84660786Sps 847161475Sdelphij len = strlen(lessopen) + strlen(filename) + 2; 848161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 849161475Sdelphij SNPRINTF1(cmd, len, lessopen, filename); 85060786Sps fd = shellcmd(cmd); 85160786Sps free(cmd); 85260786Sps if (fd == NULL) 85360786Sps { 85460786Sps /* 85560786Sps * Cannot create the pipe. 85660786Sps */ 85760786Sps return (NULL); 85860786Sps } 85960786Sps#if HAVE_FILENO 86060786Sps if (returnfd) 86160786Sps { 86260786Sps int f; 86360786Sps char c; 86460786Sps 86560786Sps /* 86660786Sps * Read one char to see if the pipe will produce any data. 86760786Sps * If it does, push the char back on the pipe. 86860786Sps */ 86960786Sps f = fileno(fd); 87060786Sps SET_BINARY(f); 87160786Sps if (read(f, &c, 1) != 1) 87260786Sps { 87360786Sps /* 87460786Sps * Pipe is empty. This means there is no alt file. 87560786Sps */ 87660786Sps pclose(fd); 87760786Sps return (NULL); 87860786Sps } 87960786Sps ch_ungetchar(c); 88060786Sps *pfd = (void *) fd; 88160786Sps *pf = f; 88260786Sps return (save("-")); 88360786Sps } 88460786Sps#endif 885128345Stjr cmd = readfd(fd); 88660786Sps pclose(fd); 887128345Stjr if (*cmd == '\0') 88860786Sps /* 88960786Sps * Pipe is empty. This means there is no alt file. 89060786Sps */ 89160786Sps return (NULL); 892128345Stjr return (cmd); 89360786Sps#endif /* HAVE_POPEN */ 89460786Sps} 89560786Sps 89660786Sps/* 89760786Sps * Close a replacement file. 89860786Sps */ 89960786Sps public void 90060786Spsclose_altfile(altfilename, filename, pipefd) 90160786Sps char *altfilename; 90260786Sps char *filename; 90360786Sps void *pipefd; 90460786Sps{ 90560786Sps#if HAVE_POPEN 90660786Sps char *lessclose; 90760786Sps FILE *fd; 90860786Sps char *cmd; 909161475Sdelphij int len; 91060786Sps 91160786Sps if (secure) 91260786Sps return; 91360786Sps if (pipefd != NULL) 91489019Sps { 91589019Sps#if OS2 91689019Sps /* 91789019Sps * The pclose function of OS/2 emx sometimes fails. 91889019Sps * Send SIGINT to the piped process before closing it. 91989019Sps */ 92089019Sps kill(((FILE*)pipefd)->_pid, SIGINT); 92189019Sps#endif 92260786Sps pclose((FILE*) pipefd); 92389019Sps } 92460786Sps if ((lessclose = lgetenv("LESSCLOSE")) == NULL) 92560786Sps return; 926161475Sdelphij len = strlen(lessclose) + strlen(filename) + strlen(altfilename) + 2; 927161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 928161475Sdelphij SNPRINTF2(cmd, len, lessclose, filename, altfilename); 92960786Sps fd = shellcmd(cmd); 93060786Sps free(cmd); 93160786Sps if (fd != NULL) 93260786Sps pclose(fd); 93360786Sps#endif 93460786Sps} 93560786Sps 93660786Sps/* 93760786Sps * Is the specified file a directory? 93860786Sps */ 93960786Sps public int 94060786Spsis_dir(filename) 94160786Sps char *filename; 94260786Sps{ 94360786Sps int isdir = 0; 94460786Sps 945128345Stjr filename = shell_unquote(filename); 94660786Sps#if HAVE_STAT 94760786Sps{ 94860786Sps int r; 94960786Sps struct stat statbuf; 95060786Sps 95160786Sps r = stat(filename, &statbuf); 95260786Sps isdir = (r >= 0 && S_ISDIR(statbuf.st_mode)); 95360786Sps} 95460786Sps#else 95560786Sps#ifdef _OSK 95660786Sps{ 95760786Sps register int f; 95860786Sps 95960786Sps f = open(filename, S_IREAD | S_IFDIR); 96060786Sps if (f >= 0) 96160786Sps close(f); 96260786Sps isdir = (f >= 0); 96360786Sps} 96460786Sps#endif 96560786Sps#endif 96660786Sps free(filename); 96760786Sps return (isdir); 96860786Sps} 96960786Sps 97060786Sps/* 97160786Sps * Returns NULL if the file can be opened and 97260786Sps * is an ordinary file, otherwise an error message 97360786Sps * (if it cannot be opened or is a directory, etc.) 97460786Sps */ 97560786Sps public char * 97660786Spsbad_file(filename) 97760786Sps char *filename; 97860786Sps{ 97960786Sps register char *m = NULL; 98060786Sps 981128345Stjr filename = shell_unquote(filename); 982170256Sdelphij if (!force_open && is_dir(filename)) 98360786Sps { 984128345Stjr static char is_a_dir[] = " is a directory"; 98560786Sps 986128345Stjr m = (char *) ecalloc(strlen(filename) + sizeof(is_a_dir), 98760786Sps sizeof(char)); 98860786Sps strcpy(m, filename); 989128345Stjr strcat(m, is_a_dir); 99060786Sps } else 99160786Sps { 99260786Sps#if HAVE_STAT 99360786Sps int r; 99460786Sps struct stat statbuf; 99560786Sps 99660786Sps r = stat(filename, &statbuf); 99760786Sps if (r < 0) 99860786Sps { 99960786Sps m = errno_message(filename); 100060786Sps } else if (force_open) 100160786Sps { 100260786Sps m = NULL; 100360786Sps } else if (!S_ISREG(statbuf.st_mode)) 100460786Sps { 100560786Sps static char not_reg[] = " is not a regular file (use -f to see it)"; 100660786Sps m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 100760786Sps sizeof(char)); 100860786Sps strcpy(m, filename); 100960786Sps strcat(m, not_reg); 101060786Sps } 101160786Sps#endif 101260786Sps } 101360786Sps free(filename); 101460786Sps return (m); 101560786Sps} 101660786Sps 101760786Sps/* 101860786Sps * Return the size of a file, as cheaply as possible. 101960786Sps * In Unix, we can stat the file. 102060786Sps */ 102160786Sps public POSITION 102260786Spsfilesize(f) 102360786Sps int f; 102460786Sps{ 102560786Sps#if HAVE_STAT 102660786Sps struct stat statbuf; 102760786Sps 102860786Sps if (fstat(f, &statbuf) >= 0) 102960786Sps return ((POSITION) statbuf.st_size); 103060786Sps#else 103160786Sps#ifdef _OSK 103260786Sps long size; 103360786Sps 103460786Sps if ((size = (long) _gs_size(f)) >= 0) 103560786Sps return ((POSITION) size); 103660786Sps#endif 103760786Sps#endif 103860786Sps return (seek_filesize(f)); 103960786Sps} 104060786Sps 1041128345Stjr/* 1042128345Stjr * 1043128345Stjr */ 1044128345Stjr public char * 1045128345Stjrshell_coption() 1046128345Stjr{ 1047128345Stjr return ("-c"); 1048128345Stjr} 1049