filename.c revision 221715
160786Sps/* 2221715Sdelphij * Copyright (C) 1984-2011 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 403221715Sdelphij 40460786Sps#if TAB_COMPLETE_FILENAME 40560786Sps 40660786Sps/* 40760786Sps * Return a blank-separated list of filenames which "complete" 40860786Sps * the given string. 40960786Sps */ 41060786Sps public char * 41160786Spsfcomplete(s) 41260786Sps char *s; 41360786Sps{ 41460786Sps char *fpat; 415128345Stjr char *qs; 41660786Sps 41760786Sps if (secure) 41860786Sps return (NULL); 41960786Sps /* 42060786Sps * Complete the filename "s" by globbing "s*". 42160786Sps */ 42260786Sps#if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC) 42360786Sps /* 42460786Sps * But in DOS, we have to glob "s*.*". 42560786Sps * But if the final component of the filename already has 42660786Sps * a dot in it, just do "s*". 42760786Sps * (Thus, "FILE" is globbed as "FILE*.*", 42860786Sps * but "FILE.A" is globbed as "FILE.A*"). 42960786Sps */ 43060786Sps { 43160786Sps char *slash; 432161475Sdelphij int len; 43360786Sps for (slash = s+strlen(s)-1; slash > s; slash--) 43460786Sps if (*slash == *PATHNAME_SEP || *slash == '/') 43560786Sps break; 436161475Sdelphij len = strlen(s) + 4; 437161475Sdelphij fpat = (char *) ecalloc(len, sizeof(char)); 43860786Sps if (strchr(slash, '.') == NULL) 439161475Sdelphij SNPRINTF1(fpat, len, "%s*.*", s); 44060786Sps else 441161475Sdelphij SNPRINTF1(fpat, len, "%s*", s); 44260786Sps } 44360786Sps#else 444161475Sdelphij { 445161475Sdelphij int len = strlen(s) + 2; 446161475Sdelphij fpat = (char *) ecalloc(len, sizeof(char)); 447161475Sdelphij SNPRINTF1(fpat, len, "%s*", s); 448161475Sdelphij } 44960786Sps#endif 450128345Stjr qs = lglob(fpat); 451128345Stjr s = shell_unquote(qs); 45260786Sps if (strcmp(s,fpat) == 0) 45360786Sps { 45460786Sps /* 45560786Sps * The filename didn't expand. 45660786Sps */ 457128345Stjr free(qs); 458128345Stjr qs = NULL; 45960786Sps } 460128345Stjr free(s); 46160786Sps free(fpat); 462128345Stjr return (qs); 46360786Sps} 46460786Sps#endif 46560786Sps 46660786Sps/* 46760786Sps * Try to determine if a file is "binary". 46860786Sps * This is just a guess, and we need not try too hard to make it accurate. 46960786Sps */ 47060786Sps public int 47160786Spsbin_file(f) 47260786Sps int f; 47360786Sps{ 47460786Sps int n; 475170256Sdelphij int bin_count = 0; 476191930Sdelphij char data[256]; 477191930Sdelphij char* p; 478191930Sdelphij char* pend; 47960786Sps 48060786Sps if (!seekable(f)) 48160786Sps return (0); 482173682Sdelphij if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK) 48360786Sps return (0); 48460786Sps n = read(f, data, sizeof(data)); 485191930Sdelphij pend = &data[n]; 486191930Sdelphij for (p = data; p < pend; ) 487170256Sdelphij { 488191930Sdelphij LWCHAR c = step_char(&p, +1, pend); 489172468Sdelphij if (ctldisp == OPT_ONPLUS && IS_CSI_START(c)) 490170256Sdelphij { 491191930Sdelphij do { 492191930Sdelphij c = step_char(&p, +1, pend); 493191930Sdelphij } while (p < pend && is_ansi_middle(c)); 494170256Sdelphij } else if (binary_char(c)) 495170256Sdelphij bin_count++; 496170256Sdelphij } 497170256Sdelphij /* 498170256Sdelphij * Call it a binary file if there are more than 5 binary characters 499170256Sdelphij * in the first 256 bytes of the file. 500170256Sdelphij */ 501170256Sdelphij return (bin_count > 5); 50260786Sps} 50360786Sps 50460786Sps/* 50560786Sps * Try to determine the size of a file by seeking to the end. 50660786Sps */ 50760786Sps static POSITION 50860786Spsseek_filesize(f) 50960786Sps int f; 51060786Sps{ 51160786Sps off_t spos; 51260786Sps 513173682Sdelphij spos = lseek(f, (off_t)0, SEEK_END); 51460786Sps if (spos == BAD_LSEEK) 51560786Sps return (NULL_POSITION); 51660786Sps return ((POSITION) spos); 51760786Sps} 51860786Sps 51960786Sps/* 52060786Sps * Read a string from a file. 52160786Sps * Return a pointer to the string in memory. 52260786Sps */ 52360786Sps static char * 52460786Spsreadfd(fd) 52560786Sps FILE *fd; 52660786Sps{ 52760786Sps int len; 52860786Sps int ch; 52960786Sps char *buf; 53060786Sps char *p; 53160786Sps 53260786Sps /* 53360786Sps * Make a guess about how many chars in the string 53460786Sps * and allocate a buffer to hold it. 53560786Sps */ 53660786Sps len = 100; 53760786Sps buf = (char *) ecalloc(len, sizeof(char)); 53860786Sps for (p = buf; ; p++) 53960786Sps { 54060786Sps if ((ch = getc(fd)) == '\n' || ch == EOF) 54160786Sps break; 54260786Sps if (p - buf >= len-1) 54360786Sps { 54460786Sps /* 54560786Sps * The string is too big to fit in the buffer we have. 54660786Sps * Allocate a new buffer, twice as big. 54760786Sps */ 54860786Sps len *= 2; 54960786Sps *p = '\0'; 55060786Sps p = (char *) ecalloc(len, sizeof(char)); 55160786Sps strcpy(p, buf); 55260786Sps free(buf); 55360786Sps buf = p; 55460786Sps p = buf + strlen(buf); 55560786Sps } 55660786Sps *p = ch; 55760786Sps } 55860786Sps *p = '\0'; 55960786Sps return (buf); 56060786Sps} 56160786Sps 56260786Sps 56360786Sps 56460786Sps#if HAVE_POPEN 56560786Sps 56660786SpsFILE *popen(); 56760786Sps 56860786Sps/* 56960786Sps * Execute a shell command. 57060786Sps * Return a pointer to a pipe connected to the shell command's standard output. 57160786Sps */ 57260786Sps static FILE * 57360786Spsshellcmd(cmd) 57460786Sps char *cmd; 57560786Sps{ 57660786Sps FILE *fd; 57760786Sps 57860786Sps#if HAVE_SHELL 57960786Sps char *shell; 58060786Sps 58160786Sps shell = lgetenv("SHELL"); 58260786Sps if (shell != NULL && *shell != '\0') 58360786Sps { 58460786Sps char *scmd; 58560786Sps char *esccmd; 58660786Sps 58760786Sps /* 588128345Stjr * Read the output of <$SHELL -c cmd>. 589128345Stjr * Escape any metacharacters in the command. 59060786Sps */ 591128345Stjr esccmd = shell_quote(cmd); 592128345Stjr if (esccmd == NULL) 59360786Sps { 594128345Stjr fd = popen(cmd, "r"); 59560786Sps } else 59660786Sps { 597161475Sdelphij int len = strlen(shell) + strlen(esccmd) + 5; 598161475Sdelphij scmd = (char *) ecalloc(len, sizeof(char)); 599161475Sdelphij SNPRINTF3(scmd, len, "%s %s %s", shell, shell_coption(), esccmd); 60060786Sps free(esccmd); 601128345Stjr fd = popen(scmd, "r"); 602128345Stjr free(scmd); 60360786Sps } 60460786Sps } else 60560786Sps#endif 60660786Sps { 60760786Sps fd = popen(cmd, "r"); 60860786Sps } 609128345Stjr /* 610128345Stjr * Redirection in `popen' might have messed with the 611128345Stjr * standard devices. Restore binary input mode. 612128345Stjr */ 613128345Stjr SET_BINARY(0); 61460786Sps return (fd); 61560786Sps} 61660786Sps 61760786Sps#endif /* HAVE_POPEN */ 61860786Sps 61960786Sps 62060786Sps/* 62160786Sps * Expand a filename, doing any system-specific metacharacter substitutions. 62260786Sps */ 62360786Sps public char * 62460786Spslglob(filename) 62560786Sps char *filename; 62660786Sps{ 62760786Sps char *gfilename; 62860786Sps char *ofilename; 62960786Sps 63060786Sps ofilename = fexpand(filename); 63160786Sps if (secure) 63260786Sps return (ofilename); 633128345Stjr filename = shell_unquote(ofilename); 63460786Sps 63560786Sps#ifdef DECL_GLOB_LIST 63660786Sps{ 63760786Sps /* 63860786Sps * The globbing function returns a list of names. 63960786Sps */ 64060786Sps int length; 64160786Sps char *p; 642128345Stjr char *qfilename; 64360786Sps DECL_GLOB_LIST(list) 64460786Sps 64560786Sps GLOB_LIST(filename, list); 64660786Sps if (GLOB_LIST_FAILED(list)) 64760786Sps { 64860786Sps free(filename); 64960786Sps return (ofilename); 65060786Sps } 65160786Sps length = 1; /* Room for trailing null byte */ 65260786Sps for (SCAN_GLOB_LIST(list, p)) 65360786Sps { 65460786Sps INIT_GLOB_LIST(list, p); 655128345Stjr qfilename = shell_quote(p); 656128345Stjr if (qfilename != NULL) 657128345Stjr { 658128345Stjr length += strlen(qfilename) + 1; 659128345Stjr free(qfilename); 660128345Stjr } 66160786Sps } 66260786Sps gfilename = (char *) ecalloc(length, sizeof(char)); 66360786Sps for (SCAN_GLOB_LIST(list, p)) 66460786Sps { 66560786Sps INIT_GLOB_LIST(list, p); 666128345Stjr qfilename = shell_quote(p); 667128345Stjr if (qfilename != NULL) 668128345Stjr { 669128345Stjr sprintf(gfilename + strlen(gfilename), "%s ", qfilename); 670128345Stjr free(qfilename); 671128345Stjr } 67260786Sps } 67360786Sps /* 67460786Sps * Overwrite the final trailing space with a null terminator. 67560786Sps */ 67660786Sps *--p = '\0'; 67760786Sps GLOB_LIST_DONE(list); 67860786Sps} 67960786Sps#else 68060786Sps#ifdef DECL_GLOB_NAME 68160786Sps{ 68260786Sps /* 68360786Sps * The globbing function returns a single name, and 68460786Sps * is called multiple times to walk thru all names. 68560786Sps */ 68660786Sps register char *p; 68760786Sps register int len; 68860786Sps register int n; 689128345Stjr char *pathname; 690128345Stjr char *qpathname; 69160786Sps DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) 69260786Sps 69360786Sps GLOB_FIRST_NAME(filename, &fnd, handle); 69460786Sps if (GLOB_FIRST_FAILED(handle)) 69560786Sps { 69660786Sps free(filename); 69760786Sps return (ofilename); 69860786Sps } 69960786Sps 70060786Sps _splitpath(filename, drive, dir, fname, ext); 70160786Sps len = 100; 70260786Sps gfilename = (char *) ecalloc(len, sizeof(char)); 70360786Sps p = gfilename; 70460786Sps do { 70560786Sps n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1; 706128345Stjr pathname = (char *) ecalloc(n, sizeof(char)); 707161475Sdelphij SNPRINTF3(pathname, n, "%s%s%s", drive, dir, fnd.GLOB_NAME); 708128345Stjr qpathname = shell_quote(pathname); 709128345Stjr free(pathname); 710128345Stjr if (qpathname != NULL) 71160786Sps { 712128345Stjr n = strlen(qpathname); 713128345Stjr while (p - gfilename + n + 2 >= len) 714128345Stjr { 715128345Stjr /* 716128345Stjr * No room in current buffer. 717128345Stjr * Allocate a bigger one. 718128345Stjr */ 719128345Stjr len *= 2; 720128345Stjr *p = '\0'; 721128345Stjr p = (char *) ecalloc(len, sizeof(char)); 722128345Stjr strcpy(p, gfilename); 723128345Stjr free(gfilename); 724128345Stjr gfilename = p; 725128345Stjr p = gfilename + strlen(gfilename); 726128345Stjr } 727128345Stjr strcpy(p, qpathname); 728128345Stjr free(qpathname); 729128345Stjr p += n; 730128345Stjr *p++ = ' '; 73160786Sps } 73260786Sps } while (GLOB_NEXT_NAME(handle, &fnd) == 0); 73360786Sps 73460786Sps /* 73560786Sps * Overwrite the final trailing space with a null terminator. 73660786Sps */ 73760786Sps *--p = '\0'; 73860786Sps GLOB_NAME_DONE(handle); 73960786Sps} 74060786Sps#else 74160786Sps#if HAVE_POPEN 74260786Sps{ 74360786Sps /* 74460786Sps * We get the shell to glob the filename for us by passing 74560786Sps * an "echo" command to the shell and reading its output. 74660786Sps */ 74760786Sps FILE *fd; 74860786Sps char *s; 74960786Sps char *lessecho; 75060786Sps char *cmd; 751128345Stjr char *esc; 752161475Sdelphij int len; 75360786Sps 754128345Stjr esc = get_meta_escape(); 755128345Stjr if (strlen(esc) == 0) 756128345Stjr esc = "-"; 757128345Stjr esc = shell_quote(esc); 758128345Stjr if (esc == NULL) 75960786Sps { 76060786Sps free(filename); 76160786Sps return (ofilename); 76260786Sps } 763128345Stjr lessecho = lgetenv("LESSECHO"); 764128345Stjr if (lessecho == NULL || *lessecho == '\0') 765128345Stjr lessecho = "lessecho"; 76660786Sps /* 76760786Sps * Invoke lessecho, and read its output (a globbed list of filenames). 76860786Sps */ 769161475Sdelphij len = strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24; 770161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 771161475Sdelphij SNPRINTF4(cmd, len, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote, closequote, esc); 772128345Stjr free(esc); 773128345Stjr for (s = metachars(); *s != '\0'; s++) 774128345Stjr sprintf(cmd + strlen(cmd), "-n0x%x ", *s); 775128345Stjr sprintf(cmd + strlen(cmd), "-- %s", ofilename); 77660786Sps fd = shellcmd(cmd); 77760786Sps free(cmd); 77860786Sps if (fd == NULL) 77960786Sps { 78060786Sps /* 78160786Sps * Cannot create the pipe. 78260786Sps * Just return the original (fexpanded) filename. 78360786Sps */ 78460786Sps free(filename); 78560786Sps return (ofilename); 78660786Sps } 78760786Sps gfilename = readfd(fd); 78860786Sps pclose(fd); 78960786Sps if (*gfilename == '\0') 79060786Sps { 79160786Sps free(gfilename); 79260786Sps free(filename); 79360786Sps return (ofilename); 79460786Sps } 79560786Sps} 79660786Sps#else 79760786Sps /* 79860786Sps * No globbing functions at all. Just use the fexpanded filename. 79960786Sps */ 80060786Sps gfilename = save(filename); 80160786Sps#endif 80260786Sps#endif 80360786Sps#endif 80460786Sps free(filename); 80560786Sps free(ofilename); 80660786Sps return (gfilename); 80760786Sps} 80860786Sps 80960786Sps/* 81060786Sps * See if we should open a "replacement file" 81160786Sps * instead of the file we're about to open. 81260786Sps */ 81360786Sps public char * 81460786Spsopen_altfile(filename, pf, pfd) 81560786Sps char *filename; 81660786Sps int *pf; 81760786Sps void **pfd; 81860786Sps{ 81960786Sps#if !HAVE_POPEN 82060786Sps return (NULL); 82160786Sps#else 82260786Sps char *lessopen; 82360786Sps char *cmd; 824161475Sdelphij int len; 82560786Sps FILE *fd; 82660786Sps#if HAVE_FILENO 82760786Sps int returnfd = 0; 82860786Sps#endif 82960786Sps 830128345Stjr if (!use_lessopen || secure) 83160786Sps return (NULL); 83260786Sps ch_ungetchar(-1); 83360786Sps if ((lessopen = lgetenv("LESSOPEN")) == NULL) 83460786Sps return (NULL); 83560786Sps if (*lessopen == '|') 83660786Sps { 83760786Sps /* 83860786Sps * If LESSOPEN starts with a |, it indicates 83960786Sps * a "pipe preprocessor". 84060786Sps */ 841191930Sdelphij#if !HAVE_FILENO 842191930Sdelphij error("LESSOPEN pipe is not supported", NULL_PARG); 843191930Sdelphij return (NULL); 844191930Sdelphij#else 84560786Sps lessopen++; 84660786Sps returnfd = 1; 84760786Sps#endif 84860786Sps } 849195941Sdelphij if (*lessopen == '-') { 850195941Sdelphij /* 851195941Sdelphij * Lessopen preprocessor will accept "-" as a filename. 852195941Sdelphij */ 853195941Sdelphij lessopen++; 854195941Sdelphij } else { 855195941Sdelphij if (strcmp(filename, "-") == 0) 856195941Sdelphij return (NULL); 857195941Sdelphij } 85860786Sps 859161475Sdelphij len = strlen(lessopen) + strlen(filename) + 2; 860161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 861161475Sdelphij SNPRINTF1(cmd, len, lessopen, filename); 86260786Sps fd = shellcmd(cmd); 86360786Sps free(cmd); 86460786Sps if (fd == NULL) 86560786Sps { 86660786Sps /* 86760786Sps * Cannot create the pipe. 86860786Sps */ 86960786Sps return (NULL); 87060786Sps } 87160786Sps#if HAVE_FILENO 87260786Sps if (returnfd) 87360786Sps { 87460786Sps int f; 87560786Sps char c; 87660786Sps 87760786Sps /* 87860786Sps * Read one char to see if the pipe will produce any data. 87960786Sps * If it does, push the char back on the pipe. 88060786Sps */ 88160786Sps f = fileno(fd); 88260786Sps SET_BINARY(f); 88360786Sps if (read(f, &c, 1) != 1) 88460786Sps { 88560786Sps /* 88660786Sps * Pipe is empty. This means there is no alt file. 88760786Sps */ 88860786Sps pclose(fd); 88960786Sps return (NULL); 89060786Sps } 89160786Sps ch_ungetchar(c); 89260786Sps *pfd = (void *) fd; 89360786Sps *pf = f; 89460786Sps return (save("-")); 89560786Sps } 89660786Sps#endif 897128345Stjr cmd = readfd(fd); 89860786Sps pclose(fd); 899128345Stjr if (*cmd == '\0') 90060786Sps /* 90160786Sps * Pipe is empty. This means there is no alt file. 90260786Sps */ 90360786Sps return (NULL); 904128345Stjr return (cmd); 90560786Sps#endif /* HAVE_POPEN */ 90660786Sps} 90760786Sps 90860786Sps/* 90960786Sps * Close a replacement file. 91060786Sps */ 91160786Sps public void 91260786Spsclose_altfile(altfilename, filename, pipefd) 91360786Sps char *altfilename; 91460786Sps char *filename; 91560786Sps void *pipefd; 91660786Sps{ 91760786Sps#if HAVE_POPEN 91860786Sps char *lessclose; 91960786Sps FILE *fd; 92060786Sps char *cmd; 921161475Sdelphij int len; 92260786Sps 92360786Sps if (secure) 92460786Sps return; 92560786Sps if (pipefd != NULL) 92689019Sps { 92789019Sps#if OS2 92889019Sps /* 92989019Sps * The pclose function of OS/2 emx sometimes fails. 93089019Sps * Send SIGINT to the piped process before closing it. 93189019Sps */ 93289019Sps kill(((FILE*)pipefd)->_pid, SIGINT); 93389019Sps#endif 93460786Sps pclose((FILE*) pipefd); 93589019Sps } 93660786Sps if ((lessclose = lgetenv("LESSCLOSE")) == NULL) 93760786Sps return; 938161475Sdelphij len = strlen(lessclose) + strlen(filename) + strlen(altfilename) + 2; 939161475Sdelphij cmd = (char *) ecalloc(len, sizeof(char)); 940161475Sdelphij SNPRINTF2(cmd, len, lessclose, filename, altfilename); 94160786Sps fd = shellcmd(cmd); 94260786Sps free(cmd); 94360786Sps if (fd != NULL) 94460786Sps pclose(fd); 94560786Sps#endif 94660786Sps} 94760786Sps 94860786Sps/* 94960786Sps * Is the specified file a directory? 95060786Sps */ 95160786Sps public int 95260786Spsis_dir(filename) 95360786Sps char *filename; 95460786Sps{ 95560786Sps int isdir = 0; 95660786Sps 957128345Stjr filename = shell_unquote(filename); 95860786Sps#if HAVE_STAT 95960786Sps{ 96060786Sps int r; 96160786Sps struct stat statbuf; 96260786Sps 96360786Sps r = stat(filename, &statbuf); 96460786Sps isdir = (r >= 0 && S_ISDIR(statbuf.st_mode)); 96560786Sps} 96660786Sps#else 96760786Sps#ifdef _OSK 96860786Sps{ 96960786Sps register int f; 97060786Sps 97160786Sps f = open(filename, S_IREAD | S_IFDIR); 97260786Sps if (f >= 0) 97360786Sps close(f); 97460786Sps isdir = (f >= 0); 97560786Sps} 97660786Sps#endif 97760786Sps#endif 97860786Sps free(filename); 97960786Sps return (isdir); 98060786Sps} 98160786Sps 98260786Sps/* 98360786Sps * Returns NULL if the file can be opened and 98460786Sps * is an ordinary file, otherwise an error message 98560786Sps * (if it cannot be opened or is a directory, etc.) 98660786Sps */ 98760786Sps public char * 98860786Spsbad_file(filename) 98960786Sps char *filename; 99060786Sps{ 99160786Sps register char *m = NULL; 99260786Sps 993128345Stjr filename = shell_unquote(filename); 994170256Sdelphij if (!force_open && is_dir(filename)) 99560786Sps { 996128345Stjr static char is_a_dir[] = " is a directory"; 99760786Sps 998128345Stjr m = (char *) ecalloc(strlen(filename) + sizeof(is_a_dir), 99960786Sps sizeof(char)); 100060786Sps strcpy(m, filename); 1001128345Stjr strcat(m, is_a_dir); 100260786Sps } else 100360786Sps { 100460786Sps#if HAVE_STAT 100560786Sps int r; 100660786Sps struct stat statbuf; 100760786Sps 100860786Sps r = stat(filename, &statbuf); 100960786Sps if (r < 0) 101060786Sps { 101160786Sps m = errno_message(filename); 101260786Sps } else if (force_open) 101360786Sps { 101460786Sps m = NULL; 101560786Sps } else if (!S_ISREG(statbuf.st_mode)) 101660786Sps { 101760786Sps static char not_reg[] = " is not a regular file (use -f to see it)"; 101860786Sps m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 101960786Sps sizeof(char)); 102060786Sps strcpy(m, filename); 102160786Sps strcat(m, not_reg); 102260786Sps } 102360786Sps#endif 102460786Sps } 102560786Sps free(filename); 102660786Sps return (m); 102760786Sps} 102860786Sps 102960786Sps/* 103060786Sps * Return the size of a file, as cheaply as possible. 103160786Sps * In Unix, we can stat the file. 103260786Sps */ 103360786Sps public POSITION 103460786Spsfilesize(f) 103560786Sps int f; 103660786Sps{ 103760786Sps#if HAVE_STAT 103860786Sps struct stat statbuf; 103960786Sps 104060786Sps if (fstat(f, &statbuf) >= 0) 104160786Sps return ((POSITION) statbuf.st_size); 104260786Sps#else 104360786Sps#ifdef _OSK 104460786Sps long size; 104560786Sps 104660786Sps if ((size = (long) _gs_size(f)) >= 0) 104760786Sps return ((POSITION) size); 104860786Sps#endif 104960786Sps#endif 105060786Sps return (seek_filesize(f)); 105160786Sps} 105260786Sps 1053128345Stjr/* 1054128345Stjr * 1055128345Stjr */ 1056128345Stjr public char * 1057128345Stjrshell_coption() 1058128345Stjr{ 1059128345Stjr return ("-c"); 1060128345Stjr} 1061221715Sdelphij 1062221715Sdelphij/* 1063221715Sdelphij * Return last component of a pathname. 1064221715Sdelphij */ 1065221715Sdelphij public char * 1066221715Sdelphijlast_component(name) 1067221715Sdelphij char *name; 1068221715Sdelphij{ 1069221715Sdelphij char *slash; 1070221715Sdelphij 1071221715Sdelphij for (slash = name + strlen(name); slash > name; ) 1072221715Sdelphij { 1073221715Sdelphij --slash; 1074221715Sdelphij if (*slash == *PATHNAME_SEP || *slash == '/') 1075221715Sdelphij return (slash + 1); 1076221715Sdelphij } 1077221715Sdelphij return (name); 1078221715Sdelphij} 1079221715Sdelphij 1080