[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.14

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:
1.14    ! deraadt   259: #ifndef SMALL_PROGRAM
1.1       etheisen  260: /*
                    261:  * Return the full pathname of the given file in the "home directory".
                    262:  */
                    263:        public char *
                    264: homefile(filename)
                    265:        char *filename;
                    266: {
1.8       millert   267:        register char *pathname;
1.1       etheisen  268:
                    269:        /*
                    270:         * Try $HOME/filename.
                    271:         */
1.8       millert   272:        pathname = dirfile(lgetenv("HOME"), filename);
1.1       etheisen  273:        if (pathname != NULL)
                    274:                return (pathname);
                    275: #if OS2
                    276:        /*
                    277:         * Try $INIT/filename.
                    278:         */
1.8       millert   279:        pathname = dirfile(lgetenv("INIT"), filename);
1.1       etheisen  280:        if (pathname != NULL)
                    281:                return (pathname);
                    282: #endif
1.8       millert   283: #if MSDOS_COMPILER || OS2
1.1       etheisen  284:        /*
                    285:         * Look for the file anywhere on search path.
                    286:         */
                    287:        pathname = (char *) calloc(_MAX_PATH, sizeof(char));
1.8       millert   288: #if MSDOS_COMPILER==DJGPPC
                    289:        {
                    290:                char *res = searchpath(filename);
                    291:                if (res == 0)
                    292:                        *pathname = '\0';
                    293:                else
                    294:                        strlcpy(pathname, res, _MAX_PATH);
                    295:        }
                    296: #else
1.1       etheisen  297:        _searchenv(filename, "PATH", pathname);
1.8       millert   298: #endif
1.1       etheisen  299:        if (*pathname != '\0')
                    300:                return (pathname);
                    301:        free(pathname);
                    302: #endif
                    303:        return (NULL);
                    304: }
1.14    ! deraadt   305: #endif /* SMALL_PROGRAM */
1.1       etheisen  306:
1.9       millert   307: #ifdef HELPFILE
                    308: /*
                    309:  * Find out where the help file is.
                    310:  */
                    311:        public char *
                    312: find_helpfile()
                    313: {
                    314:        char *helpfile;
                    315:
                    316:        if ((helpfile = getenv("LESSHELP")) != NULL && *helpfile != '\0')
                    317:                return (save(helpfile));
                    318: #if MSDOS_COMPILER || OS2
                    319:        return (homefile(HELPFILE));
                    320: #else
                    321:        return (save(HELPFILE));
                    322: #endif
                    323: }
                    324: #endif
                    325:
1.1       etheisen  326: /*
                    327:  * Expand a string, substituting any "%" with the current filename,
                    328:  * and any "#" with the previous filename.
1.8       millert   329:  * But a string of N "%"s is just replaced with N-1 "%"s.
                    330:  * Likewise for a string of N "#"s.
1.1       etheisen  331:  * {{ This is a lot of work just to support % and #. }}
                    332:  */
                    333:        public char *
                    334: fexpand(s)
                    335:        char *s;
                    336: {
1.8       millert   337:        register char *fr, *to;
                    338:        register int n;
                    339:        register char *e;
                    340:        IFILE ifile;
                    341:
                    342: #define        fchar_ifile(c) \
                    343:        ((c) == '%' ? curr_ifile : \
                    344:         (c) == '#' ? old_ifile : NULL_IFILE)
1.1       etheisen  345:
                    346:        /*
                    347:         * Make one pass to see how big a buffer we
                    348:         * need to allocate for the expanded string.
                    349:         */
                    350:        n = 0;
                    351:        for (fr = s;  *fr != '\0';  fr++)
                    352:        {
                    353:                switch (*fr)
                    354:                {
                    355:                case '%':
1.8       millert   356:                case '#':
                    357:                        if (fr > s && fr[-1] == *fr)
1.1       etheisen  358:                        {
1.8       millert   359:                                /*
                    360:                                 * Second (or later) char in a string
                    361:                                 * of identical chars.  Treat as normal.
                    362:                                 */
                    363:                                n++;
                    364:                        } else if (fr[1] != *fr)
1.1       etheisen  365:                        {
1.8       millert   366:                                /*
                    367:                                 * Single char (not repeated).  Treat specially.
                    368:                                 */
                    369:                                ifile = fchar_ifile(*fr);
                    370:                                if (ifile == NULL_IFILE)
                    371:                                        n++;
                    372:                                else
                    373:                                        n += strlen(get_filename(ifile));
1.1       etheisen  374:                        }
1.8       millert   375:                        /*
                    376:                         * Else it is the first char in a string of
                    377:                         * identical chars.  Just discard it.
                    378:                         */
1.1       etheisen  379:                        break;
                    380:                default:
                    381:                        n++;
                    382:                        break;
                    383:                }
                    384:        }
                    385:
                    386:        e = (char *) ecalloc(n+1, sizeof(char));
                    387:
                    388:        /*
                    389:         * Now copy the string, expanding any "%" or "#".
                    390:         */
                    391:        to = e;
                    392:        for (fr = s;  *fr != '\0';  fr++)
                    393:        {
                    394:                switch (*fr)
                    395:                {
                    396:                case '%':
                    397:                case '#':
1.8       millert   398:                        if (fr > s && fr[-1] == *fr)
                    399:                        {
                    400:                                *to++ = *fr;
                    401:                        } else if (fr[1] != *fr)
                    402:                        {
                    403:                                ifile = fchar_ifile(*fr);
                    404:                                if (ifile == NULL_IFILE)
                    405:                                        *to++ = *fr;
                    406:                                else
                    407:                                {
                    408:                                        strlcpy(to, get_filename(ifile),
                    409:                                            e + n + 1 - to);
                    410:                                        to += strlen(to);
                    411:                                }
                    412:                        }
1.1       etheisen  413:                        break;
                    414:                default:
                    415:                        *to++ = *fr;
                    416:                        break;
                    417:                }
                    418:        }
                    419:        *to = '\0';
                    420:        return (e);
                    421: }
                    422:
                    423: #if TAB_COMPLETE_FILENAME
                    424:
                    425: /*
                    426:  * Return a blank-separated list of filenames which "complete"
                    427:  * the given string.
                    428:  */
                    429:        public char *
                    430: fcomplete(s)
                    431:        char *s;
                    432: {
                    433:        char *fpat;
1.8       millert   434:        char *qs;
                    435:        size_t len;
1.7       deraadt   436:
1.8       millert   437:        if (secure)
                    438:                return (NULL);
1.1       etheisen  439:        /*
                    440:         * Complete the filename "s" by globbing "s*".
                    441:         */
1.8       millert   442: #if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC)
1.1       etheisen  443:        /*
                    444:         * But in DOS, we have to glob "s*.*".
                    445:         * But if the final component of the filename already has
                    446:         * a dot in it, just do "s*".
                    447:         * (Thus, "FILE" is globbed as "FILE*.*",
                    448:         *  but "FILE.A" is globbed as "FILE.A*").
                    449:         */
1.8       millert   450:        {
                    451:                char *slash;
                    452:                for (slash = s+strlen(s)-1;  slash > s;  slash--)
                    453:                        if (*slash == *PATHNAME_SEP || *slash == '/')
                    454:                                break;
                    455:                len = strlen(s) + 4;
                    456:                fpat = (char *) ecalloc(len, sizeof(char));
                    457:                if (strchr(slash, '.') == NULL)
                    458:                        snprintf(fpat, len, "%s*.*", s);
                    459:                else
                    460:                        snprintf(fpat, len, "%s*", s);
                    461:        }
1.1       etheisen  462: #else
1.8       millert   463:        len = strlen(s) + 2;
                    464:        fpat = (char *) ecalloc(len, sizeof(char));
                    465:        snprintf(fpat, len, "%s*", s);
1.1       etheisen  466: #endif
1.8       millert   467:        qs = lglob(fpat);
                    468:        s = shell_unquote(qs);
1.1       etheisen  469:        if (strcmp(s,fpat) == 0)
                    470:        {
                    471:                /*
                    472:                 * The filename didn't expand.
                    473:                 */
1.8       millert   474:                free(qs);
                    475:                qs = NULL;
1.1       etheisen  476:        }
1.8       millert   477:        free(s);
1.1       etheisen  478:        free(fpat);
1.8       millert   479:        return (qs);
1.1       etheisen  480: }
                    481: #endif
                    482:
                    483: /*
                    484:  * Try to determine if a file is "binary".
                    485:  * This is just a guess, and we need not try too hard to make it accurate.
                    486:  */
                    487:        public int
                    488: bin_file(f)
                    489:        int f;
                    490: {
                    491:        int i;
                    492:        int n;
                    493:        unsigned char data[64];
                    494:
                    495:        if (!seekable(f))
                    496:                return (0);
1.11      deraadt   497:        if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK)
1.1       etheisen  498:                return (0);
                    499:        n = read(f, data, sizeof(data));
                    500:        for (i = 0;  i < n;  i++)
                    501:                if (binary_char(data[i]))
                    502:                        return (1);
                    503:        return (0);
                    504: }
                    505:
                    506: /*
                    507:  * Try to determine the size of a file by seeking to the end.
                    508:  */
                    509:        static POSITION
                    510: seek_filesize(f)
                    511:        int f;
                    512: {
                    513:        off_t spos;
                    514:
1.11      deraadt   515:        spos = lseek(f, (off_t)0, SEEK_END);
1.1       etheisen  516:        if (spos == BAD_LSEEK)
                    517:                return (NULL_POSITION);
                    518:        return ((POSITION) spos);
                    519: }
                    520:
                    521: /*
                    522:  * Read a string from a file.
                    523:  * Return a pointer to the string in memory.
                    524:  */
                    525:        static char *
                    526: readfd(fd)
                    527:        FILE *fd;
                    528: {
                    529:        int len;
                    530:        int ch;
                    531:        char *buf;
                    532:        char *p;
                    533:
                    534:        /*
                    535:         * Make a guess about how many chars in the string
                    536:         * and allocate a buffer to hold it.
                    537:         */
                    538:        len = 100;
                    539:        buf = (char *) ecalloc(len, sizeof(char));
                    540:        for (p = buf;  ;  p++)
                    541:        {
                    542:                if ((ch = getc(fd)) == '\n' || ch == EOF)
                    543:                        break;
                    544:                if (p - buf >= len-1)
                    545:                {
                    546:                        /*
                    547:                         * The string is too big to fit in the buffer we have.
                    548:                         * Allocate a new buffer, twice as big.
                    549:                         */
                    550:                        len *= 2;
                    551:                        *p = '\0';
                    552:                        p = (char *) ecalloc(len, sizeof(char));
1.5       deraadt   553:                        strlcpy(p, buf, len);
1.1       etheisen  554:                        free(buf);
                    555:                        buf = p;
                    556:                        p = buf + strlen(buf);
                    557:                }
                    558:                *p = ch;
                    559:        }
                    560:        *p = '\0';
                    561:        return (buf);
                    562: }
                    563:
1.8       millert   564:
                    565:
                    566: #if HAVE_POPEN
                    567:
                    568: FILE *popen();
                    569:
1.1       etheisen  570: /*
                    571:  * Execute a shell command.
                    572:  * Return a pointer to a pipe connected to the shell command's standard output.
                    573:  */
                    574:        static FILE *
1.8       millert   575: shellcmd(cmd)
1.1       etheisen  576:        char *cmd;
                    577: {
                    578:        FILE *fd;
1.8       millert   579:        size_t len;
                    580:
1.1       etheisen  581: #if HAVE_SHELL
1.8       millert   582:        char *shell;
                    583:
                    584:        shell = lgetenv("SHELL");
1.1       etheisen  585:        if (shell != NULL && *shell != '\0')
                    586:        {
1.8       millert   587:                char *scmd;
                    588:                char *esccmd;
                    589:
1.1       etheisen  590:                /*
1.8       millert   591:                 * Read the output of <$SHELL -c cmd>.
                    592:                 * Escape any metacharacters in the command.
1.1       etheisen  593:                 */
1.8       millert   594:                esccmd = shell_quote(cmd);
                    595:                if (esccmd == NULL)
                    596:                {
                    597:                        fd = popen(cmd, "r");
                    598:                } else
                    599:                {
                    600:                        len = strlen(shell) + strlen(esccmd) + 5;
                    601:                        scmd = (char *) ecalloc(len, sizeof(char));
                    602:                        snprintf(scmd, len, "%s %s %s", shell, shell_coption(),
                    603:                            esccmd);
                    604:                        free(esccmd);
                    605:                        fd = popen(scmd, "r");
                    606:                        free(scmd);
                    607:                }
                    608:        } else
                    609: #endif
                    610:        {
                    611:                fd = popen(cmd, "r");
1.1       etheisen  612:        }
1.8       millert   613:        /*
                    614:         * Redirection in `popen' might have messed with the
                    615:         * standard devices.  Restore binary input mode.
                    616:         */
                    617:        SET_BINARY(0);
1.1       etheisen  618:        return (fd);
                    619: }
                    620:
1.8       millert   621: #endif /* HAVE_POPEN */
                    622:
                    623:
1.1       etheisen  624: /*
1.8       millert   625:  * Expand a filename, doing any system-specific metacharacter substitutions.
1.1       etheisen  626:  */
                    627:        public char *
1.8       millert   628: lglob(filename)
1.1       etheisen  629:        char *filename;
                    630: {
                    631:        char *gfilename;
1.8       millert   632:        char *ofilename;
1.1       etheisen  633:
1.8       millert   634:        ofilename = fexpand(filename);
                    635:        if (secure)
                    636:                return (ofilename);
                    637:        filename = shell_unquote(ofilename);
                    638:
                    639: #ifdef DECL_GLOB_LIST
1.1       etheisen  640: {
1.8       millert   641:        /*
                    642:         * The globbing function returns a list of names.
                    643:         */
1.1       etheisen  644:        int length;
1.8       millert   645:        char *p;
                    646:        char *qfilename;
                    647:        DECL_GLOB_LIST(list)
1.1       etheisen  648:
1.8       millert   649:        GLOB_LIST(filename, list);
                    650:        if (GLOB_LIST_FAILED(list))
                    651:        {
                    652:                free(filename);
                    653:                return (ofilename);
                    654:        }
                    655:        length = 1; /* Room for trailing null byte */
                    656:        for (SCAN_GLOB_LIST(list, p))
                    657:        {
                    658:                INIT_GLOB_LIST(list, p);
                    659:                qfilename = shell_quote(p);
                    660:                if (qfilename != NULL)
                    661:                {
                    662:                        length += strlen(qfilename) + 1;
                    663:                        free(qfilename);
                    664:                }
                    665:        }
1.1       etheisen  666:        gfilename = (char *) ecalloc(length, sizeof(char));
1.8       millert   667:        for (SCAN_GLOB_LIST(list, p))
1.1       etheisen  668:        {
1.8       millert   669:                INIT_GLOB_LIST(list, p);
                    670:                qfilename = shell_quote(p);
                    671:                if (qfilename != NULL)
                    672:                {
                    673:                        snprintf(gfilename + strlen(gfilename),
                    674:                            length - strlen(gfilename), "%s ", qfilename);
                    675:                        free(qfilename);
                    676:                }
1.1       etheisen  677:        }
1.8       millert   678:        /*
                    679:         * Overwrite the final trailing space with a null terminator.
                    680:         */
1.13      ray       681:        if (gfilename[0] != '\0' && gfilename[strlen(gfilename) - 1] == ' ')
                    682:                gfilename[strlen(gfilename) - 1] = '\0';
1.8       millert   683:        GLOB_LIST_DONE(list);
1.1       etheisen  684: }
                    685: #else
1.8       millert   686: #ifdef DECL_GLOB_NAME
1.1       etheisen  687: {
1.8       millert   688:        /*
                    689:         * The globbing function returns a single name, and
                    690:         * is called multiple times to walk thru all names.
                    691:         */
                    692:        register char *p;
                    693:        register int len;
                    694:        register int n;
                    695:        char *pathname;
                    696:        char *qpathname;
                    697:        DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle)
                    698:
                    699:        GLOB_FIRST_NAME(filename, &fnd, handle);
                    700:        if (GLOB_FIRST_FAILED(handle))
                    701:        {
                    702:                free(filename);
                    703:                return (ofilename);
                    704:        }
                    705:
                    706:        _splitpath(filename, drive, dir, fname, ext);
                    707:        len = 100;
                    708:        gfilename = (char *) ecalloc(len, sizeof(char));
                    709:        p = gfilename;
                    710:        do {
                    711:                n = strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1;
                    712:                pathname = (char *) ecalloc(n, sizeof(char));
                    713:                snprintf(pathname, n, "%s%s%s", drive, dir, fnd.GLOB_NAME);
                    714:                qpathname = shell_quote(pathname);
                    715:                free(pathname);
                    716:                if (qpathname != NULL)
                    717:                {
                    718:                        n = strlen(qpathname);
                    719:                        while (p - gfilename + n + 2 >= len)
                    720:                        {
                    721:                                /*
                    722:                                 * No room in current buffer.
                    723:                                 * Allocate a bigger one.
                    724:                                 */
                    725:                                len *= 2;
                    726:                                *p = '\0';
                    727:                                p = (char *) ecalloc(len, sizeof(char));
                    728:                                strlcpy(p, gfilename, len);
                    729:                                free(gfilename);
                    730:                                gfilename = p;
                    731:                                p = gfilename + strlen(gfilename);
                    732:                        }
                    733:                        strlcpy(p, qpathname, gfilename + len - p);
                    734:                        free(qpathname);
                    735:                        p += n;
                    736:                        *p++ = ' ';
                    737:                }
                    738:        } while (GLOB_NEXT_NAME(handle, &fnd) == 0);
                    739:
                    740:        /*
                    741:         * Overwrite the final trailing space with a null terminator.
                    742:         */
                    743:        *--p = '\0';
                    744:        GLOB_NAME_DONE(handle);
                    745: }
                    746: #else
                    747: #if HAVE_POPEN
                    748: {
                    749:        /*
                    750:         * We get the shell to glob the filename for us by passing
                    751:         * an "echo" command to the shell and reading its output.
                    752:         */
1.1       etheisen  753:        FILE *fd;
1.8       millert   754:        char *s;
                    755:        char *lessecho;
                    756:        char *cmd;
                    757:        char *esc;
                    758:        size_t len;
1.1       etheisen  759:
1.8       millert   760:        esc = get_meta_escape();
                    761:        if (strlen(esc) == 0)
                    762:                esc = "-";
                    763:        esc = shell_quote(esc);
                    764:        if (esc == NULL)
                    765:        {
                    766:                free(filename);
                    767:                return (ofilename);
                    768:        }
                    769:        lessecho = lgetenv("LESSECHO");
                    770:        if (lessecho == NULL || *lessecho == '\0')
                    771:                lessecho = "lessecho";
1.1       etheisen  772:        /*
1.8       millert   773:         * Invoke lessecho, and read its output (a globbed list of filenames).
1.1       etheisen  774:         */
1.8       millert   775:        len = strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24;
                    776:        cmd = (char *) ecalloc(len, sizeof(char));
                    777:        snprintf(cmd, len, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote,
                    778:            closequote, esc);
                    779:        free(esc);
                    780:        for (s = metachars();  *s != '\0';  s++)
                    781:                snprintf(cmd + strlen(cmd), len - strlen(cmd), "-n0x%x ", *s);
                    782:        snprintf(cmd + strlen(cmd), len - strlen(cmd), "-- %s", ofilename);
                    783:        fd = shellcmd(cmd);
                    784:        free(cmd);
1.1       etheisen  785:        if (fd == NULL)
                    786:        {
                    787:                /*
                    788:                 * Cannot create the pipe.
                    789:                 * Just return the original (fexpanded) filename.
                    790:                 */
1.8       millert   791:                free(filename);
                    792:                return (ofilename);
1.1       etheisen  793:        }
                    794:        gfilename = readfd(fd);
                    795:        pclose(fd);
                    796:        if (*gfilename == '\0')
                    797:        {
                    798:                free(gfilename);
1.8       millert   799:                free(filename);
                    800:                return (ofilename);
1.1       etheisen  801:        }
                    802: }
1.8       millert   803: #else
                    804:        /*
                    805:         * No globbing functions at all.  Just use the fexpanded filename.
                    806:         */
                    807:        gfilename = save(filename);
                    808: #endif
                    809: #endif
1.1       etheisen  810: #endif
1.8       millert   811:        free(filename);
                    812:        free(ofilename);
1.1       etheisen  813:        return (gfilename);
                    814: }
                    815:
                    816: /*
                    817:  * See if we should open a "replacement file"
                    818:  * instead of the file we're about to open.
                    819:  */
                    820:        public char *
                    821: open_altfile(filename, pf, pfd)
                    822:        char *filename;
                    823:        int *pf;
                    824:        void **pfd;
                    825: {
1.8       millert   826: #if !HAVE_POPEN
                    827:        return (NULL);
                    828: #else
1.1       etheisen  829:        char *lessopen;
1.10      millert   830:        char *cmd, *cp;
1.8       millert   831:        FILE *fd;
1.10      millert   832:        size_t i, len;
                    833:        int found;
1.8       millert   834: #if HAVE_FILENO
1.1       etheisen  835:        int returnfd = 0;
1.8       millert   836: #endif
1.1       etheisen  837:
1.8       millert   838:        if (!use_lessopen || secure)
                    839:                return (NULL);
1.1       etheisen  840:        ch_ungetchar(-1);
1.8       millert   841:        if ((lessopen = lgetenv("LESSOPEN")) == NULL)
1.1       etheisen  842:                return (NULL);
                    843:        if (strcmp(filename, "-") == 0)
                    844:                return (NULL);
                    845:        if (*lessopen == '|')
                    846:        {
                    847:                /*
                    848:                 * If LESSOPEN starts with a |, it indicates
                    849:                 * a "pipe preprocessor".
                    850:                 */
1.8       millert   851: #if HAVE_FILENO
1.1       etheisen  852:                lessopen++;
                    853:                returnfd = 1;
1.8       millert   854: #else
                    855:                error("LESSOPEN pipe is not supported", NULL_PARG);
                    856:                return (NULL);
                    857: #endif
1.1       etheisen  858:        }
1.8       millert   859:
1.10      millert   860:        /* strlen(filename) is guaranteed to be > 0 */
                    861:        len = strlen(lessopen) + strlen(filename);
1.8       millert   862:        cmd = (char *) ecalloc(len, sizeof(char));
1.10      millert   863:        for (cp = cmd, i = 0, found = 0; i < strlen(lessopen); i++) {
                    864:                if (!found && lessopen[i] == '%' && lessopen[i + 1] == 's') {
                    865:                        found = 1;
                    866:                        strlcat(cmd, filename, len);
                    867:                        cp += strlen(filename);
                    868:                        i++;
                    869:                } else
                    870:                        *cp++ = lessopen[i];
                    871:        }
1.8       millert   872:        fd = shellcmd(cmd);
                    873:        free(cmd);
1.1       etheisen  874:        if (fd == NULL)
                    875:        {
                    876:                /*
                    877:                 * Cannot create the pipe.
                    878:                 */
                    879:                return (NULL);
                    880:        }
1.8       millert   881: #if HAVE_FILENO
1.1       etheisen  882:        if (returnfd)
                    883:        {
                    884:                int f;
                    885:                char c;
                    886:
                    887:                /*
                    888:                 * Read one char to see if the pipe will produce any data.
                    889:                 * If it does, push the char back on the pipe.
                    890:                 */
                    891:                f = fileno(fd);
1.8       millert   892:                SET_BINARY(f);
1.1       etheisen  893:                if (read(f, &c, 1) != 1)
                    894:                {
                    895:                        /*
                    896:                         * Pipe is empty.  This means there is no alt file.
                    897:                         */
                    898:                        pclose(fd);
                    899:                        return (NULL);
                    900:                }
                    901:                ch_ungetchar(c);
                    902:                *pfd = (void *) fd;
                    903:                *pf = f;
                    904:                return (save("-"));
1.8       millert   905:        }
1.1       etheisen  906: #endif
1.8       millert   907:        cmd = readfd(fd);
1.1       etheisen  908:        pclose(fd);
1.8       millert   909:        if (*cmd == '\0')
1.1       etheisen  910:                /*
                    911:                 * Pipe is empty.  This means there is no alt file.
                    912:                 */
                    913:                return (NULL);
1.8       millert   914:        return (cmd);
                    915: #endif /* HAVE_POPEN */
1.1       etheisen  916: }
                    917:
                    918: /*
                    919:  * Close a replacement file.
                    920:  */
                    921:        public void
                    922: close_altfile(altfilename, filename, pipefd)
                    923:        char *altfilename;
                    924:        char *filename;
                    925:        void *pipefd;
                    926: {
1.8       millert   927: #if HAVE_POPEN
1.1       etheisen  928:        char *lessclose;
                    929:        FILE *fd;
1.10      millert   930:        char *cmd, *cp;
                    931:        size_t i, len;
                    932:        int found;
1.1       etheisen  933:
1.8       millert   934:        if (secure)
                    935:                return;
1.1       etheisen  936:        if (pipefd != NULL)
1.8       millert   937:        {
                    938: #if OS2
                    939:                /*
                    940:                 * The pclose function of OS/2 emx sometimes fails.
                    941:                 * Send SIGINT to the piped process before closing it.
                    942:                 */
                    943:                kill(((FILE*)pipefd)->_pid, SIGINT);
                    944: #endif
1.1       etheisen  945:                pclose((FILE*) pipefd);
1.8       millert   946:        }
                    947:        if ((lessclose = lgetenv("LESSCLOSE")) == NULL)
1.1       etheisen  948:                return;
1.10      millert   949:        /* strlen(filename) is guaranteed to be > 0 */
                    950:        len = strlen(lessclose) + strlen(filename) + strlen(altfilename);
1.8       millert   951:        cmd = (char *) ecalloc(len, sizeof(char));
1.10      millert   952:        for (cp = cmd, i = 0, found = 0; i < strlen(lessclose); i++) {
                    953:                if (found < 2 && lessclose[i] == '%' && lessclose[i + 1] == 's') {
                    954:                        if (++found == 1) {
                    955:                                strlcat(cmd, filename, len);
                    956:                                cp += strlen(filename);
                    957:                        } else {
                    958:                                strlcat(cmd, altfilename, len);
                    959:                                cp += strlen(altfilename);
                    960:                        }
                    961:                        i++;
                    962:                } else
                    963:                        *cp++ = lessclose[i];
                    964:        }
1.8       millert   965:        fd = shellcmd(cmd);
                    966:        free(cmd);
                    967:        if (fd != NULL)
                    968:                pclose(fd);
                    969: #endif
1.1       etheisen  970: }
                    971:
1.8       millert   972: /*
                    973:  * Is the specified file a directory?
                    974:  */
                    975:        public int
                    976: is_dir(filename)
1.1       etheisen  977:        char *filename;
                    978: {
1.8       millert   979:        int isdir = 0;
                    980:
                    981:        filename = shell_unquote(filename);
                    982: #if HAVE_STAT
1.1       etheisen  983: {
1.8       millert   984:        int r;
                    985:        struct stat statbuf;
1.1       etheisen  986:
1.8       millert   987:        r = stat(filename, &statbuf);
                    988:        isdir = (r >= 0 && S_ISDIR(statbuf.st_mode));
1.1       etheisen  989: }
                    990: #else
1.8       millert   991: #ifdef _OSK
1.1       etheisen  992: {
1.8       millert   993:        register int f;
1.1       etheisen  994:
1.8       millert   995:        f = open(filename, S_IREAD | S_IFDIR);
                    996:        if (f >= 0)
                    997:                close(f);
                    998:        isdir = (f >= 0);
1.1       etheisen  999: }
                   1000: #endif
                   1001: #endif
1.8       millert  1002:        free(filename);
                   1003:        return (isdir);
                   1004: }
1.1       etheisen 1005:
                   1006: /*
                   1007:  * Returns NULL if the file can be opened and
                   1008:  * is an ordinary file, otherwise an error message
                   1009:  * (if it cannot be opened or is a directory, etc.)
                   1010:  */
                   1011:        public char *
                   1012: bad_file(filename)
                   1013:        char *filename;
                   1014: {
1.8       millert  1015:        register char *m = NULL;
                   1016:        size_t len;
1.1       etheisen 1017:
1.8       millert  1018:        filename = shell_unquote(filename);
                   1019:        if (is_dir(filename))
1.1       etheisen 1020:        {
1.8       millert  1021:                static char is_a_dir[] = " is a directory";
1.5       deraadt  1022:
1.8       millert  1023:                len = strlen(filename) + sizeof(is_a_dir);
1.5       deraadt  1024:                m = (char *) ecalloc(len, sizeof(char));
                   1025:                strlcpy(m, filename, len);
1.8       millert  1026:                strlcat(m, is_a_dir, len);
                   1027:        } else
1.1       etheisen 1028:        {
1.8       millert  1029: #if HAVE_STAT
                   1030:                int r;
                   1031:                struct stat statbuf;
1.5       deraadt  1032:
1.8       millert  1033:                r = stat(filename, &statbuf);
                   1034:                if (r < 0)
                   1035:                {
                   1036:                        m = errno_message(filename);
                   1037:                } else if (force_open)
                   1038:                {
                   1039:                        m = NULL;
                   1040:                } else if (!S_ISREG(statbuf.st_mode))
                   1041:                {
                   1042:                        static char not_reg[] = " is not a regular file (use -f to see it)";
                   1043:                        len = strlen(filename) + sizeof(not_reg);
                   1044:                        m = (char *) ecalloc(len, sizeof(char));
                   1045:                        strlcpy(m, filename, len);
                   1046:                        strlcat(m, not_reg, len);
                   1047:                }
                   1048: #endif
1.1       etheisen 1049:        }
1.8       millert  1050:        free(filename);
                   1051:        return (m);
1.1       etheisen 1052: }
                   1053:
                   1054: /*
                   1055:  * Return the size of a file, as cheaply as possible.
                   1056:  * In Unix, we can stat the file.
                   1057:  */
                   1058:        public POSITION
                   1059: filesize(f)
                   1060:        int f;
                   1061: {
1.8       millert  1062: #if HAVE_STAT
1.1       etheisen 1063:        struct stat statbuf;
                   1064:
1.8       millert  1065:        if (fstat(f, &statbuf) >= 0)
                   1066:                return ((POSITION) statbuf.st_size);
                   1067: #else
                   1068: #ifdef _OSK
                   1069:        long size;
1.1       etheisen 1070:
1.8       millert  1071:        if ((size = (long) _gs_size(f)) >= 0)
                   1072:                return ((POSITION) size);
                   1073: #endif
                   1074: #endif
                   1075:        return (seek_filesize(f));
1.1       etheisen 1076: }
                   1077:
                   1078: /*
1.8       millert  1079:  *
1.1       etheisen 1080:  */
                   1081:        public char *
1.8       millert  1082: shell_coption()
1.1       etheisen 1083: {
1.8       millert  1084:        return ("-c");
1.1       etheisen 1085: }