[BACK]Return to filename.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Annotation of src/usr.bin/less/filename.c, Revision 1.13

1.1       etheisen    1: /*
1.8       millert     2:  * Copyright (C) 1984-2002  Mark Nudelman
1.1       etheisen    3:  *
1.8       millert     4:  * You may distribute under the terms of either the GNU General Public
                      5:  * License or the Less License, as specified in the README file.
1.1       etheisen    6:  *
1.8       millert     7:  * For more information about less, or for information on how to
                      8:  * contact the author, see the README file.
1.1       etheisen    9:  */
                     10:
                     11:
                     12: /*
                     13:  * Routines to mess around with filenames (and files).
                     14:  * Much of this is very OS dependent.
                     15:  */
                     16:
                     17: #include "less.h"
1.8       millert    18: #include "lglob.h"
                     19: #if MSDOS_COMPILER
1.1       etheisen   20: #include <dos.h>
1.8       millert    21: #if MSDOS_COMPILER==WIN32C && !defined(_MSC_VER)
                     22: #include <dir.h>
                     23: #endif
                     24: #if MSDOS_COMPILER==DJGPPC
                     25: #include <glob.h>
                     26: #include <dir.h>
                     27: #define _MAX_PATH      PATH_MAX
                     28: #endif
                     29: #endif
                     30: #ifdef _OSK
                     31: #include <rbf.h>
                     32: #ifndef _OSK_MWC32
                     33: #include <modes.h>
                     34: #endif
                     35: #endif
                     36: #if OS2
                     37: #include <signal.h>
                     38: #endif
                     39:
                     40: #if HAVE_STAT
                     41: #include <sys/stat.h>
                     42: #ifndef S_ISDIR
                     43: #define        S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
                     44: #endif
                     45: #ifndef S_ISREG
                     46: #define        S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
                     47: #endif
1.1       etheisen   48: #endif
                     49:
1.8       millert    50:
1.1       etheisen   51: extern int force_open;
1.8       millert    52: extern int secure;
                     53: extern int use_lessopen;
1.1       etheisen   54: extern IFILE curr_ifile;
                     55: extern IFILE old_ifile;
1.8       millert    56: #if SPACES_IN_FILENAMES
                     57: extern char openquote;
                     58: extern char closequote;
                     59: #endif
                     60:
                     61: /*
                     62:  * Remove quotes around a filename.
                     63:  */
                     64:        public char *
                     65: shell_unquote(str)
                     66:        char *str;
                     67: {
                     68:        char *name;
                     69:        char *p;
                     70:
                     71:        name = p = (char *) ecalloc(strlen(str)+1, sizeof(char));
                     72:        if (*str == openquote)
                     73:        {
                     74:                str++;
                     75:                while (*str != '\0')
                     76:                {
                     77:                        if (*str == closequote)
                     78:                        {
                     79:                                if (str[1] != closequote)
                     80:                                        break;
                     81:                                str++;
                     82:                        }
                     83:                        *p++ = *str++;
                     84:                }
                     85:        } else
                     86:        {
                     87:                char *esc = get_meta_escape();
                     88:                int esclen = strlen(esc);
                     89:                while (*str != '\0')
                     90:                {
                     91:                        if (esclen > 0 && strncmp(str, esc, esclen) == 0)
                     92:                                str += esclen;
                     93:                        *p++ = *str++;
                     94:                }
                     95:        }
                     96:        *p = '\0';
                     97:        return (name);
                     98: }
                     99:
                    100: /*
                    101:  * Get the shell's escape character.
                    102:  */
                    103:        public char *
                    104: get_meta_escape()
                    105: {
                    106:        char *s;
                    107:
                    108:        s = lgetenv("LESSMETAESCAPE");
                    109:        if (s == NULL)
                    110:                s = DEF_METAESCAPE;
                    111:        return (s);
                    112: }
                    113:
                    114: /*
                    115:  * Get the characters which the shell considers to be "metacharacters".
                    116:  */
                    117:        static char *
                    118: metachars()
                    119: {
                    120:        static char *mchars = NULL;
                    121:
                    122:        if (mchars == NULL)
                    123:        {
                    124:                mchars = lgetenv("LESSMETACHARS");
                    125:                if (mchars == NULL)
                    126:                        mchars = DEF_METACHARS;
                    127:        }
                    128:        return (mchars);
                    129: }
                    130:
                    131: /*
                    132:  * Is this a shell metacharacter?
                    133:  */
                    134:        static int
                    135: metachar(c)
                    136:        char c;
                    137: {
                    138:        return (strchr(metachars(), c) != NULL);
                    139: }
                    140:
                    141: /*
                    142:  * Insert a backslash before each metacharacter in a string.
                    143:  */
                    144:        public char *
                    145: shell_quote(s)
                    146:        char *s;
                    147: {
                    148:        char *p;
                    149:        char *newstr;
                    150:        int len;
                    151:        char *esc = get_meta_escape();
                    152:        int esclen = strlen(esc);
                    153:        int use_quotes = 0;
                    154:        int have_quotes = 0;
                    155:
                    156:        /*
                    157:         * Determine how big a string we need to allocate.
                    158:         */
                    159:        len = 1; /* Trailing null byte */
                    160:        for (p = s;  *p != '\0';  p++)
                    161:        {
                    162:                len++;
                    163:                if (*p == openquote || *p == closequote)
                    164:                        have_quotes = 1;
                    165:                if (metachar(*p))
                    166:                {
                    167:                        if (esclen == 0)
                    168:                        {
                    169:                                /*
                    170:                                 * We've got a metachar, but this shell
                    171:                                 * doesn't support escape chars.  Use quotes.
                    172:                                 */
                    173:                                use_quotes = 1;
                    174:                        } else
                    175:                        {
                    176:                                /*
                    177:                                 * Allow space for the escape char.
                    178:                                 */
                    179:                                len += esclen;
                    180:                        }
                    181:                }
                    182:        }
                    183:        if (use_quotes)
                    184:        {
                    185:                if (have_quotes)
                    186:                        /*
                    187:                         * We can't quote a string that contains quotes.
                    188:                         */
                    189:                        return (NULL);
                    190:                len = strlen(s) + 3;
                    191:        }
                    192:        /*
                    193:         * Allocate and construct the new string.
                    194:         */
                    195:        newstr = p = (char *) ecalloc(len, sizeof(char));
                    196:        if (use_quotes)
                    197:        {
                    198:                snprintf(newstr, len, "%c%s%c", openquote, s, closequote);
                    199:        } else
                    200:        {
                    201:                while (*s != '\0')
                    202:                {
                    203:                        if (metachar(*s))
                    204:                        {
                    205:                                /*
                    206:                                 * Add the escape char.
                    207:                                 */
                    208:                                strlcpy(p, esc, newstr + len - p);
                    209:                                p += esclen;
                    210:                        }
                    211:                        *p++ = *s++;
                    212:                }
                    213:                *p = '\0';
                    214:        }
                    215:        return (newstr);
                    216: }
1.1       etheisen  217:
                    218: /*
                    219:  * Return a pathname that points to a specified file in a specified directory.
                    220:  * Return NULL if the file does not exist in the directory.
                    221:  */
                    222:        static char *
                    223: dirfile(dirname, filename)
                    224:        char *dirname;
                    225:        char *filename;
                    226: {
                    227:        char *pathname;
1.8       millert   228:        char *qpathname;
                    229:        int f;
                    230:        size_t len;
1.1       etheisen  231:
                    232:        if (dirname == NULL || *dirname == '\0')
                    233:                return (NULL);
                    234:        /*
                    235:         * Construct the full pathname.
                    236:         */
1.4       deraadt   237:        len = strlen(dirname) + strlen(filename) + 2;
                    238:        pathname = (char *) calloc(len, sizeof(char));
1.1       etheisen  239:        if (pathname == NULL)
                    240:                return (NULL);
1.8       millert   241:        snprintf(pathname, len, "%s%s%s", dirname, PATHNAME_SEP, filename);
1.1       etheisen  242:        /*
                    243:         * Make sure the file exists.
                    244:         */
1.8       millert   245:        qpathname = shell_unquote(pathname);
                    246:        f = open(qpathname, OPEN_READ);
1.1       etheisen  247:        if (f < 0)
                    248:        {
                    249:                free(pathname);
                    250:                pathname = NULL;
                    251:        } else
                    252:        {
1.8       millert   253:                close(f);
1.1       etheisen  254:        }
1.8       millert   255:        free(qpathname);
1.1       etheisen  256:        return (pathname);
                    257: }
                    258:
                    259: /*
                    260:  * Return the full pathname of the given file in the "home directory".
                    261:  */
                    262:        public char *
                    263: homefile(filename)
                    264:        char *filename;
                    265: {
1.8       millert   266:        register char *pathname;
1.1       etheisen  267:
                    268:        /*
                    269:         * Try $HOME/filename.
                    270:         */
1.8       millert   271:        pathname = dirfile(lgetenv("HOME"), filename);
1.1       etheisen  272:        if (pathname != NULL)
                    273:                return (pathname);
                    274: #if OS2
                    275:        /*
                    276:         * Try $INIT/filename.
                    277:         */
1.8       millert   278:        pathname = dirfile(lgetenv("INIT"), filename);
1.1       etheisen  279:        if (pathname != NULL)
                    280:                return (pathname);
                    281: #endif
1.8       millert   282: #if MSDOS_COMPILER || OS2
1.1       etheisen  283:        /*
                    284:         * Look for the file anywhere on search path.
                    285:         */
                    286:        pathname = (char *) calloc(_MAX_PATH, sizeof(char));
1.8       millert   287: #if MSDOS_COMPILER==DJGPPC
                    288:        {
                    289:                char *res = searchpath(filename);
                    290:                if (res == 0)
                    291:                        *pathname = '\0';
                    292:                else
                    293:                        strlcpy(pathname, res, _MAX_PATH);
                    294:        }
                    295: #else
1.1       etheisen  296:        _searchenv(filename, "PATH", pathname);
1.8       millert   297: #endif
1.1       etheisen  298:        if (*pathname != '\0')
                    299:                return (pathname);
                    300:        free(pathname);
                    301: #endif
                    302:        return (NULL);
                    303: }
                    304:
1.9       millert   305: #ifdef HELPFILE
                    306: /*
                    307:  * Find out where the help file is.
                    308:  */
                    309:        public char *
                    310: find_helpfile()
                    311: {
                    312:        char *helpfile;
                    313:
                    314:        if ((helpfile = getenv("LESSHELP")) != NULL && *helpfile != '\0')
                    315:                return (save(helpfile));
                    316: #if MSDOS_COMPILER || OS2
                    317:        return (homefile(HELPFILE));
                    318: #else
                    319:        return (save(HELPFILE));
                    320: #endif
                    321: }
                    322: #endif
                    323:
1.1       etheisen  324: /*
                    325:  * Expand a string, substituting any "%" with the current filename,
                    326:  * and any "#" with the previous filename.
1.8       millert   327:  * But a string of N "%"s is just replaced with N-1 "%"s.
                    328:  * Likewise for a string of N "#"s.
1.1       etheisen  329:  * {{ This is a lot of work just to support % and #. }}
                    330:  */
                    331:        public char *
                    332: fexpand(s)
                    333:        char *s;
                    334: {
1.8       millert   335:        register char *fr, *to;
                    336:        register int n;
                    337:        register char *e;
                    338:        IFILE ifile;
                    339:
                    340: #define        fchar_ifile(c) \
                    341:        ((c) == '%' ? curr_ifile : \
                    342:         (c) == '#' ? old_ifile : NULL_IFILE)
1.1       etheisen  343:
                    344:        /*
                    345:         * Make one pass to see how big a buffer we
                    346:         * need to allocate for the expanded string.
                    347:         */
                    348:        n = 0;
                    349:        for (fr = s;  *fr != '\0';  fr++)
                    350:        {
                    351:                switch (*fr)
                    352:                {
                    353:                case '%':
1.8       millert   354:                case '#':
                    355:                        if (fr > s && fr[-1] == *fr)
1.1       etheisen  356:                        {
1.8       millert   357:                                /*
                    358:                                 * Second (or later) char in a string
                    359:                                 * of identical chars.  Treat as normal.
                    360:                                 */
                    361:                                n++;
                    362:                        } else if (fr[1] != *fr)
1.1       etheisen  363:                        {
1.8       millert   364:                                /*
                    365:                                 * Single char (not repeated).  Treat specially.
                    366:                                 */
                    367:                                ifile = fchar_ifile(*fr);
                    368:                                if (ifile == NULL_IFILE)
                    369:                                        n++;
                    370:                                else
                    371:                                        n += strlen(get_filename(ifile));
1.1       etheisen  372:                        }
1.8       millert   373:                        /*
                    374:                         * Else it is the first char in a string of
                    375:                         * identical chars.  Just discard it.
                    376:                         */
1.1       etheisen  377:                        break;
                    378:                default:
                    379:                        n++;
                    380:                        break;
                    381:                }
                    382:        }
                    383:
                    384:        e = (char *) ecalloc(n+1, sizeof(char));
                    385:
                    386:        /*
                    387:         * Now copy the string, expanding any "%" or "#".
                    388:         */
                    389:        to = e;
                    390:        for (fr = s;  *fr != '\0';  fr++)
                    391:        {
                    392:                switch (*fr)
                    393:                {
                    394:                case '%':
                    395:                case '#':
1.8       millert   396:                        if (fr > s && fr[-1] == *fr)
                    397:                        {
                    398:                                *to++ = *fr;
                    399:                        } else if (fr[1] != *fr)
                    400:                        {
                    401:                                ifile = fchar_ifile(*fr);
                    402:                                if (ifile == NULL_IFILE)
                    403:                                        *to++ = *fr;
                    404:                                else
                    405:                                {
                    406:                                        strlcpy(to, get_filename(ifile),
                    407:                                            e + n + 1 - to);
                    408:                                        to += strlen(to);
                    409:                                }
                    410:                        }
1.1       etheisen  411:                        break;
                    412:                default:
                    413:                        *to++ = *fr;
                    414:                        break;
                    415:                }
                    416:        }
                    417:        *to = '\0';
                    418:        return (e);
                    419: }
                    420:
                    421: #if TAB_COMPLETE_FILENAME
                    422:
                    423: /*
                    424:  * Return a blank-separated list of filenames which "complete"
                    425:  * the given string.
                    426:  */
                    427:        public char *
                    428: fcomplete(s)
                    429:        char *s;
                    430: {
                    431:        char *fpat;
1.8       millert   432:        char *qs;
                    433:        size_t len;
1.7       deraadt   434:
1.8       millert   435:        if (secure)
                    436:                return (NULL);
1.1       etheisen  437:        /*
                    438:         * Complete the filename "s" by globbing "s*".
                    439:         */
1.8       millert   440: #if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC)
1.1       etheisen  441:        /*
                    442:         * But in DOS, we have to glob "s*.*".
                    443:         * But if the final component of the filename already has
                    444:         * a dot in it, just do "s*".
                    445:         * (Thus, "FILE" is globbed as "FILE*.*",
                    446:         *  but "FILE.A" is globbed as "FILE.A*").
                    447:         */
1.8       millert   448:        {
                    449:                char *slash;
                    450:                for (slash = s+strlen(s)-1;  slash > s;  slash--)
                    451:                        if (*slash == *PATHNAME_SEP || *slash == '/')
                    452:                                break;
                    453:                len = strlen(s) + 4;
                    454:                fpat = (char *) ecalloc(len, sizeof(char));
                    455:                if (strchr(slash, '.') == NULL)
                    456:                        snprintf(fpat, len, "%s*.*", s);
                    457:                else
                    458:                        snprintf(fpat, len, "%s*", s);
                    459:        }
1.1       etheisen  460: #else
1.8       millert   461:        len = strlen(s) + 2;
                    462:        fpat = (char *) ecalloc(len, sizeof(char));
                    463:        snprintf(fpat, len, "%s*", s);
1.1       etheisen  464: #endif
1.8       millert   465:        qs = lglob(fpat);
                    466:        s = shell_unquote(qs);
1.1       etheisen  467:        if (strcmp(s,fpat) == 0)
                    468:        {
                    469:                /*
                    470:                 * The filename didn't expand.
                    471:                 */
1.8       millert   472:                free(qs);
                    473:                qs = NULL;
1.1       etheisen  474:        }
1.8       millert   475:        free(s);
1.1       etheisen  476:        free(fpat);
1.8       millert   477:        return (qs);
1.1       etheisen  478: }
                    479: #endif
                    480:
                    481: /*
                    482:  * Try to determine if a file is "binary".
                    483:  * This is just a guess, and we need not try too hard to make it accurate.
                    484:  */
                    485:        public int
                    486: bin_file(f)
                    487:        int f;
                    488: {
                    489:        int i;
                    490:        int n;
                    491:        unsigned char data[64];
                    492:
                    493:        if (!seekable(f))
                    494:                return (0);
1.11      deraadt   495:        if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK)
1.1       etheisen  496:                return (0);
                    497:        n = read(f, data, sizeof(data));
                    498:        for (i = 0;  i < n;  i++)
                    499:                if (binary_char(data[i]))
                    500:                        return (1);
                    501:        return (0);
                    502: }
                    503:
                    504: /*
                    505:  * Try to determine the size of a file by seeking to the end.
                    506:  */
                    507:        static POSITION
                    508: seek_filesize(f)
                    509:        int f;
                    510: {
                    511:        off_t spos;
                    512:
1.11      deraadt   513:        spos = lseek(f, (off_t)0, SEEK_END);
1.1       etheisen  514:        if (spos == BAD_LSEEK)
                    515:                return (NULL_POSITION);
                    516:        return ((POSITION) spos);
                    517: }
                    518:
                    519: /*
                    520:  * Read a string from a file.
                    521:  * Return a pointer to the string in memory.
                    522:  */
                    523:        static char *
                    524: readfd(fd)
                    525:        FILE *fd;
                    526: {
                    527:        int len;
                    528:        int ch;
                    529:        char *buf;
                    530:        char *p;
                    531:
                    532:        /*
                    533:         * Make a guess about how many chars in the string
                    534:         * and allocate a buffer to hold it.
                    535:         */
                    536:        len = 100;
                    537:        buf = (char *) ecalloc(len, sizeof(char));
                    538:        for (p = buf;  ;  p++)
                    539:        {
                    540:                if ((ch = getc(fd)) == '\n' || ch == EOF)
                    541:                        break;
                    542:                if (p - buf >= len-1)
                    543:                {
                    544:                        /*
                    545:                         * The string is too big to fit in the buffer we have.
                    546:                         * Allocate a new buffer, twice as big.
                    547:                         */
                    548:                        len *= 2;
                    549:                        *p = '\0';
                    550:                        p = (char *) ecalloc(len, sizeof(char));
1.5       deraadt   551:                        strlcpy(p, buf, len);
1.1       etheisen  552:                        free(buf);
                    553:                        buf = p;
                    554:                        p = buf + strlen(buf);
                    555:                }
                    556:                *p = ch;
                    557:        }
                    558:        *p = '\0';
                    559:        return (buf);
                    560: }
                    561:
1.8       millert   562:
                    563:
                    564: #if HAVE_POPEN
                    565:
                    566: FILE *popen();
                    567:
1.1       etheisen  568: /*
                    569:  * Execute a shell command.
                    570:  * Return a pointer to a pipe connected to the shell command's standard output.
                    571:  */
                    572:        static FILE *
1.8       millert   573: shellcmd(cmd)
1.1       etheisen  574:        char *cmd;
                    575: {
                    576:        FILE *fd;
1.8       millert   577:        size_t len;
                    578:
1.1       etheisen  579: #if HAVE_SHELL
1.8       millert   580:        char *shell;
                    581:
                    582:        shell = lgetenv("SHELL");
1.1       etheisen  583:        if (shell != NULL && *shell != '\0')
                    584:        {
1.8       millert   585:                char *scmd;
                    586:                char *esccmd;
                    587:
1.1       etheisen  588:                /*
1.8       millert   589:                 * Read the output of <$SHELL -c cmd>.
                    590:                 * Escape any metacharacters in the command.
1.1       etheisen  591:                 */
1.8       millert   592:                esccmd = shell_quote(cmd);
                    593:                if (esccmd == NULL)
                    594:                {
                    595:                        fd = popen(cmd, "r");
                    596:                } else
                    597:                {
                    598:                        len = strlen(shell) + strlen(esccmd) + 5;
                    599:                        scmd = (char *) ecalloc(len, sizeof(char));
                    600:                        snprintf(scmd, len, "%s %s %s", shell, shell_coption(),
                    601:                            esccmd);
                    602:                        free(esccmd);
                    603:                        fd = popen(scmd, "r");
                    604:                        free(scmd);
                    605:                }
                    606:        } else
                    607: #endif
                    608:        {
                    609:                fd = popen(cmd, "r");
1.1       etheisen  610:        }
1.8       millert   611:        /*
                    612:         * Redirection in `popen' might have messed with the
                    613:         * standard devices.  Restore binary input mode.
                    614:         */
                    615:        SET_BINARY(0);
1.1       etheisen  616:        return (fd);
                    617: }
                    618:
1.8       millert   619: #endif /* HAVE_POPEN */
                    620:
                    621:
1.1       etheisen  622: /*
1.8       millert   623:  * Expand a filename, doing any system-specific metacharacter substitutions.
1.1       etheisen  624:  */
                    625:        public char *
1.8       millert   626: lglob(filename)
1.1       etheisen  627:        char *filename;
                    628: {
                    629:        char *gfilename;
1.8       millert   630:        char *ofilename;
1.1       etheisen  631:
1.8       millert   632:        ofilename = fexpand(filename);
                    633:        if (secure)
                    634:                return (ofilename);
                    635:        filename = shell_unquote(ofilename);
                    636:
                    637: #ifdef DECL_GLOB_LIST
1.1       etheisen  638: {
1.8       millert   639:        /*
                    640:         * The globbing function returns a list of names.
                    641:         */
1.1       etheisen  642:        int length;
1.8       millert   643:        char *p;
                    644:        char *qfilename;
                    645:        DECL_GLOB_LIST(list)
1.1       etheisen  646:
1.8       millert   647:        GLOB_LIST(filename, list);
                    648:        if (GLOB_LIST_FAILED(list))
                    649:        {
                    650:                free(filename);
                    651:                return (ofilename);
                    652:        }
                    653:        length = 1; /* Room for trailing null byte */
                    654:        for (SCAN_GLOB_LIST(list, p))
                    655:        {
                    656:                INIT_GLOB_LIST(list, p);
                    657:                qfilename = shell_quote(p);
                    658:                if (qfilename != NULL)
                    659:                {
                    660:                        length += strlen(qfilename) + 1;
                    661:                        free(qfilename);
                    662:                }
                    663:        }
1.1       etheisen  664:        gfilename = (char *) ecalloc(length, sizeof(char));
1.8       millert   665:        for (SCAN_GLOB_LIST(list, p))
1.1       etheisen  666:        {
1.8       millert   667:                INIT_GLOB_LIST(list, p);
                    668:                qfilename = shell_quote(p);
                    669:                if (qfilename != NULL)
                    670:                {
                    671:                        snprintf(gfilename + strlen(gfilename),
                    672:                            length - strlen(gfilename), "%s ", qfilename);
                    673:                        free(qfilename);
                    674:                }
1.1       etheisen  675:        }
1.8       millert   676:        /*
                    677:         * Overwrite the final trailing space with a null terminator.
                    678:         */
1.13    ! ray       679:        if (gfilename[0] != '\0' && gfilename[strlen(gfilename) - 1] == ' ')
        !           680:                gfilename[strlen(gfilename) - 1] = '\0';
1.8       millert   681:        GLOB_LIST_DONE(list);
1.1       etheisen  682: }
                    683: #else
1.8       millert   684: #ifdef DECL_GLOB_NAME
1.1       etheisen  685: {
1.8       millert   686:        /*
                    687:         * The globbing function returns a single name, and
                    688:         * is called multiple times to walk thru all names.
                    689:         */
                    690:        register char *p;
                    691:        register int len;
                    692:        register int n;
                    693:        char *pathname;
                    694:        char *qpathname;
                    695:        DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle)
                    696:
                    697:        GLOB_FIRST_NAME(filename, &fnd, handle);
                    698:        if (GLOB_FIRST_FAILED(handle))
                    699:        {
                    700:                free(filename);
                    701:                return (ofilename);
                    702:        }
                    703:
                    704:        _splitpath(filename, drive, dir, fname, ext);
                    705:        len = 100;
                    706:        gfilename = (char *) ecalloc(len, sizeof(char));
                    707:        p = gfilename;
                    708:        do {
                    709:                n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1;
                    710:                pathname = (char *) ecalloc(n, sizeof(char));
                    711:                snprintf(pathname, n, "%s%s%s", drive, dir, fnd.GLOB_NAME);
                    712:                qpathname = shell_quote(pathname);
                    713:                free(pathname);
                    714:                if (qpathname != NULL)
                    715:                {
                    716:                        n = strlen(qpathname);
                    717:                        while (p - gfilename + n + 2 >= len)
                    718:                        {
                    719:                                /*
                    720:                                 * No room in current buffer.
                    721:                                 * Allocate a bigger one.
                    722:                                 */
                    723:                                len *= 2;
                    724:                                *p = '\0';
                    725:                                p = (char *) ecalloc(len, sizeof(char));
                    726:                                strlcpy(p, gfilename, len);
                    727:                                free(gfilename);
                    728:                                gfilename = p;
                    729:                                p = gfilename + strlen(gfilename);
                    730:                        }
                    731:                        strlcpy(p, qpathname, gfilename + len - p);
                    732:                        free(qpathname);
                    733:                        p += n;
                    734:                        *p++ = ' ';
                    735:                }
                    736:        } while (GLOB_NEXT_NAME(handle, &fnd) == 0);
                    737:
                    738:        /*
                    739:         * Overwrite the final trailing space with a null terminator.
                    740:         */
                    741:        *--p = '\0';
                    742:        GLOB_NAME_DONE(handle);
                    743: }
                    744: #else
                    745: #if HAVE_POPEN
                    746: {
                    747:        /*
                    748:         * We get the shell to glob the filename for us by passing
                    749:         * an "echo" command to the shell and reading its output.
                    750:         */
1.1       etheisen  751:        FILE *fd;
1.8       millert   752:        char *s;
                    753:        char *lessecho;
                    754:        char *cmd;
                    755:        char *esc;
                    756:        size_t len;
1.1       etheisen  757:
1.8       millert   758:        esc = get_meta_escape();
                    759:        if (strlen(esc) == 0)
                    760:                esc = "-";
                    761:        esc = shell_quote(esc);
                    762:        if (esc == NULL)
                    763:        {
                    764:                free(filename);
                    765:                return (ofilename);
                    766:        }
                    767:        lessecho = lgetenv("LESSECHO");
                    768:        if (lessecho == NULL || *lessecho == '\0')
                    769:                lessecho = "lessecho";
1.1       etheisen  770:        /*
1.8       millert   771:         * Invoke lessecho, and read its output (a globbed list of filenames).
1.1       etheisen  772:         */
1.8       millert   773:        len = strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24;
                    774:        cmd = (char *) ecalloc(len, sizeof(char));
                    775:        snprintf(cmd, len, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote,
                    776:            closequote, esc);
                    777:        free(esc);
                    778:        for (s = metachars();  *s != '\0';  s++)
                    779:                snprintf(cmd + strlen(cmd), len - strlen(cmd), "-n0x%x ", *s);
                    780:        snprintf(cmd + strlen(cmd), len - strlen(cmd), "-- %s", ofilename);
                    781:        fd = shellcmd(cmd);
                    782:        free(cmd);
1.1       etheisen  783:        if (fd == NULL)
                    784:        {
                    785:                /*
                    786:                 * Cannot create the pipe.
                    787:                 * Just return the original (fexpanded) filename.
                    788:                 */
1.8       millert   789:                free(filename);
                    790:                return (ofilename);
1.1       etheisen  791:        }
                    792:        gfilename = readfd(fd);
                    793:        pclose(fd);
                    794:        if (*gfilename == '\0')
                    795:        {
                    796:                free(gfilename);
1.8       millert   797:                free(filename);
                    798:                return (ofilename);
1.1       etheisen  799:        }
                    800: }
1.8       millert   801: #else
                    802:        /*
                    803:         * No globbing functions at all.  Just use the fexpanded filename.
                    804:         */
                    805:        gfilename = save(filename);
                    806: #endif
                    807: #endif
1.1       etheisen  808: #endif
1.8       millert   809:        free(filename);
                    810:        free(ofilename);
1.1       etheisen  811:        return (gfilename);
                    812: }
                    813:
                    814: /*
                    815:  * See if we should open a "replacement file"
                    816:  * instead of the file we're about to open.
                    817:  */
                    818:        public char *
                    819: open_altfile(filename, pf, pfd)
                    820:        char *filename;
                    821:        int *pf;
                    822:        void **pfd;
                    823: {
1.8       millert   824: #if !HAVE_POPEN
                    825:        return (NULL);
                    826: #else
1.1       etheisen  827:        char *lessopen;
1.10      millert   828:        char *cmd, *cp;
1.8       millert   829:        FILE *fd;
1.10      millert   830:        size_t i, len;
                    831:        int found;
1.8       millert   832: #if HAVE_FILENO
1.1       etheisen  833:        int returnfd = 0;
1.8       millert   834: #endif
1.1       etheisen  835:
1.8       millert   836:        if (!use_lessopen || secure)
                    837:                return (NULL);
1.1       etheisen  838:        ch_ungetchar(-1);
1.8       millert   839:        if ((lessopen = lgetenv("LESSOPEN")) == NULL)
1.1       etheisen  840:                return (NULL);
                    841:        if (strcmp(filename, "-") == 0)
                    842:                return (NULL);
                    843:        if (*lessopen == '|')
                    844:        {
                    845:                /*
                    846:                 * If LESSOPEN starts with a |, it indicates
                    847:                 * a "pipe preprocessor".
                    848:                 */
1.8       millert   849: #if HAVE_FILENO
1.1       etheisen  850:                lessopen++;
                    851:                returnfd = 1;
1.8       millert   852: #else
                    853:                error("LESSOPEN pipe is not supported", NULL_PARG);
                    854:                return (NULL);
                    855: #endif
1.1       etheisen  856:        }
1.8       millert   857:
1.10      millert   858:        /* strlen(filename) is guaranteed to be > 0 */
                    859:        len = strlen(lessopen) + strlen(filename);
1.8       millert   860:        cmd = (char *) ecalloc(len, sizeof(char));
1.10      millert   861:        for (cp = cmd, i = 0, found = 0; i < strlen(lessopen); i++) {
                    862:                if (!found && lessopen[i] == '%' && lessopen[i + 1] == 's') {
                    863:                        found = 1;
                    864:                        strlcat(cmd, filename, len);
                    865:                        cp += strlen(filename);
                    866:                        i++;
                    867:                } else
                    868:                        *cp++ = lessopen[i];
                    869:        }
1.8       millert   870:        fd = shellcmd(cmd);
                    871:        free(cmd);
1.1       etheisen  872:        if (fd == NULL)
                    873:        {
                    874:                /*
                    875:                 * Cannot create the pipe.
                    876:                 */
                    877:                return (NULL);
                    878:        }
1.8       millert   879: #if HAVE_FILENO
1.1       etheisen  880:        if (returnfd)
                    881:        {
                    882:                int f;
                    883:                char c;
                    884:
                    885:                /*
                    886:                 * Read one char to see if the pipe will produce any data.
                    887:                 * If it does, push the char back on the pipe.
                    888:                 */
                    889:                f = fileno(fd);
1.8       millert   890:                SET_BINARY(f);
1.1       etheisen  891:                if (read(f, &c, 1) != 1)
                    892:                {
                    893:                        /*
                    894:                         * Pipe is empty.  This means there is no alt file.
                    895:                         */
                    896:                        pclose(fd);
                    897:                        return (NULL);
                    898:                }
                    899:                ch_ungetchar(c);
                    900:                *pfd = (void *) fd;
                    901:                *pf = f;
                    902:                return (save("-"));
1.8       millert   903:        }
1.1       etheisen  904: #endif
1.8       millert   905:        cmd = readfd(fd);
1.1       etheisen  906:        pclose(fd);
1.8       millert   907:        if (*cmd == '\0')
1.1       etheisen  908:                /*
                    909:                 * Pipe is empty.  This means there is no alt file.
                    910:                 */
                    911:                return (NULL);
1.8       millert   912:        return (cmd);
                    913: #endif /* HAVE_POPEN */
1.1       etheisen  914: }
                    915:
                    916: /*
                    917:  * Close a replacement file.
                    918:  */
                    919:        public void
                    920: close_altfile(altfilename, filename, pipefd)
                    921:        char *altfilename;
                    922:        char *filename;
                    923:        void *pipefd;
                    924: {
1.8       millert   925: #if HAVE_POPEN
1.1       etheisen  926:        char *lessclose;
                    927:        FILE *fd;
1.10      millert   928:        char *cmd, *cp;
                    929:        size_t i, len;
                    930:        int found;
1.1       etheisen  931:
1.8       millert   932:        if (secure)
                    933:                return;
1.1       etheisen  934:        if (pipefd != NULL)
1.8       millert   935:        {
                    936: #if OS2
                    937:                /*
                    938:                 * The pclose function of OS/2 emx sometimes fails.
                    939:                 * Send SIGINT to the piped process before closing it.
                    940:                 */
                    941:                kill(((FILE*)pipefd)->_pid, SIGINT);
                    942: #endif
1.1       etheisen  943:                pclose((FILE*) pipefd);
1.8       millert   944:        }
                    945:        if ((lessclose = lgetenv("LESSCLOSE")) == NULL)
1.1       etheisen  946:                return;
1.10      millert   947:        /* strlen(filename) is guaranteed to be > 0 */
                    948:        len = strlen(lessclose) + strlen(filename) + strlen(altfilename);
1.8       millert   949:        cmd = (char *) ecalloc(len, sizeof(char));
1.10      millert   950:        for (cp = cmd, i = 0, found = 0; i < strlen(lessclose); i++) {
                    951:                if (found < 2 && lessclose[i] == '%' && lessclose[i + 1] == 's') {
                    952:                        if (++found == 1) {
                    953:                                strlcat(cmd, filename, len);
                    954:                                cp += strlen(filename);
                    955:                        } else {
                    956:                                strlcat(cmd, altfilename, len);
                    957:                                cp += strlen(altfilename);
                    958:                        }
                    959:                        i++;
                    960:                } else
                    961:                        *cp++ = lessclose[i];
                    962:        }
1.8       millert   963:        fd = shellcmd(cmd);
                    964:        free(cmd);
                    965:        if (fd != NULL)
                    966:                pclose(fd);
                    967: #endif
1.1       etheisen  968: }
                    969:
1.8       millert   970: /*
                    971:  * Is the specified file a directory?
                    972:  */
                    973:        public int
                    974: is_dir(filename)
1.1       etheisen  975:        char *filename;
                    976: {
1.8       millert   977:        int isdir = 0;
                    978:
                    979:        filename = shell_unquote(filename);
                    980: #if HAVE_STAT
1.1       etheisen  981: {
1.8       millert   982:        int r;
                    983:        struct stat statbuf;
1.1       etheisen  984:
1.8       millert   985:        r = stat(filename, &statbuf);
                    986:        isdir = (r >= 0 && S_ISDIR(statbuf.st_mode));
1.1       etheisen  987: }
                    988: #else
1.8       millert   989: #ifdef _OSK
1.1       etheisen  990: {
1.8       millert   991:        register int f;
1.1       etheisen  992:
1.8       millert   993:        f = open(filename, S_IREAD | S_IFDIR);
                    994:        if (f >= 0)
                    995:                close(f);
                    996:        isdir = (f >= 0);
1.1       etheisen  997: }
                    998: #endif
                    999: #endif
1.8       millert  1000:        free(filename);
                   1001:        return (isdir);
                   1002: }
1.1       etheisen 1003:
                   1004: /*
                   1005:  * Returns NULL if the file can be opened and
                   1006:  * is an ordinary file, otherwise an error message
                   1007:  * (if it cannot be opened or is a directory, etc.)
                   1008:  */
                   1009:        public char *
                   1010: bad_file(filename)
                   1011:        char *filename;
                   1012: {
1.8       millert  1013:        register char *m = NULL;
                   1014:        size_t len;
1.1       etheisen 1015:
1.8       millert  1016:        filename = shell_unquote(filename);
                   1017:        if (is_dir(filename))
1.1       etheisen 1018:        {
1.8       millert  1019:                static char is_a_dir[] = " is a directory";
1.5       deraadt  1020:
1.8       millert  1021:                len = strlen(filename) + sizeof(is_a_dir);
1.5       deraadt  1022:                m = (char *) ecalloc(len, sizeof(char));
                   1023:                strlcpy(m, filename, len);
1.8       millert  1024:                strlcat(m, is_a_dir, len);
                   1025:        } else
1.1       etheisen 1026:        {
1.8       millert  1027: #if HAVE_STAT
                   1028:                int r;
                   1029:                struct stat statbuf;
1.5       deraadt  1030:
1.8       millert  1031:                r = stat(filename, &statbuf);
                   1032:                if (r < 0)
                   1033:                {
                   1034:                        m = errno_message(filename);
                   1035:                } else if (force_open)
                   1036:                {
                   1037:                        m = NULL;
                   1038:                } else if (!S_ISREG(statbuf.st_mode))
                   1039:                {
                   1040:                        static char not_reg[] = " is not a regular file (use -f to see it)";
                   1041:                        len = strlen(filename) + sizeof(not_reg);
                   1042:                        m = (char *) ecalloc(len, sizeof(char));
                   1043:                        strlcpy(m, filename, len);
                   1044:                        strlcat(m, not_reg, len);
                   1045:                }
                   1046: #endif
1.1       etheisen 1047:        }
1.8       millert  1048:        free(filename);
                   1049:        return (m);
1.1       etheisen 1050: }
                   1051:
                   1052: /*
                   1053:  * Return the size of a file, as cheaply as possible.
                   1054:  * In Unix, we can stat the file.
                   1055:  */
                   1056:        public POSITION
                   1057: filesize(f)
                   1058:        int f;
                   1059: {
1.8       millert  1060: #if HAVE_STAT
1.1       etheisen 1061:        struct stat statbuf;
                   1062:
1.8       millert  1063:        if (fstat(f, &statbuf) >= 0)
                   1064:                return ((POSITION) statbuf.st_size);
                   1065: #else
                   1066: #ifdef _OSK
                   1067:        long size;
1.1       etheisen 1068:
1.8       millert  1069:        if ((size = (long) _gs_size(f)) >= 0)
                   1070:                return ((POSITION) size);
                   1071: #endif
                   1072: #endif
                   1073:        return (seek_filesize(f));
1.1       etheisen 1074: }
                   1075:
                   1076: /*
1.8       millert  1077:  *
1.1       etheisen 1078:  */
                   1079:        public char *
1.8       millert  1080: shell_coption()
1.1       etheisen 1081: {
1.8       millert  1082:        return ("-c");
1.1       etheisen 1083: }