filename.c revision 60786
160786Sps/* 260786Sps * Copyright (C) 1984-2000 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#include <limits.h> 2860786Sps#define _MAX_PATH PATH_MAX 2960786Sps#endif 3060786Sps#endif 3160786Sps#ifdef _OSK 3260786Sps#include <rbf.h> 3360786Sps#ifndef _OSK_MWC32 3460786Sps#include <modes.h> 3560786Sps#endif 3660786Sps#endif 3760786Sps 3860786Sps#if HAVE_STAT 3960786Sps#include <sys/stat.h> 4060786Sps#ifndef S_ISDIR 4160786Sps#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 4260786Sps#endif 4360786Sps#ifndef S_ISREG 4460786Sps#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 4560786Sps#endif 4660786Sps#endif 4760786Sps 4860786Sps 4960786Spsextern int force_open; 5060786Spsextern int secure; 5160786Spsextern IFILE curr_ifile; 5260786Spsextern IFILE old_ifile; 5360786Sps#if SPACES_IN_FILENAMES 5460786Spsextern char openquote; 5560786Spsextern char closequote; 5660786Sps#endif 5760786Sps 5860786Sps/* 5960786Sps * Remove quotes around a filename. 6060786Sps */ 6160786Sps public char * 6260786Spsunquote_file(str) 6360786Sps char *str; 6460786Sps{ 6560786Sps#if SPACES_IN_FILENAMES 6660786Sps char *name; 6760786Sps char *p; 6860786Sps 6960786Sps if (*str != openquote) 7060786Sps return (save(str)); 7160786Sps name = (char *) ecalloc(strlen(str), sizeof(char)); 7260786Sps strcpy(name, str+1); 7360786Sps p = name + strlen(name) - 1; 7460786Sps if (*p == closequote) 7560786Sps *p = '\0'; 7660786Sps return (name); 7760786Sps#else 7860786Sps return (save(str)); 7960786Sps#endif 8060786Sps} 8160786Sps 8260786Sps/* 8360786Sps * Return a pathname that points to a specified file in a specified directory. 8460786Sps * Return NULL if the file does not exist in the directory. 8560786Sps */ 8660786Sps static char * 8760786Spsdirfile(dirname, filename) 8860786Sps char *dirname; 8960786Sps char *filename; 9060786Sps{ 9160786Sps char *pathname; 9260786Sps char *qpathname; 9360786Sps int f; 9460786Sps 9560786Sps if (dirname == NULL || *dirname == '\0') 9660786Sps return (NULL); 9760786Sps /* 9860786Sps * Construct the full pathname. 9960786Sps */ 10060786Sps pathname = (char *) calloc(strlen(dirname) + strlen(filename) + 2, 10160786Sps sizeof(char)); 10260786Sps if (pathname == NULL) 10360786Sps return (NULL); 10460786Sps sprintf(pathname, "%s%s%s", dirname, PATHNAME_SEP, filename); 10560786Sps /* 10660786Sps * Make sure the file exists. 10760786Sps */ 10860786Sps qpathname = unquote_file(pathname); 10960786Sps f = open(qpathname, OPEN_READ); 11060786Sps if (f < 0) 11160786Sps { 11260786Sps free(pathname); 11360786Sps pathname = NULL; 11460786Sps } else 11560786Sps { 11660786Sps close(f); 11760786Sps } 11860786Sps free(qpathname); 11960786Sps return (pathname); 12060786Sps} 12160786Sps 12260786Sps/* 12360786Sps * Return the full pathname of the given file in the "home directory". 12460786Sps */ 12560786Sps public char * 12660786Spshomefile(filename) 12760786Sps char *filename; 12860786Sps{ 12960786Sps register char *pathname; 13060786Sps 13160786Sps /* 13260786Sps * Try $HOME/filename. 13360786Sps */ 13460786Sps pathname = dirfile(lgetenv("HOME"), filename); 13560786Sps if (pathname != NULL) 13660786Sps return (pathname); 13760786Sps#if OS2 13860786Sps /* 13960786Sps * Try $INIT/filename. 14060786Sps */ 14160786Sps pathname = dirfile(lgetenv("INIT"), filename); 14260786Sps if (pathname != NULL) 14360786Sps return (pathname); 14460786Sps#endif 14560786Sps#if MSDOS_COMPILER || OS2 14660786Sps /* 14760786Sps * Look for the file anywhere on search path. 14860786Sps */ 14960786Sps pathname = (char *) calloc(_MAX_PATH, sizeof(char)); 15060786Sps#if MSDOS_COMPILER==DJGPPC 15160786Sps { 15260786Sps char *res = searchpath(filename); 15360786Sps if (res == 0) 15460786Sps *pathname = '\0'; 15560786Sps else 15660786Sps strcpy(pathname, res); 15760786Sps } 15860786Sps#else 15960786Sps _searchenv(filename, "PATH", pathname); 16060786Sps#endif 16160786Sps if (*pathname != '\0') 16260786Sps return (pathname); 16360786Sps free(pathname); 16460786Sps#endif 16560786Sps return (NULL); 16660786Sps} 16760786Sps 16860786Sps/* 16960786Sps * Expand a string, substituting any "%" with the current filename, 17060786Sps * and any "#" with the previous filename. 17160786Sps * But a string of N "%"s is just replaced with N-1 "%"s. 17260786Sps * Likewise for a string of N "#"s. 17360786Sps * {{ This is a lot of work just to support % and #. }} 17460786Sps */ 17560786Sps public char * 17660786Spsfexpand(s) 17760786Sps char *s; 17860786Sps{ 17960786Sps register char *fr, *to; 18060786Sps register int n; 18160786Sps register char *e; 18260786Sps IFILE ifile; 18360786Sps 18460786Sps#define fchar_ifile(c) \ 18560786Sps ((c) == '%' ? curr_ifile : \ 18660786Sps (c) == '#' ? old_ifile : NULL_IFILE) 18760786Sps 18860786Sps /* 18960786Sps * Make one pass to see how big a buffer we 19060786Sps * need to allocate for the expanded string. 19160786Sps */ 19260786Sps n = 0; 19360786Sps for (fr = s; *fr != '\0'; fr++) 19460786Sps { 19560786Sps switch (*fr) 19660786Sps { 19760786Sps case '%': 19860786Sps case '#': 19960786Sps if (fr > s && fr[-1] == *fr) 20060786Sps { 20160786Sps /* 20260786Sps * Second (or later) char in a string 20360786Sps * of identical chars. Treat as normal. 20460786Sps */ 20560786Sps n++; 20660786Sps } else if (fr[1] != *fr) 20760786Sps { 20860786Sps /* 20960786Sps * Single char (not repeated). Treat specially. 21060786Sps */ 21160786Sps ifile = fchar_ifile(*fr); 21260786Sps if (ifile == NULL_IFILE) 21360786Sps n++; 21460786Sps else 21560786Sps n += strlen(get_filename(ifile)); 21660786Sps } 21760786Sps /* 21860786Sps * Else it is the first char in a string of 21960786Sps * identical chars. Just discard it. 22060786Sps */ 22160786Sps break; 22260786Sps default: 22360786Sps n++; 22460786Sps break; 22560786Sps } 22660786Sps } 22760786Sps 22860786Sps e = (char *) ecalloc(n+1, sizeof(char)); 22960786Sps 23060786Sps /* 23160786Sps * Now copy the string, expanding any "%" or "#". 23260786Sps */ 23360786Sps to = e; 23460786Sps for (fr = s; *fr != '\0'; fr++) 23560786Sps { 23660786Sps switch (*fr) 23760786Sps { 23860786Sps case '%': 23960786Sps case '#': 24060786Sps if (fr > s && fr[-1] == *fr) 24160786Sps { 24260786Sps *to++ = *fr; 24360786Sps } else if (fr[1] != *fr) 24460786Sps { 24560786Sps ifile = fchar_ifile(*fr); 24660786Sps if (ifile == NULL_IFILE) 24760786Sps *to++ = *fr; 24860786Sps else 24960786Sps { 25060786Sps strcpy(to, get_filename(ifile)); 25160786Sps to += strlen(to); 25260786Sps } 25360786Sps } 25460786Sps break; 25560786Sps default: 25660786Sps *to++ = *fr; 25760786Sps break; 25860786Sps } 25960786Sps } 26060786Sps *to = '\0'; 26160786Sps return (e); 26260786Sps} 26360786Sps 26460786Sps#if TAB_COMPLETE_FILENAME 26560786Sps 26660786Sps/* 26760786Sps * Return a blank-separated list of filenames which "complete" 26860786Sps * the given string. 26960786Sps */ 27060786Sps public char * 27160786Spsfcomplete(s) 27260786Sps char *s; 27360786Sps{ 27460786Sps char *fpat; 27560786Sps 27660786Sps if (secure) 27760786Sps return (NULL); 27860786Sps /* 27960786Sps * Complete the filename "s" by globbing "s*". 28060786Sps */ 28160786Sps#if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC) 28260786Sps /* 28360786Sps * But in DOS, we have to glob "s*.*". 28460786Sps * But if the final component of the filename already has 28560786Sps * a dot in it, just do "s*". 28660786Sps * (Thus, "FILE" is globbed as "FILE*.*", 28760786Sps * but "FILE.A" is globbed as "FILE.A*"). 28860786Sps */ 28960786Sps { 29060786Sps char *slash; 29160786Sps for (slash = s+strlen(s)-1; slash > s; slash--) 29260786Sps if (*slash == *PATHNAME_SEP || *slash == '/') 29360786Sps break; 29460786Sps fpat = (char *) ecalloc(strlen(s)+4, sizeof(char)); 29560786Sps if (strchr(slash, '.') == NULL) 29660786Sps sprintf(fpat, "%s*.*", s); 29760786Sps else 29860786Sps sprintf(fpat, "%s*", s); 29960786Sps } 30060786Sps#else 30160786Sps fpat = (char *) ecalloc(strlen(s)+2, sizeof(char)); 30260786Sps sprintf(fpat, "%s*", s); 30360786Sps#endif 30460786Sps s = lglob(fpat); 30560786Sps if (strcmp(s,fpat) == 0) 30660786Sps { 30760786Sps /* 30860786Sps * The filename didn't expand. 30960786Sps */ 31060786Sps free(s); 31160786Sps s = NULL; 31260786Sps } 31360786Sps free(fpat); 31460786Sps return (s); 31560786Sps} 31660786Sps#endif 31760786Sps 31860786Sps/* 31960786Sps * Try to determine if a file is "binary". 32060786Sps * This is just a guess, and we need not try too hard to make it accurate. 32160786Sps */ 32260786Sps public int 32360786Spsbin_file(f) 32460786Sps int f; 32560786Sps{ 32660786Sps int i; 32760786Sps int n; 32860786Sps unsigned char data[64]; 32960786Sps 33060786Sps if (!seekable(f)) 33160786Sps return (0); 33260786Sps if (lseek(f, (off_t)0, 0) == BAD_LSEEK) 33360786Sps return (0); 33460786Sps n = read(f, data, sizeof(data)); 33560786Sps for (i = 0; i < n; i++) 33660786Sps if (binary_char(data[i])) 33760786Sps return (1); 33860786Sps return (0); 33960786Sps} 34060786Sps 34160786Sps/* 34260786Sps * Try to determine the size of a file by seeking to the end. 34360786Sps */ 34460786Sps static POSITION 34560786Spsseek_filesize(f) 34660786Sps int f; 34760786Sps{ 34860786Sps off_t spos; 34960786Sps 35060786Sps spos = lseek(f, (off_t)0, 2); 35160786Sps if (spos == BAD_LSEEK) 35260786Sps return (NULL_POSITION); 35360786Sps return ((POSITION) spos); 35460786Sps} 35560786Sps 35660786Sps/* 35760786Sps * Read a string from a file. 35860786Sps * Return a pointer to the string in memory. 35960786Sps */ 36060786Sps static char * 36160786Spsreadfd(fd) 36260786Sps FILE *fd; 36360786Sps{ 36460786Sps int len; 36560786Sps int ch; 36660786Sps char *buf; 36760786Sps char *p; 36860786Sps 36960786Sps /* 37060786Sps * Make a guess about how many chars in the string 37160786Sps * and allocate a buffer to hold it. 37260786Sps */ 37360786Sps len = 100; 37460786Sps buf = (char *) ecalloc(len, sizeof(char)); 37560786Sps for (p = buf; ; p++) 37660786Sps { 37760786Sps if ((ch = getc(fd)) == '\n' || ch == EOF) 37860786Sps break; 37960786Sps if (p - buf >= len-1) 38060786Sps { 38160786Sps /* 38260786Sps * The string is too big to fit in the buffer we have. 38360786Sps * Allocate a new buffer, twice as big. 38460786Sps */ 38560786Sps len *= 2; 38660786Sps *p = '\0'; 38760786Sps p = (char *) ecalloc(len, sizeof(char)); 38860786Sps strcpy(p, buf); 38960786Sps free(buf); 39060786Sps buf = p; 39160786Sps p = buf + strlen(buf); 39260786Sps } 39360786Sps *p = ch; 39460786Sps } 39560786Sps *p = '\0'; 39660786Sps return (buf); 39760786Sps} 39860786Sps 39960786Sps#if HAVE_SHELL 40060786Sps 40160786Sps/* 40260786Sps * Get the shell's escape character. 40360786Sps */ 40460786Sps static char * 40560786Spsget_meta_escape() 40660786Sps{ 40760786Sps char *s; 40860786Sps 40960786Sps s = lgetenv("LESSMETAESCAPE"); 41060786Sps if (s == NULL) 41160786Sps s = DEF_METAESCAPE; 41260786Sps return (s); 41360786Sps} 41460786Sps 41560786Sps/* 41660786Sps * Is this a shell metacharacter? 41760786Sps */ 41860786Sps static int 41960786Spsmetachar(c) 42060786Sps char c; 42160786Sps{ 42260786Sps static char *metachars = NULL; 42360786Sps 42460786Sps if (metachars == NULL) 42560786Sps { 42660786Sps metachars = lgetenv("LESSMETACHARS"); 42760786Sps if (metachars == NULL) 42860786Sps metachars = DEF_METACHARS; 42960786Sps } 43060786Sps return (strchr(metachars, c) != NULL); 43160786Sps} 43260786Sps 43360786Sps/* 43460786Sps * Insert a backslash before each metacharacter in a string. 43560786Sps */ 43660786Sps public char * 43760786Spsesc_metachars(s) 43860786Sps char *s; 43960786Sps{ 44060786Sps char *p; 44160786Sps char *newstr; 44260786Sps int len; 44360786Sps char *esc; 44460786Sps int esclen; 44560786Sps 44660786Sps /* 44760786Sps * Determine how big a string we need to allocate. 44860786Sps */ 44960786Sps esc = get_meta_escape(); 45060786Sps esclen = strlen(esc); 45160786Sps len = 1; /* Trailing null byte */ 45260786Sps for (p = s; *p != '\0'; p++) 45360786Sps { 45460786Sps len++; 45560786Sps if (metachar(*p)) 45660786Sps { 45760786Sps if (*esc == '\0') 45860786Sps { 45960786Sps /* 46060786Sps * We've got a metachar, but this shell 46160786Sps * doesn't support escape chars. Give up. 46260786Sps */ 46360786Sps return (NULL); 46460786Sps } 46560786Sps /* 46660786Sps * Allow space for the escape char. 46760786Sps */ 46860786Sps len += esclen; 46960786Sps } 47060786Sps } 47160786Sps /* 47260786Sps * Allocate and construct the new string. 47360786Sps */ 47460786Sps newstr = p = (char *) ecalloc(len, sizeof(char)); 47560786Sps while (*s != '\0') 47660786Sps { 47760786Sps if (metachar(*s)) 47860786Sps { 47960786Sps /* 48060786Sps * Add the escape char. 48160786Sps */ 48260786Sps strcpy(p, esc); 48360786Sps p += esclen; 48460786Sps } 48560786Sps *p++ = *s++; 48660786Sps } 48760786Sps *p = '\0'; 48860786Sps return (newstr); 48960786Sps} 49060786Sps 49160786Sps#else /* HAVE_SHELL */ 49260786Sps 49360786Sps public char * 49460786Spsesc_metachars(s) 49560786Sps char *s; 49660786Sps{ 49760786Sps return (save(s)); 49860786Sps} 49960786Sps 50060786Sps#endif /* HAVE_SHELL */ 50160786Sps 50260786Sps 50360786Sps#if HAVE_POPEN 50460786Sps 50560786SpsFILE *popen(); 50660786Sps 50760786Sps/* 50860786Sps * Execute a shell command. 50960786Sps * Return a pointer to a pipe connected to the shell command's standard output. 51060786Sps */ 51160786Sps static FILE * 51260786Spsshellcmd(cmd) 51360786Sps char *cmd; 51460786Sps{ 51560786Sps FILE *fd; 51660786Sps 51760786Sps#if HAVE_SHELL 51860786Sps char *shell; 51960786Sps 52060786Sps shell = lgetenv("SHELL"); 52160786Sps if (shell != NULL && *shell != '\0') 52260786Sps { 52360786Sps char *scmd; 52460786Sps char *esccmd; 52560786Sps 52660786Sps /* 52760786Sps * Try to escape any metacharacters in the command. 52860786Sps * If we can't do that, just put the command in quotes. 52960786Sps * (But that doesn't work well if the command itself 53060786Sps * contains quotes.) 53160786Sps */ 53260786Sps if ((esccmd = esc_metachars(cmd)) == NULL) 53360786Sps { 53460786Sps /* 53560786Sps * Cannot escape the metacharacters, so use quotes. 53660786Sps * Read the output of <$SHELL -c "cmd">. 53760786Sps */ 53860786Sps scmd = (char *) ecalloc(strlen(shell) + strlen(cmd) + 7, 53960786Sps sizeof(char)); 54060786Sps sprintf(scmd, "%s -c \"%s\"", shell, cmd); 54160786Sps } else 54260786Sps { 54360786Sps /* 54460786Sps * Read the output of <$SHELL -c cmd>. 54560786Sps * No quotes; use the escaped cmd. 54660786Sps */ 54760786Sps scmd = (char *) ecalloc(strlen(shell) + strlen(esccmd) + 5, 54860786Sps sizeof(char)); 54960786Sps sprintf(scmd, "%s -c %s", shell, esccmd); 55060786Sps free(esccmd); 55160786Sps } 55260786Sps fd = popen(scmd, "r"); 55360786Sps free(scmd); 55460786Sps } else 55560786Sps#endif 55660786Sps { 55760786Sps fd = popen(cmd, "r"); 55860786Sps /* 55960786Sps * Redirection in `popen' might have messed with the 56060786Sps * standard devices. Restore binary input mode. 56160786Sps */ 56260786Sps SET_BINARY(0); 56360786Sps } 56460786Sps return (fd); 56560786Sps} 56660786Sps 56760786Sps#endif /* HAVE_POPEN */ 56860786Sps 56960786Sps 57060786Sps/* 57160786Sps * Expand a filename, doing any system-specific metacharacter substitutions. 57260786Sps */ 57360786Sps public char * 57460786Spslglob(filename) 57560786Sps char *filename; 57660786Sps{ 57760786Sps char *gfilename; 57860786Sps char *ofilename; 57960786Sps 58060786Sps ofilename = fexpand(filename); 58160786Sps if (secure) 58260786Sps return (ofilename); 58360786Sps filename = unquote_file(ofilename); 58460786Sps 58560786Sps#ifdef DECL_GLOB_LIST 58660786Sps{ 58760786Sps /* 58860786Sps * The globbing function returns a list of names. 58960786Sps */ 59060786Sps int length; 59160786Sps char *p; 59260786Sps DECL_GLOB_LIST(list) 59360786Sps 59460786Sps GLOB_LIST(filename, list); 59560786Sps if (GLOB_LIST_FAILED(list)) 59660786Sps { 59760786Sps free(filename); 59860786Sps return (ofilename); 59960786Sps } 60060786Sps length = 1; /* Room for trailing null byte */ 60160786Sps for (SCAN_GLOB_LIST(list, p)) 60260786Sps { 60360786Sps INIT_GLOB_LIST(list, p); 60460786Sps length += strlen(p) + 1; 60560786Sps#if SPACES_IN_FILENAMES 60660786Sps if (strchr(p, ' ') != NULL) 60760786Sps length += 2; /* Allow for quotes */ 60860786Sps#endif 60960786Sps } 61060786Sps gfilename = (char *) ecalloc(length, sizeof(char)); 61160786Sps for (SCAN_GLOB_LIST(list, p)) 61260786Sps { 61360786Sps INIT_GLOB_LIST(list, p); 61460786Sps#if SPACES_IN_FILENAMES 61560786Sps if (strchr(p, ' ') != NULL) 61660786Sps sprintf(gfilename + strlen(gfilename), "%c%s%c ", 61760786Sps openquote, p, closequote); 61860786Sps else 61960786Sps#endif 62060786Sps sprintf(gfilename + strlen(gfilename), "%s ", p); 62160786Sps } 62260786Sps /* 62360786Sps * Overwrite the final trailing space with a null terminator. 62460786Sps */ 62560786Sps *--p = '\0'; 62660786Sps GLOB_LIST_DONE(list); 62760786Sps} 62860786Sps#else 62960786Sps#ifdef DECL_GLOB_NAME 63060786Sps{ 63160786Sps /* 63260786Sps * The globbing function returns a single name, and 63360786Sps * is called multiple times to walk thru all names. 63460786Sps */ 63560786Sps register char *p; 63660786Sps register int len; 63760786Sps register int n; 63860786Sps#if SPACES_IN_FILENAMES 63960786Sps register int spaces_in_file; 64060786Sps#endif 64160786Sps DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) 64260786Sps 64360786Sps GLOB_FIRST_NAME(filename, &fnd, handle); 64460786Sps if (GLOB_FIRST_FAILED(handle)) 64560786Sps { 64660786Sps free(filename); 64760786Sps return (ofilename); 64860786Sps } 64960786Sps 65060786Sps _splitpath(filename, drive, dir, fname, ext); 65160786Sps len = 100; 65260786Sps gfilename = (char *) ecalloc(len, sizeof(char)); 65360786Sps p = gfilename; 65460786Sps do { 65560786Sps n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1; 65660786Sps#if SPACES_IN_FILENAMES 65760786Sps spaces_in_file = 0; 65860786Sps if (strchr(fnd.GLOB_NAME, ' ') != NULL || 65960786Sps strchr(filename, ' ') != NULL) 66060786Sps { 66160786Sps spaces_in_file = 1; 66260786Sps n += 2; 66360786Sps } 66460786Sps#endif 66560786Sps while (p - gfilename + n+2 >= len) 66660786Sps { 66760786Sps /* 66860786Sps * No room in current buffer. Allocate a bigger one. 66960786Sps */ 67060786Sps len *= 2; 67160786Sps *p = '\0'; 67260786Sps p = (char *) ecalloc(len, sizeof(char)); 67360786Sps strcpy(p, gfilename); 67460786Sps free(gfilename); 67560786Sps gfilename = p; 67660786Sps p = gfilename + strlen(gfilename); 67760786Sps } 67860786Sps#if SPACES_IN_FILENAMES 67960786Sps if (spaces_in_file) 68060786Sps sprintf(p, "%c%s%s%s%c ", openquote, 68160786Sps drive, dir, fnd.GLOB_NAME, closequote); 68260786Sps else 68360786Sps#endif 68460786Sps sprintf(p, "%s%s%s ", drive, dir, fnd.GLOB_NAME); 68560786Sps p += n; 68660786Sps } while (GLOB_NEXT_NAME(handle, &fnd) == 0); 68760786Sps 68860786Sps /* 68960786Sps * Overwrite the final trailing space with a null terminator. 69060786Sps */ 69160786Sps *--p = '\0'; 69260786Sps GLOB_NAME_DONE(handle); 69360786Sps} 69460786Sps#else 69560786Sps#if HAVE_POPEN 69660786Sps{ 69760786Sps /* 69860786Sps * We get the shell to glob the filename for us by passing 69960786Sps * an "echo" command to the shell and reading its output. 70060786Sps */ 70160786Sps FILE *fd; 70260786Sps char *s; 70360786Sps char *lessecho; 70460786Sps char *cmd; 70560786Sps 70660786Sps lessecho = lgetenv("LESSECHO"); 70760786Sps if (lessecho == NULL || *lessecho == '\0') 70860786Sps lessecho = "lessecho"; 70960786Sps s = esc_metachars(filename); 71060786Sps if (s == NULL) 71160786Sps { 71260786Sps /* 71360786Sps * There may be dangerous metachars in this name. 71460786Sps * We can't risk passing it to the shell. 71560786Sps * {{ For example, do "!;TAB" when the first file 71660786Sps * in the dir is named "rm". }} 71760786Sps */ 71860786Sps free(filename); 71960786Sps return (ofilename); 72060786Sps } 72160786Sps /* 72260786Sps * Invoke lessecho, and read its output (a globbed list of filenames). 72360786Sps */ 72460786Sps cmd = (char *) ecalloc(strlen(lessecho) + strlen(s) + 24, sizeof(char)); 72560786Sps sprintf(cmd, "%s -p0x%x -d0x%x -- %s", 72660786Sps lessecho, openquote, closequote, s); 72760786Sps fd = shellcmd(cmd); 72860786Sps free(s); 72960786Sps free(cmd); 73060786Sps if (fd == NULL) 73160786Sps { 73260786Sps /* 73360786Sps * Cannot create the pipe. 73460786Sps * Just return the original (fexpanded) filename. 73560786Sps */ 73660786Sps free(filename); 73760786Sps return (ofilename); 73860786Sps } 73960786Sps gfilename = readfd(fd); 74060786Sps pclose(fd); 74160786Sps if (*gfilename == '\0') 74260786Sps { 74360786Sps free(gfilename); 74460786Sps free(filename); 74560786Sps return (ofilename); 74660786Sps } 74760786Sps} 74860786Sps#else 74960786Sps /* 75060786Sps * No globbing functions at all. Just use the fexpanded filename. 75160786Sps */ 75260786Sps gfilename = save(filename); 75360786Sps#endif 75460786Sps#endif 75560786Sps#endif 75660786Sps free(filename); 75760786Sps free(ofilename); 75860786Sps return (gfilename); 75960786Sps} 76060786Sps 76160786Sps/* 76260786Sps * See if we should open a "replacement file" 76360786Sps * instead of the file we're about to open. 76460786Sps */ 76560786Sps public char * 76660786Spsopen_altfile(filename, pf, pfd) 76760786Sps char *filename; 76860786Sps int *pf; 76960786Sps void **pfd; 77060786Sps{ 77160786Sps#if !HAVE_POPEN 77260786Sps return (NULL); 77360786Sps#else 77460786Sps char *lessopen; 77560786Sps char *gfilename; 77660786Sps char *cmd; 77760786Sps FILE *fd; 77860786Sps#if HAVE_FILENO 77960786Sps int returnfd = 0; 78060786Sps#endif 78160786Sps 78260786Sps if (secure) 78360786Sps return (NULL); 78460786Sps ch_ungetchar(-1); 78560786Sps if ((lessopen = lgetenv("LESSOPEN")) == NULL) 78660786Sps return (NULL); 78760786Sps if (strcmp(filename, "-") == 0) 78860786Sps return (NULL); 78960786Sps if (*lessopen == '|') 79060786Sps { 79160786Sps /* 79260786Sps * If LESSOPEN starts with a |, it indicates 79360786Sps * a "pipe preprocessor". 79460786Sps */ 79560786Sps#if HAVE_FILENO 79660786Sps lessopen++; 79760786Sps returnfd = 1; 79860786Sps#else 79960786Sps error("LESSOPEN pipe is not supported", NULL_PARG); 80060786Sps return (NULL); 80160786Sps#endif 80260786Sps } 80360786Sps 80460786Sps gfilename = esc_metachars(filename); 80560786Sps if (gfilename == NULL) 80660786Sps { 80760786Sps /* 80860786Sps * Cannot escape metacharacters. 80960786Sps */ 81060786Sps return (NULL); 81160786Sps } 81260786Sps cmd = (char *) ecalloc(strlen(lessopen) + strlen(gfilename) + 2, 81360786Sps sizeof(char)); 81460786Sps sprintf(cmd, lessopen, gfilename); 81560786Sps fd = shellcmd(cmd); 81660786Sps free(gfilename); 81760786Sps free(cmd); 81860786Sps if (fd == NULL) 81960786Sps { 82060786Sps /* 82160786Sps * Cannot create the pipe. 82260786Sps */ 82360786Sps return (NULL); 82460786Sps } 82560786Sps#if HAVE_FILENO 82660786Sps if (returnfd) 82760786Sps { 82860786Sps int f; 82960786Sps char c; 83060786Sps 83160786Sps /* 83260786Sps * Read one char to see if the pipe will produce any data. 83360786Sps * If it does, push the char back on the pipe. 83460786Sps */ 83560786Sps f = fileno(fd); 83660786Sps SET_BINARY(f); 83760786Sps if (read(f, &c, 1) != 1) 83860786Sps { 83960786Sps /* 84060786Sps * Pipe is empty. This means there is no alt file. 84160786Sps */ 84260786Sps pclose(fd); 84360786Sps return (NULL); 84460786Sps } 84560786Sps ch_ungetchar(c); 84660786Sps *pfd = (void *) fd; 84760786Sps *pf = f; 84860786Sps return (save("-")); 84960786Sps } 85060786Sps#endif 85160786Sps gfilename = readfd(fd); 85260786Sps pclose(fd); 85360786Sps if (*gfilename == '\0') 85460786Sps /* 85560786Sps * Pipe is empty. This means there is no alt file. 85660786Sps */ 85760786Sps return (NULL); 85860786Sps return (gfilename); 85960786Sps#endif /* HAVE_POPEN */ 86060786Sps} 86160786Sps 86260786Sps/* 86360786Sps * Close a replacement file. 86460786Sps */ 86560786Sps public void 86660786Spsclose_altfile(altfilename, filename, pipefd) 86760786Sps char *altfilename; 86860786Sps char *filename; 86960786Sps void *pipefd; 87060786Sps{ 87160786Sps#if HAVE_POPEN 87260786Sps char *lessclose; 87360786Sps char *gfilename; 87460786Sps char *galtfilename; 87560786Sps FILE *fd; 87660786Sps char *cmd; 87760786Sps 87860786Sps if (secure) 87960786Sps return; 88060786Sps if (pipefd != NULL) 88160786Sps pclose((FILE*) pipefd); 88260786Sps if ((lessclose = lgetenv("LESSCLOSE")) == NULL) 88360786Sps return; 88460786Sps gfilename = esc_metachars(filename); 88560786Sps if (gfilename == NULL) 88660786Sps { 88760786Sps return; 88860786Sps } 88960786Sps galtfilename = esc_metachars(altfilename); 89060786Sps if (galtfilename == NULL) 89160786Sps { 89260786Sps free(gfilename); 89360786Sps return; 89460786Sps } 89560786Sps cmd = (char *) ecalloc(strlen(lessclose) + strlen(gfilename) + 89660786Sps strlen(galtfilename) + 2, sizeof(char)); 89760786Sps sprintf(cmd, lessclose, gfilename, galtfilename); 89860786Sps fd = shellcmd(cmd); 89960786Sps free(galtfilename); 90060786Sps free(gfilename); 90160786Sps free(cmd); 90260786Sps if (fd != NULL) 90360786Sps pclose(fd); 90460786Sps#endif 90560786Sps} 90660786Sps 90760786Sps/* 90860786Sps * Is the specified file a directory? 90960786Sps */ 91060786Sps public int 91160786Spsis_dir(filename) 91260786Sps char *filename; 91360786Sps{ 91460786Sps int isdir = 0; 91560786Sps 91660786Sps filename = unquote_file(filename); 91760786Sps#if HAVE_STAT 91860786Sps{ 91960786Sps int r; 92060786Sps struct stat statbuf; 92160786Sps 92260786Sps r = stat(filename, &statbuf); 92360786Sps isdir = (r >= 0 && S_ISDIR(statbuf.st_mode)); 92460786Sps} 92560786Sps#else 92660786Sps#ifdef _OSK 92760786Sps{ 92860786Sps register int f; 92960786Sps 93060786Sps f = open(filename, S_IREAD | S_IFDIR); 93160786Sps if (f >= 0) 93260786Sps close(f); 93360786Sps isdir = (f >= 0); 93460786Sps} 93560786Sps#endif 93660786Sps#endif 93760786Sps free(filename); 93860786Sps return (isdir); 93960786Sps} 94060786Sps 94160786Sps/* 94260786Sps * Returns NULL if the file can be opened and 94360786Sps * is an ordinary file, otherwise an error message 94460786Sps * (if it cannot be opened or is a directory, etc.) 94560786Sps */ 94660786Sps public char * 94760786Spsbad_file(filename) 94860786Sps char *filename; 94960786Sps{ 95060786Sps register char *m = NULL; 95160786Sps 95260786Sps filename = unquote_file(filename); 95360786Sps if (is_dir(filename)) 95460786Sps { 95560786Sps static char is_dir[] = " is a directory"; 95660786Sps 95760786Sps m = (char *) ecalloc(strlen(filename) + sizeof(is_dir), 95860786Sps sizeof(char)); 95960786Sps strcpy(m, filename); 96060786Sps strcat(m, is_dir); 96160786Sps } else 96260786Sps { 96360786Sps#if HAVE_STAT 96460786Sps int r; 96560786Sps struct stat statbuf; 96660786Sps 96760786Sps r = stat(filename, &statbuf); 96860786Sps if (r < 0) 96960786Sps { 97060786Sps m = errno_message(filename); 97160786Sps } else if (force_open) 97260786Sps { 97360786Sps m = NULL; 97460786Sps } else if (!S_ISREG(statbuf.st_mode)) 97560786Sps { 97660786Sps static char not_reg[] = " is not a regular file (use -f to see it)"; 97760786Sps m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), 97860786Sps sizeof(char)); 97960786Sps strcpy(m, filename); 98060786Sps strcat(m, not_reg); 98160786Sps } 98260786Sps#endif 98360786Sps } 98460786Sps free(filename); 98560786Sps return (m); 98660786Sps} 98760786Sps 98860786Sps/* 98960786Sps * Return the size of a file, as cheaply as possible. 99060786Sps * In Unix, we can stat the file. 99160786Sps */ 99260786Sps public POSITION 99360786Spsfilesize(f) 99460786Sps int f; 99560786Sps{ 99660786Sps#if HAVE_STAT 99760786Sps struct stat statbuf; 99860786Sps 99960786Sps if (fstat(f, &statbuf) >= 0) 100060786Sps return ((POSITION) statbuf.st_size); 100160786Sps#else 100260786Sps#ifdef _OSK 100360786Sps long size; 100460786Sps 100560786Sps if ((size = (long) _gs_size(f)) >= 0) 100660786Sps return ((POSITION) size); 100760786Sps#endif 100860786Sps#endif 100960786Sps return (seek_filesize(f)); 101060786Sps} 101160786Sps 1012