filename.c revision 195941
160786Sps/* 2195941Sdelphij * Copyright (C) 1984-2009 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; 55191930Sdelphijextern int utf_mode; 5660786Spsextern IFILE curr_ifile; 5760786Spsextern IFILE old_ifile; 5860786Sps#if SPACES_IN_FILENAMES 5960786Spsextern char openquote; 6060786Spsextern char closequote; 6160786Sps#endif 6260786Sps 6360786Sps/* 6460786Sps * Remove quotes around a filename. 6560786Sps */ 6660786Sps public char * 67128345Stjrshell_unquote(str) 6860786Sps char *str; 6960786Sps{ 7060786Sps char *name; 7160786Sps char *p; 7260786Sps 73128345Stjr name = p = (char *) ecalloc(strlen(str)+1, sizeof(char)); 74128345Stjr if (*str == openquote) 75128345Stjr { 76128345Stjr str++; 77128345Stjr while (*str != '\0') 78128345Stjr { 79128345Stjr if (*str == closequote) 80128345Stjr { 81128345Stjr if (str[1] != closequote) 82128345Stjr break; 83128345Stjr str++; 84128345Stjr } 85128345Stjr *p++ = *str++; 86128345Stjr } 87128345Stjr } else 88128345Stjr { 89128345Stjr char *esc = get_meta_escape(); 90128345Stjr int esclen = strlen(esc); 91128345Stjr while (*str != '\0') 92128345Stjr { 93128345Stjr if (esclen > 0 && strncmp(str, esc, esclen) == 0) 94128345Stjr str += esclen; 95128345Stjr *p++ = *str++; 96128345Stjr } 97128345Stjr } 98128345Stjr *p = '\0'; 9960786Sps return (name); 10060786Sps} 10160786Sps 10260786Sps/* 103128345Stjr * Get the shell's escape character. 104128345Stjr */ 105128345Stjr public char * 106128345Stjrget_meta_escape() 107128345Stjr{ 108128345Stjr char *s; 109128345Stjr 110128345Stjr s = lgetenv("LESSMETAESCAPE"); 111128345Stjr if (s == NULL) 112128345Stjr s = DEF_METAESCAPE; 113128345Stjr return (s); 114128345Stjr} 115128345Stjr 116128345Stjr/* 117128345Stjr * Get the characters which the shell considers to be "metacharacters". 118128345Stjr */ 119128345Stjr static char * 120128345Stjrmetachars() 121128345Stjr{ 122128345Stjr static char *mchars = NULL; 123128345Stjr 124128345Stjr if (mchars == NULL) 125128345Stjr { 126128345Stjr mchars = lgetenv("LESSMETACHARS"); 127128345Stjr if (mchars == NULL) 128128345Stjr mchars = DEF_METACHARS; 129128345Stjr } 130128345Stjr return (mchars); 131128345Stjr} 132128345Stjr 133128345Stjr/* 134128345Stjr * Is this a shell metacharacter? 135128345Stjr */ 136128345Stjr static int 137128345Stjrmetachar(c) 138128345Stjr char c; 139128345Stjr{ 140128345Stjr return (strchr(metachars(), c) != NULL); 141128345Stjr} 142128345Stjr 143128345Stjr/* 144128345Stjr * Insert a backslash before each metacharacter in a string. 145128345Stjr */ 146128345Stjr public char * 147128345Stjrshell_quote(s) 148128345Stjr char *s; 149128345Stjr{ 150128345Stjr char *p; 151128345Stjr char *newstr; 152128345Stjr int len; 153128345Stjr char *esc = get_meta_escape(); 154128345Stjr int esclen = strlen(esc); 155128345Stjr int use_quotes = 0; 156128345Stjr int have_quotes = 0; 157128345Stjr 158128345Stjr /* 159128345Stjr * Determine how big a string we need to allocate. 160128345Stjr */ 161128345Stjr len = 1; /* Trailing null byte */ 162128345Stjr for (p = s; *p != '\0'; p++) 163128345Stjr { 164128345Stjr len++; 165128345Stjr if (*p == openquote || *p == closequote) 166128345Stjr have_quotes = 1; 167128345Stjr if (metachar(*p)) 168128345Stjr { 169128345Stjr if (esclen == 0) 170128345Stjr { 171128345Stjr /* 172128345Stjr * We've got a metachar, but this shell 173128345Stjr * doesn't support escape chars. Use quotes. 174128345Stjr */ 175128345Stjr use_quotes = 1; 176128345Stjr } else 177128345Stjr { 178128345Stjr /* 179128345Stjr * Allow space for the escape char. 180128345Stjr */ 181128345Stjr len += esclen; 182128345Stjr } 183128345Stjr } 184128345Stjr } 185128345Stjr if (use_quotes) 186128345Stjr { 187128345Stjr if (have_quotes) 188128345Stjr /* 189128345Stjr * We can't quote a string that contains quotes. 190128345Stjr */ 191128345Stjr return (NULL); 192128345Stjr len = strlen(s) + 3; 193128345Stjr } 194128345Stjr /* 195128345Stjr * Allocate and construct the new string. 196128345Stjr */ 197128345Stjr newstr = p = (char *) ecalloc(len, sizeof(char)); 198128345Stjr if (use_quotes) 199128345Stjr { 200161475Sdelphij SNPRINTF3(newstr, len, "%c%s%c", openquote, s, closequote); 201128345Stjr } else 202128345Stjr { 203128345Stjr while (*s != '\0') 204128345Stjr { 205128345Stjr if (metachar(*s)) 206128345Stjr { 207128345Stjr /* 208128345Stjr * Add the escape char. 209128345Stjr */ 210128345Stjr strcpy(p, esc); 211128345Stjr p += esclen; 212128345Stjr } 213128345Stjr *p++ = *s++; 214128345Stjr } 215128345Stjr *p = '\0'; 216128345Stjr } 217128345Stjr return (newstr); 218128345Stjr} 219128345Stjr 220128345Stjr/* 22160786Sps * Return a pathname that points to a specified file in a specified directory. 22260786Sps * Return NULL if the file does not exist in the directory. 22360786Sps */ 22460786Sps static char * 22560786Spsdirfile(dirname, filename) 22660786Sps char *dirname; 22760786Sps char *filename; 22860786Sps{ 22960786Sps char *pathname; 23060786Sps char *qpathname; 231161475Sdelphij int len; 23260786Sps int f; 23360786Sps 23460786Sps if (dirname == NULL || *dirname == '\0') 23560786Sps return (NULL); 23660786Sps /* 23760786Sps * Construct the full pathname. 23860786Sps */ 239161475Sdelphij len= strlen(dirname) + strlen(filename) + 2; 240161475Sdelphij pathname = (char *) calloc(len, sizeof(char)); 24160786Sps if (pathname == NULL) 24260786Sps return (NULL); 243161475Sdelphij SNPRINTF3(pathname, len, "%s%s%s", dirname, PATHNAME_SEP, filename); 24460786Sps /* 24560786Sps * Make sure the file exists. 24660786Sps */ 247128345Stjr qpathname = shell_unquote(pathname); 24860786Sps f = open(qpathname, OPEN_READ); 24960786Sps if (f < 0) 25060786Sps { 25160786Sps free(pathname); 25260786Sps pathname = NULL; 25360786Sps } else 25460786Sps { 25560786Sps close(f); 25660786Sps } 25760786Sps free(qpathname); 25860786Sps return (pathname); 25960786Sps} 26060786Sps 26160786Sps/* 26260786Sps * Return the full pathname of the given file in the "home directory". 26360786Sps */ 26460786Sps public char * 26560786Spshomefile(filename) 26660786Sps char *filename; 26760786Sps{ 26860786Sps register char *pathname; 26960786Sps 27060786Sps /* 27160786Sps * Try $HOME/filename. 27260786Sps */ 27360786Sps pathname = dirfile(lgetenv("HOME"), filename); 27460786Sps if (pathname != NULL) 27560786Sps return (pathname); 27660786Sps#if OS2 27760786Sps /* 27860786Sps * Try $INIT/filename. 27960786Sps */ 28060786Sps pathname = dirfile(lgetenv("INIT"), filename); 28160786Sps if (pathname != NULL) 28260786Sps return (pathname); 28360786Sps#endif 28460786Sps#if MSDOS_COMPILER || OS2 28560786Sps /* 28660786Sps * Look for the file anywhere on search path. 28760786Sps */ 28860786Sps pathname = (char *) calloc(_MAX_PATH, sizeof(char)); 28960786Sps#if MSDOS_COMPILER==DJGPPC 29060786Sps { 29160786Sps char *res = searchpath(filename); 29260786Sps if (res == 0) 29360786Sps *pathname = '\0'; 29460786Sps else 29560786Sps strcpy(pathname, res); 29660786Sps } 29760786Sps#else 29860786Sps _searchenv(filename, "PATH", pathname); 29960786Sps#endif 30060786Sps if (*pathname != '\0') 30160786Sps return (pathname); 30260786Sps free(pathname); 30360786Sps#endif 30460786Sps return (NULL); 30560786Sps} 30660786Sps 30760786Sps/* 30860786Sps * Expand a string, substituting any "%" with the current filename, 30960786Sps * and any "#" with the previous filename. 31060786Sps * But a string of N "%"s is just replaced with N-1 "%"s. 31160786Sps * Likewise for a string of N "#"s. 31260786Sps * {{ This is a lot of work just to support % and #. }} 31360786Sps */ 31460786Sps public char * 31560786Spsfexpand(s) 31660786Sps char *s; 31760786Sps{ 31860786Sps register char *fr, *to; 31960786Sps register int n; 32060786Sps register char *e; 32160786Sps IFILE ifile; 32260786Sps 32360786Sps#define fchar_ifile(c) \ 32460786Sps ((c) == '%' ? curr_ifile : \ 32560786Sps (c) == '#' ? old_ifile : NULL_IFILE) 32660786Sps 32760786Sps /* 32860786Sps * Make one pass to see how big a buffer we 32960786Sps * need to allocate for the expanded string. 33060786Sps */ 33160786Sps n = 0; 33260786Sps for (fr = s; *fr != '\0'; fr++) 33360786Sps { 33460786Sps switch (*fr) 33560786Sps { 33660786Sps case '%': 33760786Sps case '#': 33860786Sps if (fr > s && fr[-1] == *fr) 33960786Sps { 34060786Sps /* 34160786Sps * Second (or later) char in a string 34260786Sps * of identical chars. Treat as normal. 34360786Sps */ 34460786Sps n++; 34560786Sps } else if (fr[1] != *fr) 34660786Sps { 34760786Sps /* 34860786Sps * Single char (not repeated). Treat specially. 34960786Sps */ 35060786Sps ifile = fchar_ifile(*fr); 35160786Sps if (ifile == NULL_IFILE) 35260786Sps n++; 35360786Sps else 35460786Sps n += strlen(get_filename(ifile)); 35560786Sps } 35660786Sps /* 35760786Sps * Else it is the first char in a string of 35860786Sps * identical chars. Just discard it. 35960786Sps */ 36060786Sps break; 36160786Sps default: 36260786Sps n++; 36360786Sps break; 36460786Sps } 36560786Sps } 36660786Sps 36760786Sps e = (char *) ecalloc(n+1, sizeof(char)); 36860786Sps 36960786Sps /* 37060786Sps * Now copy the string, expanding any "%" or "#". 37160786Sps */ 37260786Sps to = e; 37360786Sps for (fr = s; *fr != '\0'; fr++) 37460786Sps { 37560786Sps switch (*fr) 37660786Sps { 37760786Sps case '%': 37860786Sps case '#': 37960786Sps if (fr > s && fr[-1] == *fr) 38060786Sps { 38160786Sps *to++ = *fr; 38260786Sps } else if (fr[1] != *fr) 38360786Sps { 38460786Sps ifile = fchar_ifile(*fr); 38560786Sps if (ifile == NULL_IFILE) 38660786Sps *to++ = *fr; 38760786Sps else 38860786Sps { 38960786Sps strcpy(to, get_filename(ifile)); 39060786Sps to += strlen(to); 39160786Sps } 39260786Sps } 39360786Sps break; 39460786Sps default: 39560786Sps *to++ = *fr; 39660786Sps break; 39760786Sps } 39860786Sps } 39960786Sps *to = '\0'; 40060786Sps return (e); 40160786Sps} 40260786Sps 40360786Sps#if TAB_COMPLETE_FILENAME 40460786Sps 40560786Sps/* 40660786Sps * Return a blank-separated list of filenames which "complete" 40760786Sps * the given string. 40860786Sps */ 40960786Sps public char * 41060786Spsfcomplete(s) 41160786Sps char *s; 41260786Sps{ 41360786Sps char *fpat; 414128345Stjr char *qs; 41560786Sps 41660786Sps if (secure) 41760786Sps return (NULL); 41860786Sps /* 41960786Sps * Complete the filename "s" by globbing "s*". 42060786Sps */ 42160786Sps#if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC) 42260786Sps /* 42360786Sps * But in DOS, we have to glob "s*.*". 42460786Sps * But if the final component of the filename already has 42560786Sps * a dot in it, just do "s*". 42660786Sps * (Thus, "FILE" is globbed as "FILE*.*", 42760786Sps * but "FILE.A" is globbed as "FILE.A*"). 42860786Sps */ 42960786Sps { 43060786Sps char *slash; 431161475Sdelphij int len; 43260786Sps for (slash = s+strlen(s)-1; slash > s; slash--) 43360786Sps if (*slash == *PATHNAME_SEP || *slash == '/') 43460786Sps break; 435161475Sdelphij len = strlen(s) + 4; 436161475Sdelphij fpat = (char *) ecalloc(len, sizeof(char)); 43760786Sps if (strchr(slash, '.') == NULL) 438161475Sdelphij SNPRINTF1(fpat, len, "%s*.*", s); 43960786Sps else 440161475Sdelphij SNPRINTF1(fpat, len, "%s*", s); 44160786Sps } 44260786Sps#else 443161475Sdelphij { 444161475Sdelphij int len = strlen(s) + 2; 445161475Sdelphij fpat = (char *) ecalloc(len, sizeof(char)); 446161475Sdelphij SNPRINTF1(fpat, len, "%s*", s); 447161475Sdelphij } 44860786Sps#endif 449128345Stjr qs = lglob(fpat); 450128345Stjr s = shell_unquote(qs); 45160786Sps if (strcmp(s,fpat) == 0) 45260786Sps { 45360786Sps /* 45460786Sps * The filename didn't expand. 45560786Sps */ 456128345Stjr free(qs); 457128345Stjr qs = NULL; 45860786Sps } 459128345Stjr free(s); 46060786Sps free(fpat); 461128345Stjr return (qs); 46260786Sps} 46360786Sps#endif 46460786Sps 46560786Sps/* 46660786Sps * Try to determine if a file is "binary". 46760786Sps * This is just a guess, and we need not try too hard to make it accurate. 46860786Sps */ 46960786Sps public int 47060786Spsbin_file(f) 47160786Sps int f; 47260786Sps{ 47360786Sps int n; 474170256Sdelphij int bin_count = 0; 475191930Sdelphij char data[256]; 476191930Sdelphij char* p; 477191930Sdelphij char* pend; 47860786Sps 47960786Sps if (!seekable(f)) 48060786Sps return (0); 481173682Sdelphij if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK) 48260786Sps return (0); 48360786Sps n = read(f, data, sizeof(data)); 484191930Sdelphij pend = &data[n]; 485191930Sdelphij for (p = data; p < pend; ) 486170256Sdelphij { 487191930Sdelphij LWCHAR c = step_char(&p, +1, pend); 488172468Sdelphij if (ctldisp == OPT_ONPLUS && IS_CSI_START(c)) 489170256Sdelphij { 490191930Sdelphij do { 491191930Sdelphij c = step_char(&p, +1, pend); 492191930Sdelphij } while (p < pend && is_ansi_middle(c)); 493170256Sdelphij } else if (binary_char(c)) 494170256Sdelphij bin_count++; 495170256Sdelphij } 496170256Sdelphij /* 497170256Sdelphij * Call it a binary file if there are more than 5 binary characters 498170256Sdelphij * in the first 256 bytes of the file. 499170256Sdelphij */ 500170256Sdelphij return (bin_count > 5); 50160786Sps} 50260786Sps 50360786Sps/* 50460786Sps * Try to determine the size of a file by seeking to the end. 50560786Sps */ 50660786Sps static POSITION 50760786Spsseek_filesize(f) 50860786Sps int f; 50960786Sps{ 51060786Sps off_t spos; 51160786Sps 512173682Sdelphij spos = lseek(f, (off_t)0, SEEK_END); 51360786Sps if (spos == BAD_LSEEK) 51460786Sps return (NULL_POSITION); 51560786Sps return ((POSITION) spos); 51660786Sps} 51760786Sps 51860786Sps/* 51960786Sps * Read a string from a file. 52060786Sps * Return a pointer to the string in memory. 52160786Sps */ 52260786Sps static char * 52360786Spsreadfd(fd) 52460786Sps FILE *fd; 52560786Sps{ 52660786Sps int len; 52760786Sps int ch; 52860786Sps char *buf; 52960786Sps char *p; 53060786Sps 53160786Sps /* 53260786Sps * Make a guess about how many chars in the string 53360786Sps * and allocate a buffer to hold it. 53460786Sps */ 53560786Sps len = 100; 53660786Sps buf = (char *) ecalloc(len, sizeof(char)); 53760786Sps for (p = buf; ; p++) 53860786Sps { 53960786Sps if ((ch = getc(fd)) == '\n' || ch == EOF) 54060786Sps break; 54160786Sps if (p - buf >= len-1) 54260786Sps { 54360786Sps /* 54460786Sps * The string is too big to fit in the buffer we have. 54560786Sps * Allocate a new buffer, twice as big. 54660786Sps */ 54760786Sps len *= 2; 54860786Sps *p = '\0'; 54960786Sps p = (char *) ecalloc(len, sizeof(char)); 55060786Sps strcpy(p, buf); 55160786Sps free(buf); 55260786Sps buf = p; 55360786Sps p = buf + strlen(buf); 55460786Sps } 55560786Sps *p = ch; 55660786Sps } 55760786Sps *p = '\0'; 55860786Sps return (buf); 55960786Sps} 56060786Sps 56160786Sps 56260786Sps 56360786Sps#if HAVE_POPEN 56460786Sps 56560786SpsFILE *popen(); 56660786Sps 56760786Sps/* 56860786Sps * Execute a shell command. 56960786Sps * Return a pointer to a pipe connected to the shell command's standard output. 57060786Sps */ 57160786Sps static FILE * 57260786Spsshellcmd(cmd) 57360786Sps char *cmd; 57460786Sps{ 57560786Sps FILE *fd; 57660786Sps 57760786Sps#if HAVE_SHELL 57860786Sps char *shell; 57960786Sps 58060786Sps shell = lgetenv("SHELL"); 58160786Sps if (shell != NULL && *shell != '\0') 58260786Sps { 58360786Sps char *scmd; 58460786Sps char *esccmd; 58560786Sps 58660786Sps /* 587128345Stjr * Read the output of <$SHELL -c cmd>. 588128345Stjr * Escape any metacharacters in the command. 58960786Sps */ 590128345Stjr esccmd = shell_quote(cmd); 591128345Stjr if (esccmd == NULL) 59260786Sps { 593128345Stjr fd = popen(cmd, "r"); 59460786Sps } else 59560786Sps { 596161475Sdelphij int len = strlen(shell) + strlen(esccmd) + 5; 597161475Sdelphij scmd = (char *) ecalloc(len, sizeof(char)); 598161475Sdelphij SNPRINTF3(scmd, len, "%s %s %s", shell, shell_coption(), esccmd); 59960786Sps free(esccmd); 600128345Stjr fd = popen(scmd, "r"); 601128345Stjr free(scmd); 60260786Sps } 60360786Sps } else 60460786Sps#endif 60560786Sps { 60660786Sps fd = popen(cmd, "r"); 60760786Sps } 608128345Stjr /* 609128345Stjr * Redirection in `popen' might have messed with the 610128345Stjr * standard devices. Restore binary input mode. 611128345Stjr */ 612128345Stjr SET_BINARY(0); 61360786Sps return (fd); 61460786Sps} 61560786Sps 61660786Sps#endif /* HAVE_POPEN */ 61760786Sps 61860786Sps 61960786Sps/* 62060786Sps * Expand a filename, doing any system-specific metacharacter substitutions. 62160786Sps */ 62260786Sps public char * 62360786Spslglob(filename) 62460786Sps char *filename; 62560786Sps{ 62660786Sps char *gfilename; 62760786Sps char *ofilename; 62860786Sps 62960786Sps ofilename = fexpand(filename); 63060786Sps if (secure) 63160786Sps return (ofilename); 632128345Stjr filename = shell_unquote(ofilename); 63360786Sps 63460786Sps#ifdef DECL_GLOB_LIST 63560786Sps{ 63660786Sps /* 63760786Sps * The globbing function returns a list of names. 63860786Sps */ 63960786Sps int length; 64060786Sps char *p; 641128345Stjr char *qfilename; 64260786Sps DECL_GLOB_LIST(list) 64360786Sps 64460786Sps GLOB_LIST(filename, list); 64560786Sps if (GLOB_LIST_FAILED(list)) 64660786Sps { 64760786Sps free(filename); 64860786Sps return (ofilename); 64960786Sps } 65060786Sps length = 1; /* Room for trailing null byte */ 65160786Sps for (SCAN_GLOB_LIST(list, p)) 65260786Sps { 65360786Sps INIT_GLOB_LIST(list, p); 654128345Stjr qfilename = shell_quote(p); 655128345Stjr if (qfilename != NULL) 656128345Stjr { 657128345Stjr length += strlen(qfilename) + 1; 658128345Stjr free(qfilename); 659128345Stjr } 66060786Sps } 66160786Sps gfilename = (char *) ecalloc(length, sizeof(char)); 66260786Sps for (SCAN_GLOB_LIST(list, p)) 66360786Sps { 66460786Sps INIT_GLOB_LIST(list, p); 665128345Stjr qfilename = shell_quote(p); 666128345Stjr if (qfilename != NULL) 667128345Stjr { 668128345Stjr sprintf(gfilename + strlen(gfilename), "%s ", qfilename); 669128345Stjr free(qfilename); 670128345Stjr } 67160786Sps } 67260786Sps /* 67360786Sps * Overwrite the final trailing space with a null terminator. 67460786Sps */ 67560786Sps *--p = '\0'; 67660786Sps GLOB_LIST_DONE(list); 67760786Sps} 67860786Sps#else 67960786Sps#ifdef DECL_GLOB_NAME 68060786Sps{ 68160786Sps /* 68260786Sps * The globbing function returns a single name, and 68360786Sps * is called multiple times to walk thru all names. 68460786Sps */ 68560786Sps register char *p; 68660786Sps register int len; 68760786Sps register int n; 688128345Stjr char *pathname; 689128345Stjr char *qpathname; 69060786Sps DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) 69160786Sps 69260786Sps GLOB_FIRST_NAME(filename, &fnd, handle); 69360786Sps if (GLOB_FIRST_FAILED(handle)) 69460786Sps { 69560786Sps free(filename); 69660786Sps return (ofilename); 69760786Sps } 69860786Sps 69960786Sps _splitpath(filename, drive, dir, fname, ext); 70060786Sps len = 100; 70160786Sps gfilename = (char *) ecalloc(len, sizeof(char)); 70260786Sps p = gfilename; 70360786Sps do { 70460786Sps n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1; 705128345Stjr pathname = (char *) ecalloc(n, sizeof(char)); 706161475Sdelphij SNPRINTF3(pathname, n, "%s%s%s", drive, dir, fnd.GLOB_NAME); 707128345Stjr qpathname = shell_quote(pathname); 708128345Stjr free(pathname); 709128345Stjr if (qpathname != NULL) 71060786Sps { 711128345Stjr n = strlen(qpathname); 712128345Stjr while (p - gfilename + n + 2 >= len) 713128345Stjr { 714128345Stjr /* 715128345Stjr * No room in current buffer. 716128345Stjr * Allocate a bigger one. 717128345Stjr */ 718128345Stjr len *= 2; 719128345Stjr *p = '\0'; 720128345Stjr p = (char *) ecalloc(len, sizeof(char)); 721128345Stjr strcpy(p, gfilename); 722128345Stjr free(gfilename); 723128345Stjr gfilename = p; 724128345Stjr p = gfilename + strlen(gfilename); 725128345Stjr } 726128345Stjr strcpy(p, qpathname); 727128345Stjr free(qpathname); 728128345Stjr p += n; 729128345Stjr *p++ = ' '; 73060786Sps } 73160786Sps } while (GLOB_NEXT_NAME(handle, &fnd) == 0); 73260786Sps 73360786Sps /* 73460786Sps * Overwrite the final trailing space with a null terminator. 73560786Sps */ 73660786Sps *--p = '\0'; 73760786Sps GLOB_NAME_DONE(handle); 73860786Sps} 73960786Sps#else 74060786Sps#if HAVE_POPEN 74160786Sps{ 74260786Sps /* 74360786Sps * We get the shell to glob the filename for us by passing 74460786Sps * an "echo" command to the shell and reading its output. 74560786Sps */ 74660786Sps FILE *fd; 74760786Sps char *s; 74860786Sps char *lessecho; 74960786Sps char *cmd; 750128345Stjr char *esc; 751161475Sdelphij int len; 75260786Sps 753128345Stjr esc = get_meta_escape(); 754128345Stjr if (strlen(esc) == 0) 755128345Stjr esc = "-"; 756128345Stjr esc = shell_quote(esc); 757128345Stjr if (esc == NULL) 75860786Sps { 75960786Sps free(filename); 76060786Sps return (ofilename); 76160786Sps } 762128345Stjr lessecho = lgetenv("LESSECHO"); 763128345Stjr if (lessecho == NULL || *lessecho == '\0') 764128345Stjr lessecho = "lessecho"; 76560786Sps /* 76660786Sps * Invoke lessecho, and read its output (a globbed list of filenames). 76760786Sps */ 768161475Sdelphij len = strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24; 769161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 770161475Sdelphij SNPRINTF4(cmd, len, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote, closequote, esc); 771128345Stjr free(esc); 772128345Stjr for (s = metachars(); *s != '\0'; s++) 773128345Stjr sprintf(cmd + strlen(cmd), "-n0x%x ", *s); 774128345Stjr sprintf(cmd + strlen(cmd), "-- %s", ofilename); 77560786Sps fd = shellcmd(cmd); 77660786Sps free(cmd); 77760786Sps if (fd == NULL) 77860786Sps { 77960786Sps /* 78060786Sps * Cannot create the pipe. 78160786Sps * Just return the original (fexpanded) filename. 78260786Sps */ 78360786Sps free(filename); 78460786Sps return (ofilename); 78560786Sps } 78660786Sps gfilename = readfd(fd); 78760786Sps pclose(fd); 78860786Sps if (*gfilename == '\0') 78960786Sps { 79060786Sps free(gfilename); 79160786Sps free(filename); 79260786Sps return (ofilename); 79360786Sps } 79460786Sps} 79560786Sps#else 79660786Sps /* 79760786Sps * No globbing functions at all. Just use the fexpanded filename. 79860786Sps */ 79960786Sps gfilename = save(filename); 80060786Sps#endif 80160786Sps#endif 80260786Sps#endif 80360786Sps free(filename); 80460786Sps free(ofilename); 80560786Sps return (gfilename); 80660786Sps} 80760786Sps 80860786Sps/* 80960786Sps * See if we should open a "replacement file" 81060786Sps * instead of the file we're about to open. 81160786Sps */ 81260786Sps public char * 81360786Spsopen_altfile(filename, pf, pfd) 81460786Sps char *filename; 81560786Sps int *pf; 81660786Sps void **pfd; 81760786Sps{ 81860786Sps#if !HAVE_POPEN 81960786Sps return (NULL); 82060786Sps#else 82160786Sps char *lessopen; 82260786Sps char *cmd; 823161475Sdelphij int len; 82460786Sps FILE *fd; 82560786Sps#if HAVE_FILENO 82660786Sps int returnfd = 0; 82760786Sps#endif 82860786Sps 829128345Stjr if (!use_lessopen || secure) 83060786Sps return (NULL); 83160786Sps ch_ungetchar(-1); 83260786Sps if ((lessopen = lgetenv("LESSOPEN")) == NULL) 83360786Sps return (NULL); 83460786Sps if (*lessopen == '|') 83560786Sps { 83660786Sps /* 83760786Sps * If LESSOPEN starts with a |, it indicates 83860786Sps * a "pipe preprocessor". 83960786Sps */ 840191930Sdelphij#if !HAVE_FILENO 841191930Sdelphij error("LESSOPEN pipe is not supported", NULL_PARG); 842191930Sdelphij return (NULL); 843191930Sdelphij#else 84460786Sps lessopen++; 84560786Sps returnfd = 1; 84660786Sps#endif 84760786Sps } 848195941Sdelphij if (*lessopen == '-') { 849195941Sdelphij /* 850195941Sdelphij * Lessopen preprocessor will accept "-" as a filename. 851195941Sdelphij */ 852195941Sdelphij lessopen++; 853195941Sdelphij } else { 854195941Sdelphij if (strcmp(filename, "-") == 0) 855195941Sdelphij return (NULL); 856195941Sdelphij } 85760786Sps 858161475Sdelphij len = strlen(lessopen) + strlen(filename) + 2; 859161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 860161475Sdelphij SNPRINTF1(cmd, len, lessopen, filename); 86160786Sps fd = shellcmd(cmd); 86260786Sps free(cmd); 86360786Sps if (fd == NULL) 86460786Sps { 86560786Sps /* 86660786Sps * Cannot create the pipe. 86760786Sps */ 86860786Sps return (NULL); 86960786Sps } 87060786Sps#if HAVE_FILENO 87160786Sps if (returnfd) 87260786Sps { 87360786Sps int f; 87460786Sps char c; 87560786Sps 87660786Sps /* 87760786Sps * Read one char to see if the pipe will produce any data. 87860786Sps * If it does, push the char back on the pipe. 87960786Sps */ 88060786Sps f = fileno(fd); 88160786Sps SET_BINARY(f); 88260786Sps if (read(f, &c, 1) != 1) 88360786Sps { 88460786Sps /* 88560786Sps * Pipe is empty. This means there is no alt file. 88660786Sps */ 88760786Sps pclose(fd); 88860786Sps return (NULL); 88960786Sps } 89060786Sps ch_ungetchar(c); 89160786Sps *pfd = (void *) fd; 89260786Sps *pf = f; 89360786Sps return (save("-")); 89460786Sps } 89560786Sps#endif 896128345Stjr cmd = readfd(fd); 89760786Sps pclose(fd); 898128345Stjr if (*cmd == '\0') 89960786Sps /* 90060786Sps * Pipe is empty. This means there is no alt file. 90160786Sps */ 90260786Sps return (NULL); 903128345Stjr return (cmd); 90460786Sps#endif /* HAVE_POPEN */ 90560786Sps} 90660786Sps 90760786Sps/* 90860786Sps * Close a replacement file. 90960786Sps */ 91060786Sps public void 91160786Spsclose_altfile(altfilename, filename, pipefd) 91260786Sps char *altfilename; 91360786Sps char *filename; 91460786Sps void *pipefd; 91560786Sps{ 91660786Sps#if HAVE_POPEN 91760786Sps char *lessclose; 91860786Sps FILE *fd; 91960786Sps char *cmd; 920161475Sdelphij int len; 92160786Sps 92260786Sps if (secure) 92360786Sps return; 92460786Sps if (pipefd != NULL) 92589019Sps { 92689019Sps#if OS2 92789019Sps /* 92889019Sps * The pclose function of OS/2 emx sometimes fails. 92989019Sps * Send SIGINT to the piped process before closing it. 93089019Sps */ 93189019Sps kill(((FILE*)pipefd)->_pid, SIGINT); 93289019Sps#endif 93360786Sps pclose((FILE*) pipefd); 93489019Sps } 93560786Sps if ((lessclose = lgetenv("LESSCLOSE")) == NULL) 93660786Sps return; 937161475Sdelphij len = strlen(lessclose) + strlen(filename) + strlen(altfilename) + 2; 938161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 939161475Sdelphij SNPRINTF2(cmd, len, lessclose, filename, altfilename); 94060786Sps fd = shellcmd(cmd); 94160786Sps free(cmd); 94260786Sps if (fd != NULL) 94360786Sps pclose(fd); 94460786Sps#endif 94560786Sps} 94660786Sps 94760786Sps/* 94860786Sps * Is the specified file a directory? 94960786Sps */ 95060786Sps public int 95160786Spsis_dir(filename) 95260786Sps char *filename; 95360786Sps{ 95460786Sps int isdir = 0; 95560786Sps 956128345Stjr filename = shell_unquote(filename); 95760786Sps#if HAVE_STAT 95860786Sps{ 95960786Sps int r; 96060786Sps struct stat statbuf; 96160786Sps 96260786Sps r = stat(filename, &statbuf); 96360786Sps isdir = (r >= 0 && S_ISDIR(statbuf.st_mode)); 96460786Sps} 96560786Sps#else 96660786Sps#ifdef _OSK 96760786Sps{ 96860786Sps register int f; 96960786Sps 97060786Sps f = open(filename, S_IREAD | S_IFDIR); 97160786Sps if (f >= 0) 97260786Sps close(f); 97360786Sps isdir = (f >= 0); 97460786Sps} 97560786Sps#endif 97660786Sps#endif 97760786Sps free(filename); 97860786Sps return (isdir); 97960786Sps} 98060786Sps 98160786Sps/* 98260786Sps * Returns NULL if the file can be opened and 98360786Sps * is an ordinary file, otherwise an error message 98460786Sps * (if it cannot be opened or is a directory, etc.) 98560786Sps */ 98660786Sps public char * 98760786Spsbad_file(filename) 98860786Sps char *filename; 98960786Sps{ 99060786Sps register char *m = NULL; 99160786Sps 992128345Stjr filename = shell_unquote(filename); 993170256Sdelphij if (!force_open && is_dir(filename)) 99460786Sps { 995128345Stjr static char is_a_dir[] = " is a directory"; 99660786Sps 997128345Stjr m = (char *) ecalloc(strlen(filename) + sizeof(is_a_dir), 99860786Sps sizeof(char)); 99960786Sps strcpy(m, filename); 1000128345Stjr strcat(m, is_a_dir); 100160786Sps } else 100260786Sps { 100360786Sps#if HAVE_STAT 100460786Sps int r; 100560786Sps struct stat statbuf; 100660786Sps 100760786Sps r = stat(filename, &statbuf); 100860786Sps if (r < 0) 100960786Sps { 101060786Sps m = errno_message(filename); 101160786Sps } else if (force_open) 101260786Sps { 101360786Sps m = NULL; 101460786Sps } else if (!S_ISREG(statbuf.st_mode)) 101560786Sps { 101660786Sps static char not_reg[] = " is not a regular file (use -f to see it)"; 101760786Sps m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 101860786Sps sizeof(char)); 101960786Sps strcpy(m, filename); 102060786Sps strcat(m, not_reg); 102160786Sps } 102260786Sps#endif 102360786Sps } 102460786Sps free(filename); 102560786Sps return (m); 102660786Sps} 102760786Sps 102860786Sps/* 102960786Sps * Return the size of a file, as cheaply as possible. 103060786Sps * In Unix, we can stat the file. 103160786Sps */ 103260786Sps public POSITION 103360786Spsfilesize(f) 103460786Sps int f; 103560786Sps{ 103660786Sps#if HAVE_STAT 103760786Sps struct stat statbuf; 103860786Sps 103960786Sps if (fstat(f, &statbuf) >= 0) 104060786Sps return ((POSITION) statbuf.st_size); 104160786Sps#else 104260786Sps#ifdef _OSK 104360786Sps long size; 104460786Sps 104560786Sps if ((size = (long) _gs_size(f)) >= 0) 104660786Sps return ((POSITION) size); 104760786Sps#endif 104860786Sps#endif 104960786Sps return (seek_filesize(f)); 105060786Sps} 105160786Sps 1052128345Stjr/* 1053128345Stjr * 1054128345Stjr */ 1055128345Stjr public char * 1056128345Stjrshell_coption() 1057128345Stjr{ 1058128345Stjr return ("-c"); 1059128345Stjr} 1060