diff options
author | delphij <delphij@FreeBSD.org> | 2009-05-08 23:34:35 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2009-05-08 23:34:35 +0000 |
commit | d069efd47cacc3156036ed37d5532d6a1d4f55c3 (patch) | |
tree | 2526f6b109843b646672c1537476dc51e56c0454 /contrib/less/filename.c | |
parent | 6aa3e25391d160482339ee072c010bcd22dfbbd1 (diff) | |
download | FreeBSD-src-d069efd47cacc3156036ed37d5532d6a1d4f55c3.zip FreeBSD-src-d069efd47cacc3156036ed37d5532d6a1d4f55c3.tar.gz |
Flatten all tags of the dist tree of less.
Diffstat (limited to 'contrib/less/filename.c')
-rw-r--r-- | contrib/less/filename.c | 1048 |
1 files changed, 0 insertions, 1048 deletions
diff --git a/contrib/less/filename.c b/contrib/less/filename.c deleted file mode 100644 index aa45b76..0000000 --- a/contrib/less/filename.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - * Copyright (C) 1984-2007 Mark Nudelman - * - * You may distribute under the terms of either the GNU General Public - * License or the Less License, as specified in the README file. - * - * For more information about less, or for information on how to - * contact the author, see the README file. - */ - - -/* - * Routines to mess around with filenames (and files). - * Much of this is very OS dependent. - */ - -#include "less.h" -#include "lglob.h" -#if MSDOS_COMPILER -#include <dos.h> -#if MSDOS_COMPILER==WIN32C && !defined(_MSC_VER) -#include <dir.h> -#endif -#if MSDOS_COMPILER==DJGPPC -#include <glob.h> -#include <dir.h> -#define _MAX_PATH PATH_MAX -#endif -#endif -#ifdef _OSK -#include <rbf.h> -#ifndef _OSK_MWC32 -#include <modes.h> -#endif -#endif -#if OS2 -#include <signal.h> -#endif - -#if HAVE_STAT -#include <sys/stat.h> -#ifndef S_ISDIR -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif -#ifndef S_ISREG -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif -#endif - - -extern int force_open; -extern int secure; -extern int use_lessopen; -extern int ctldisp; -extern IFILE curr_ifile; -extern IFILE old_ifile; -#if SPACES_IN_FILENAMES -extern char openquote; -extern char closequote; -#endif - -/* - * Remove quotes around a filename. - */ - public char * -shell_unquote(str) - char *str; -{ - char *name; - char *p; - - name = p = (char *) ecalloc(strlen(str)+1, sizeof(char)); - if (*str == openquote) - { - str++; - while (*str != '\0') - { - if (*str == closequote) - { - if (str[1] != closequote) - break; - str++; - } - *p++ = *str++; - } - } else - { - char *esc = get_meta_escape(); - int esclen = strlen(esc); - while (*str != '\0') - { - if (esclen > 0 && strncmp(str, esc, esclen) == 0) - str += esclen; - *p++ = *str++; - } - } - *p = '\0'; - return (name); -} - -/* - * Get the shell's escape character. - */ - public char * -get_meta_escape() -{ - char *s; - - s = lgetenv("LESSMETAESCAPE"); - if (s == NULL) - s = DEF_METAESCAPE; - return (s); -} - -/* - * Get the characters which the shell considers to be "metacharacters". - */ - static char * -metachars() -{ - static char *mchars = NULL; - - if (mchars == NULL) - { - mchars = lgetenv("LESSMETACHARS"); - if (mchars == NULL) - mchars = DEF_METACHARS; - } - return (mchars); -} - -/* - * Is this a shell metacharacter? - */ - static int -metachar(c) - char c; -{ - return (strchr(metachars(), c) != NULL); -} - -/* - * Insert a backslash before each metacharacter in a string. - */ - public char * -shell_quote(s) - char *s; -{ - char *p; - char *newstr; - int len; - char *esc = get_meta_escape(); - int esclen = strlen(esc); - int use_quotes = 0; - int have_quotes = 0; - - /* - * Determine how big a string we need to allocate. - */ - len = 1; /* Trailing null byte */ - for (p = s; *p != '\0'; p++) - { - len++; - if (*p == openquote || *p == closequote) - have_quotes = 1; - if (metachar(*p)) - { - if (esclen == 0) - { - /* - * We've got a metachar, but this shell - * doesn't support escape chars. Use quotes. - */ - use_quotes = 1; - } else - { - /* - * Allow space for the escape char. - */ - len += esclen; - } - } - } - if (use_quotes) - { - if (have_quotes) - /* - * We can't quote a string that contains quotes. - */ - return (NULL); - len = strlen(s) + 3; - } - /* - * Allocate and construct the new string. - */ - newstr = p = (char *) ecalloc(len, sizeof(char)); - if (use_quotes) - { - SNPRINTF3(newstr, len, "%c%s%c", openquote, s, closequote); - } else - { - while (*s != '\0') - { - if (metachar(*s)) - { - /* - * Add the escape char. - */ - strcpy(p, esc); - p += esclen; - } - *p++ = *s++; - } - *p = '\0'; - } - return (newstr); -} - -/* - * Return a pathname that points to a specified file in a specified directory. - * Return NULL if the file does not exist in the directory. - */ - static char * -dirfile(dirname, filename) - char *dirname; - char *filename; -{ - char *pathname; - char *qpathname; - int len; - int f; - - if (dirname == NULL || *dirname == '\0') - return (NULL); - /* - * Construct the full pathname. - */ - len= strlen(dirname) + strlen(filename) + 2; - pathname = (char *) calloc(len, sizeof(char)); - if (pathname == NULL) - return (NULL); - SNPRINTF3(pathname, len, "%s%s%s", dirname, PATHNAME_SEP, filename); - /* - * Make sure the file exists. - */ - qpathname = shell_unquote(pathname); - f = open(qpathname, OPEN_READ); - if (f < 0) - { - free(pathname); - pathname = NULL; - } else - { - close(f); - } - free(qpathname); - return (pathname); -} - -/* - * Return the full pathname of the given file in the "home directory". - */ - public char * -homefile(filename) - char *filename; -{ - register char *pathname; - - /* - * Try $HOME/filename. - */ - pathname = dirfile(lgetenv("HOME"), filename); - if (pathname != NULL) - return (pathname); -#if OS2 - /* - * Try $INIT/filename. - */ - pathname = dirfile(lgetenv("INIT"), filename); - if (pathname != NULL) - return (pathname); -#endif -#if MSDOS_COMPILER || OS2 - /* - * Look for the file anywhere on search path. - */ - pathname = (char *) calloc(_MAX_PATH, sizeof(char)); -#if MSDOS_COMPILER==DJGPPC - { - char *res = searchpath(filename); - if (res == 0) - *pathname = '\0'; - else - strcpy(pathname, res); - } -#else - _searchenv(filename, "PATH", pathname); -#endif - if (*pathname != '\0') - return (pathname); - free(pathname); -#endif - return (NULL); -} - -/* - * Expand a string, substituting any "%" with the current filename, - * and any "#" with the previous filename. - * But a string of N "%"s is just replaced with N-1 "%"s. - * Likewise for a string of N "#"s. - * {{ This is a lot of work just to support % and #. }} - */ - public char * -fexpand(s) - char *s; -{ - register char *fr, *to; - register int n; - register char *e; - IFILE ifile; - -#define fchar_ifile(c) \ - ((c) == '%' ? curr_ifile : \ - (c) == '#' ? old_ifile : NULL_IFILE) - - /* - * Make one pass to see how big a buffer we - * need to allocate for the expanded string. - */ - n = 0; - for (fr = s; *fr != '\0'; fr++) - { - switch (*fr) - { - case '%': - case '#': - if (fr > s && fr[-1] == *fr) - { - /* - * Second (or later) char in a string - * of identical chars. Treat as normal. - */ - n++; - } else if (fr[1] != *fr) - { - /* - * Single char (not repeated). Treat specially. - */ - ifile = fchar_ifile(*fr); - if (ifile == NULL_IFILE) - n++; - else - n += strlen(get_filename(ifile)); - } - /* - * Else it is the first char in a string of - * identical chars. Just discard it. - */ - break; - default: - n++; - break; - } - } - - e = (char *) ecalloc(n+1, sizeof(char)); - - /* - * Now copy the string, expanding any "%" or "#". - */ - to = e; - for (fr = s; *fr != '\0'; fr++) - { - switch (*fr) - { - case '%': - case '#': - if (fr > s && fr[-1] == *fr) - { - *to++ = *fr; - } else if (fr[1] != *fr) - { - ifile = fchar_ifile(*fr); - if (ifile == NULL_IFILE) - *to++ = *fr; - else - { - strcpy(to, get_filename(ifile)); - to += strlen(to); - } - } - break; - default: - *to++ = *fr; - break; - } - } - *to = '\0'; - return (e); -} - -#if TAB_COMPLETE_FILENAME - -/* - * Return a blank-separated list of filenames which "complete" - * the given string. - */ - public char * -fcomplete(s) - char *s; -{ - char *fpat; - char *qs; - - if (secure) - return (NULL); - /* - * Complete the filename "s" by globbing "s*". - */ -#if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC) - /* - * But in DOS, we have to glob "s*.*". - * But if the final component of the filename already has - * a dot in it, just do "s*". - * (Thus, "FILE" is globbed as "FILE*.*", - * but "FILE.A" is globbed as "FILE.A*"). - */ - { - char *slash; - int len; - for (slash = s+strlen(s)-1; slash > s; slash--) - if (*slash == *PATHNAME_SEP || *slash == '/') - break; - len = strlen(s) + 4; - fpat = (char *) ecalloc(len, sizeof(char)); - if (strchr(slash, '.') == NULL) - SNPRINTF1(fpat, len, "%s*.*", s); - else - SNPRINTF1(fpat, len, "%s*", s); - } -#else - { - int len = strlen(s) + 2; - fpat = (char *) ecalloc(len, sizeof(char)); - SNPRINTF1(fpat, len, "%s*", s); - } -#endif - qs = lglob(fpat); - s = shell_unquote(qs); - if (strcmp(s,fpat) == 0) - { - /* - * The filename didn't expand. - */ - free(qs); - qs = NULL; - } - free(s); - free(fpat); - return (qs); -} -#endif - -/* - * Try to determine if a file is "binary". - * This is just a guess, and we need not try too hard to make it accurate. - */ - public int -bin_file(f) - int f; -{ - int i; - int n; - int bin_count = 0; - unsigned char data[256]; - - if (!seekable(f)) - return (0); - if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK) - return (0); - n = read(f, data, sizeof(data)); - for (i = 0; i < n; i++) - { - char c = data[i]; - if (ctldisp == OPT_ONPLUS && IS_CSI_START(c)) - { - while (++i < n && is_ansi_middle(data[i])) - continue; - } else if (binary_char(c)) - bin_count++; - } - /* - * Call it a binary file if there are more than 5 binary characters - * in the first 256 bytes of the file. - */ - return (bin_count > 5); -} - -/* - * Try to determine the size of a file by seeking to the end. - */ - static POSITION -seek_filesize(f) - int f; -{ - off_t spos; - - spos = lseek(f, (off_t)0, SEEK_END); - if (spos == BAD_LSEEK) - return (NULL_POSITION); - return ((POSITION) spos); -} - -/* - * Read a string from a file. - * Return a pointer to the string in memory. - */ - static char * -readfd(fd) - FILE *fd; -{ - int len; - int ch; - char *buf; - char *p; - - /* - * Make a guess about how many chars in the string - * and allocate a buffer to hold it. - */ - len = 100; - buf = (char *) ecalloc(len, sizeof(char)); - for (p = buf; ; p++) - { - if ((ch = getc(fd)) == '\n' || ch == EOF) - break; - if (p - buf >= len-1) - { - /* - * The string is too big to fit in the buffer we have. - * Allocate a new buffer, twice as big. - */ - len *= 2; - *p = '\0'; - p = (char *) ecalloc(len, sizeof(char)); - strcpy(p, buf); - free(buf); - buf = p; - p = buf + strlen(buf); - } - *p = ch; - } - *p = '\0'; - return (buf); -} - - - -#if HAVE_POPEN - -FILE *popen(); - -/* - * Execute a shell command. - * Return a pointer to a pipe connected to the shell command's standard output. - */ - static FILE * -shellcmd(cmd) - char *cmd; -{ - FILE *fd; - -#if HAVE_SHELL - char *shell; - - shell = lgetenv("SHELL"); - if (shell != NULL && *shell != '\0') - { - char *scmd; - char *esccmd; - - /* - * Read the output of <$SHELL -c cmd>. - * Escape any metacharacters in the command. - */ - esccmd = shell_quote(cmd); - if (esccmd == NULL) - { - fd = popen(cmd, "r"); - } else - { - int len = strlen(shell) + strlen(esccmd) + 5; - scmd = (char *) ecalloc(len, sizeof(char)); - SNPRINTF3(scmd, len, "%s %s %s", shell, shell_coption(), esccmd); - free(esccmd); - fd = popen(scmd, "r"); - free(scmd); - } - } else -#endif - { - fd = popen(cmd, "r"); - } - /* - * Redirection in `popen' might have messed with the - * standard devices. Restore binary input mode. - */ - SET_BINARY(0); - return (fd); -} - -#endif /* HAVE_POPEN */ - - -/* - * Expand a filename, doing any system-specific metacharacter substitutions. - */ - public char * -lglob(filename) - char *filename; -{ - char *gfilename; - char *ofilename; - - ofilename = fexpand(filename); - if (secure) - return (ofilename); - filename = shell_unquote(ofilename); - -#ifdef DECL_GLOB_LIST -{ - /* - * The globbing function returns a list of names. - */ - int length; - char *p; - char *qfilename; - DECL_GLOB_LIST(list) - - GLOB_LIST(filename, list); - if (GLOB_LIST_FAILED(list)) - { - free(filename); - return (ofilename); - } - length = 1; /* Room for trailing null byte */ - for (SCAN_GLOB_LIST(list, p)) - { - INIT_GLOB_LIST(list, p); - qfilename = shell_quote(p); - if (qfilename != NULL) - { - length += strlen(qfilename) + 1; - free(qfilename); - } - } - gfilename = (char *) ecalloc(length, sizeof(char)); - for (SCAN_GLOB_LIST(list, p)) - { - INIT_GLOB_LIST(list, p); - qfilename = shell_quote(p); - if (qfilename != NULL) - { - sprintf(gfilename + strlen(gfilename), "%s ", qfilename); - free(qfilename); - } - } - /* - * Overwrite the final trailing space with a null terminator. - */ - *--p = '\0'; - GLOB_LIST_DONE(list); -} -#else -#ifdef DECL_GLOB_NAME -{ - /* - * The globbing function returns a single name, and - * is called multiple times to walk thru all names. - */ - register char *p; - register int len; - register int n; - char *pathname; - char *qpathname; - DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) - - GLOB_FIRST_NAME(filename, &fnd, handle); - if (GLOB_FIRST_FAILED(handle)) - { - free(filename); - return (ofilename); - } - - _splitpath(filename, drive, dir, fname, ext); - len = 100; - gfilename = (char *) ecalloc(len, sizeof(char)); - p = gfilename; - do { - n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1; - pathname = (char *) ecalloc(n, sizeof(char)); - SNPRINTF3(pathname, n, "%s%s%s", drive, dir, fnd.GLOB_NAME); - qpathname = shell_quote(pathname); - free(pathname); - if (qpathname != NULL) - { - n = strlen(qpathname); - while (p - gfilename + n + 2 >= len) - { - /* - * No room in current buffer. - * Allocate a bigger one. - */ - len *= 2; - *p = '\0'; - p = (char *) ecalloc(len, sizeof(char)); - strcpy(p, gfilename); - free(gfilename); - gfilename = p; - p = gfilename + strlen(gfilename); - } - strcpy(p, qpathname); - free(qpathname); - p += n; - *p++ = ' '; - } - } while (GLOB_NEXT_NAME(handle, &fnd) == 0); - - /* - * Overwrite the final trailing space with a null terminator. - */ - *--p = '\0'; - GLOB_NAME_DONE(handle); -} -#else -#if HAVE_POPEN -{ - /* - * We get the shell to glob the filename for us by passing - * an "echo" command to the shell and reading its output. - */ - FILE *fd; - char *s; - char *lessecho; - char *cmd; - char *esc; - int len; - - esc = get_meta_escape(); - if (strlen(esc) == 0) - esc = "-"; - esc = shell_quote(esc); - if (esc == NULL) - { - free(filename); - return (ofilename); - } - lessecho = lgetenv("LESSECHO"); - if (lessecho == NULL || *lessecho == '\0') - lessecho = "lessecho"; - /* - * Invoke lessecho, and read its output (a globbed list of filenames). - */ - len = strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24; - cmd = (char *) ecalloc(len, sizeof(char)); - SNPRINTF4(cmd, len, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote, closequote, esc); - free(esc); - for (s = metachars(); *s != '\0'; s++) - sprintf(cmd + strlen(cmd), "-n0x%x ", *s); - sprintf(cmd + strlen(cmd), "-- %s", ofilename); - fd = shellcmd(cmd); - free(cmd); - if (fd == NULL) - { - /* - * Cannot create the pipe. - * Just return the original (fexpanded) filename. - */ - free(filename); - return (ofilename); - } - gfilename = readfd(fd); - pclose(fd); - if (*gfilename == '\0') - { - free(gfilename); - free(filename); - return (ofilename); - } -} -#else - /* - * No globbing functions at all. Just use the fexpanded filename. - */ - gfilename = save(filename); -#endif -#endif -#endif - free(filename); - free(ofilename); - return (gfilename); -} - -/* - * See if we should open a "replacement file" - * instead of the file we're about to open. - */ - public char * -open_altfile(filename, pf, pfd) - char *filename; - int *pf; - void **pfd; -{ -#if !HAVE_POPEN - return (NULL); -#else - char *lessopen; - char *cmd; - int len; - FILE *fd; -#if HAVE_FILENO - int returnfd = 0; -#endif - - if (!use_lessopen || secure) - return (NULL); - ch_ungetchar(-1); - if ((lessopen = lgetenv("LESSOPEN")) == NULL) - return (NULL); - if (strcmp(filename, "-") == 0) - return (NULL); - if (*lessopen == '|') - { - /* - * If LESSOPEN starts with a |, it indicates - * a "pipe preprocessor". - */ -#if HAVE_FILENO - lessopen++; - returnfd = 1; -#else - error("LESSOPEN pipe is not supported", NULL_PARG); - return (NULL); -#endif - } - - len = strlen(lessopen) + strlen(filename) + 2; - cmd = (char *) ecalloc(len, sizeof(char)); - SNPRINTF1(cmd, len, lessopen, filename); - fd = shellcmd(cmd); - free(cmd); - if (fd == NULL) - { - /* - * Cannot create the pipe. - */ - return (NULL); - } -#if HAVE_FILENO - if (returnfd) - { - int f; - char c; - - /* - * Read one char to see if the pipe will produce any data. - * If it does, push the char back on the pipe. - */ - f = fileno(fd); - SET_BINARY(f); - if (read(f, &c, 1) != 1) - { - /* - * Pipe is empty. This means there is no alt file. - */ - pclose(fd); - return (NULL); - } - ch_ungetchar(c); - *pfd = (void *) fd; - *pf = f; - return (save("-")); - } -#endif - cmd = readfd(fd); - pclose(fd); - if (*cmd == '\0') - /* - * Pipe is empty. This means there is no alt file. - */ - return (NULL); - return (cmd); -#endif /* HAVE_POPEN */ -} - -/* - * Close a replacement file. - */ - public void -close_altfile(altfilename, filename, pipefd) - char *altfilename; - char *filename; - void *pipefd; -{ -#if HAVE_POPEN - char *lessclose; - FILE *fd; - char *cmd; - int len; - - if (secure) - return; - if (pipefd != NULL) - { -#if OS2 - /* - * The pclose function of OS/2 emx sometimes fails. - * Send SIGINT to the piped process before closing it. - */ - kill(((FILE*)pipefd)->_pid, SIGINT); -#endif - pclose((FILE*) pipefd); - } - if ((lessclose = lgetenv("LESSCLOSE")) == NULL) - return; - len = strlen(lessclose) + strlen(filename) + strlen(altfilename) + 2; - cmd = (char *) ecalloc(len, sizeof(char)); - SNPRINTF2(cmd, len, lessclose, filename, altfilename); - fd = shellcmd(cmd); - free(cmd); - if (fd != NULL) - pclose(fd); -#endif -} - -/* - * Is the specified file a directory? - */ - public int -is_dir(filename) - char *filename; -{ - int isdir = 0; - - filename = shell_unquote(filename); -#if HAVE_STAT -{ - int r; - struct stat statbuf; - - r = stat(filename, &statbuf); - isdir = (r >= 0 && S_ISDIR(statbuf.st_mode)); -} -#else -#ifdef _OSK -{ - register int f; - - f = open(filename, S_IREAD | S_IFDIR); - if (f >= 0) - close(f); - isdir = (f >= 0); -} -#endif -#endif - free(filename); - return (isdir); -} - -/* - * Returns NULL if the file can be opened and - * is an ordinary file, otherwise an error message - * (if it cannot be opened or is a directory, etc.) - */ - public char * -bad_file(filename) - char *filename; -{ - register char *m = NULL; - - filename = shell_unquote(filename); - if (!force_open && is_dir(filename)) - { - static char is_a_dir[] = " is a directory"; - - m = (char *) ecalloc(strlen(filename) + sizeof(is_a_dir), - sizeof(char)); - strcpy(m, filename); - strcat(m, is_a_dir); - } else - { -#if HAVE_STAT - int r; - struct stat statbuf; - - r = stat(filename, &statbuf); - if (r < 0) - { - m = errno_message(filename); - } else if (force_open) - { - m = NULL; - } else if (!S_ISREG(statbuf.st_mode)) - { - static char not_reg[] = " is not a regular file (use -f to see it)"; - m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), - sizeof(char)); - strcpy(m, filename); - strcat(m, not_reg); - } -#endif - } - free(filename); - return (m); -} - -/* - * Return the size of a file, as cheaply as possible. - * In Unix, we can stat the file. - */ - public POSITION -filesize(f) - int f; -{ -#if HAVE_STAT - struct stat statbuf; - - if (fstat(f, &statbuf) >= 0) - return ((POSITION) statbuf.st_size); -#else -#ifdef _OSK - long size; - - if ((size = (long) _gs_size(f)) >= 0) - return ((POSITION) size); -#endif -#endif - return (seek_filesize(f)); -} - -/* - * - */ - public char * -shell_coption() -{ - return ("-c"); -} |