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

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