Annotation of 43BSDTahoe/bin/csh/sh.file.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1980 Regents of the University of California.
        !             3:  * All rights reserved.  The Berkeley Software License Agreement
        !             4:  * specifies the terms and conditions for redistribution.
        !             5:  */
        !             6: 
        !             7: #ifndef lint
        !             8: static char *sccsid = "@(#)sh.file.c   5.8 (Berkeley) 5/19/88";
        !             9: #endif
        !            10: 
        !            11: #ifdef FILEC
        !            12: /*
        !            13:  * Tenex style file name recognition, .. and more.
        !            14:  * History:
        !            15:  *     Author: Ken Greer, Sept. 1975, CMU.
        !            16:  *     Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
        !            17:  */
        !            18: 
        !            19: #include "sh.h"
        !            20: #include <sgtty.h>
        !            21: #include <sys/dir.h>
        !            22: #include <pwd.h>
        !            23: 
        !            24: #define TRUE   1
        !            25: #define FALSE  0
        !            26: #define ON     1
        !            27: #define OFF    0
        !            28: 
        !            29: #define ESC    '\033'
        !            30: 
        !            31: typedef enum {LIST, RECOGNIZE} COMMAND;
        !            32: 
        !            33: int    sortscmp();                     /* defined in sh.glob.c */
        !            34: 
        !            35: /*
        !            36:  * Put this here so the binary can be patched with adb to enable file
        !            37:  * completion by default.  Filec controls completion, nobeep controls
        !            38:  * ringing the terminal bell on incomplete expansions.
        !            39:  */
        !            40: bool filec = 0;
        !            41: 
        !            42: static
        !            43: setup_tty(on)
        !            44:        int on;
        !            45: {
        !            46:        struct sgttyb sgtty;
        !            47:        static struct tchars tchars;    /* INT, QUIT, XON, XOFF, EOF, BRK */
        !            48: 
        !            49:        if (on) {
        !            50:                (void) ioctl(SHIN, TIOCGETC, (char *)&tchars);
        !            51:                tchars.t_brkc = ESC;
        !            52:                (void) ioctl(SHIN, TIOCSETC, (char *)&tchars);
        !            53:                /*
        !            54:                 * This must be done after every command: if
        !            55:                 * the tty gets into raw or cbreak mode the user
        !            56:                 * can't even type 'reset'.
        !            57:                 */
        !            58:                (void) ioctl(SHIN, TIOCGETP, (char *)&sgtty);
        !            59:                if (sgtty.sg_flags & (RAW|CBREAK)) {
        !            60:                         sgtty.sg_flags &= ~(RAW|CBREAK);
        !            61:                         (void) ioctl(SHIN, TIOCSETP, (char *)&sgtty);
        !            62:                }
        !            63:        } else {
        !            64:                tchars.t_brkc = -1;
        !            65:                (void) ioctl(SHIN, TIOCSETC, (char *)&tchars);
        !            66:        }
        !            67: }
        !            68: 
        !            69: /*
        !            70:  * Move back to beginning of current line
        !            71:  */
        !            72: static
        !            73: back_to_col_1()
        !            74: {
        !            75:        struct sgttyb tty, tty_normal;
        !            76:        long omask;
        !            77: 
        !            78:        omask = sigblock(sigmask(SIGINT));
        !            79:        (void) ioctl(SHIN, TIOCGETP, (char *)&tty);
        !            80:        tty_normal = tty;
        !            81:        tty.sg_flags &= ~CRMOD;
        !            82:        (void) ioctl(SHIN, TIOCSETN, (char *)&tty);
        !            83:        (void) write(SHOUT, "\r", 1);
        !            84:        (void) ioctl(SHIN, TIOCSETN, (char *)&tty_normal);
        !            85:        (void) sigsetmask(omask);
        !            86: }
        !            87: 
        !            88: /*
        !            89:  * Push string contents back into tty queue
        !            90:  */
        !            91: static
        !            92: pushback(string)
        !            93:        char *string;
        !            94: {
        !            95:        register char *p;
        !            96:        struct sgttyb tty, tty_normal;
        !            97:        long omask;
        !            98: 
        !            99:        omask = sigblock(sigmask(SIGINT));
        !           100:        (void) ioctl(SHOUT, TIOCGETP, (char *)&tty);
        !           101:        tty_normal = tty;
        !           102:        tty.sg_flags &= ~ECHO;
        !           103:        (void) ioctl(SHOUT, TIOCSETN, (char *)&tty);
        !           104: 
        !           105:        for (p = string; *p; p++)
        !           106:                (void) ioctl(SHOUT, TIOCSTI, p);
        !           107:        (void) ioctl(SHOUT, TIOCSETN, (char *)&tty_normal);
        !           108:        (void) sigsetmask(omask);
        !           109: }
        !           110: 
        !           111: /*
        !           112:  * Concatenate src onto tail of des.
        !           113:  * Des is a string whose maximum length is count.
        !           114:  * Always null terminate.
        !           115:  */
        !           116: static
        !           117: catn(des, src, count)
        !           118:        register char *des, *src;
        !           119:        register count;
        !           120: {
        !           121: 
        !           122:        while (--count >= 0 && *des)
        !           123:                des++;
        !           124:        while (--count >= 0)
        !           125:                if ((*des++ = *src++) == 0)
        !           126:                         return;
        !           127:        *des = '\0';
        !           128: }
        !           129: 
        !           130: /*
        !           131:  * Like strncpy but always leave room for trailing \0
        !           132:  * and always null terminate.
        !           133:  */
        !           134: static
        !           135: copyn(des, src, count)
        !           136:        register char *des, *src;
        !           137:        register count;
        !           138: {
        !           139: 
        !           140:        while (--count >= 0)
        !           141:                if ((*des++ = *src++) == 0)
        !           142:                        return;
        !           143:        *des = '\0';
        !           144: }
        !           145: 
        !           146: static char
        !           147: filetype(dir, file)
        !           148:        char *dir, *file;
        !           149: {
        !           150:        char path[MAXPATHLEN];
        !           151:        struct stat statb;
        !           152: 
        !           153:        catn(strcpy(path, dir), file, sizeof path);
        !           154:        if (lstat(path, &statb) == 0) {
        !           155:                switch(statb.st_mode & S_IFMT) {
        !           156:                    case S_IFDIR:
        !           157:                        return ('/');
        !           158: 
        !           159:                    case S_IFLNK:
        !           160:                        if (stat(path, &statb) == 0 &&      /* follow it out */
        !           161:                           (statb.st_mode & S_IFMT) == S_IFDIR)
        !           162:                                return ('>');
        !           163:                        else
        !           164:                                return ('@');
        !           165: 
        !           166:                    case S_IFSOCK:
        !           167:                        return ('=');
        !           168: 
        !           169:                    default:
        !           170:                        if (statb.st_mode & 0111)
        !           171:                                return ('*');
        !           172:                }
        !           173:        }
        !           174:        return (' ');
        !           175: }
        !           176: 
        !           177: static struct winsize win;
        !           178: 
        !           179: /*
        !           180:  * Print sorted down columns
        !           181:  */
        !           182: static
        !           183: print_by_column(dir, items, count)
        !           184:        char *dir, *items[];
        !           185: {
        !           186:        register int i, rows, r, c, maxwidth = 0, columns;
        !           187: 
        !           188:        if (ioctl(SHOUT, TIOCGWINSZ, (char *)&win) < 0 || win.ws_col == 0)
        !           189:                win.ws_col = 80;
        !           190:        for (i = 0; i < count; i++)
        !           191:                maxwidth = maxwidth > (r = strlen(items[i])) ? maxwidth : r;
        !           192:        maxwidth += 2;                  /* for the file tag and space */
        !           193:        columns = win.ws_col / maxwidth;
        !           194:        if (columns == 0)
        !           195:                columns = 1;
        !           196:        rows = (count + (columns - 1)) / columns;
        !           197:        for (r = 0; r < rows; r++) {
        !           198:                for (c = 0; c < columns; c++) {
        !           199:                        i = c * rows + r;
        !           200:                        if (i < count) {
        !           201:                                register int w;
        !           202: 
        !           203:                                printf("%s", items[i]);
        !           204:                                cshputchar(dir ? filetype(dir, items[i]) : ' ');
        !           205:                                if (c < columns - 1) {  /* last column? */
        !           206:                                        w = strlen(items[i]) + 1;
        !           207:                                        for (; w < maxwidth; w++)
        !           208:                                                cshputchar(' ');
        !           209:                                }
        !           210:                        }
        !           211:                }
        !           212:                cshputchar('\n');
        !           213:        }
        !           214: }
        !           215: 
        !           216: /*
        !           217:  * Expand file name with possible tilde usage
        !           218:  *     ~person/mumble
        !           219:  * expands to
        !           220:  *     home_directory_of_person/mumble
        !           221:  */
        !           222: static char *
        !           223: tilde(new, old)
        !           224:        char *new, *old;
        !           225: {
        !           226:        register char *o, *p;
        !           227:        register struct passwd *pw;
        !           228:        static char person[40];
        !           229: 
        !           230:        if (old[0] != '~')
        !           231:                return (strcpy(new, old));
        !           232: 
        !           233:        for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++)
        !           234:                ;
        !           235:        *p = '\0';
        !           236:        if (person[0] == '\0')
        !           237:                (void) strcpy(new, value("home"));
        !           238:        else {
        !           239:                pw = getpwnam(person);
        !           240:                if (pw == NULL)
        !           241:                        return (NULL);
        !           242:                (void) strcpy(new, pw->pw_dir);
        !           243:        }
        !           244:        (void) strcat(new, o);
        !           245:        return (new);
        !           246: }
        !           247: 
        !           248: /*
        !           249:  * Cause pending line to be printed
        !           250:  */
        !           251: static
        !           252: retype()
        !           253: {
        !           254:        int pending_input = LPENDIN;
        !           255: 
        !           256:        (void) ioctl(SHOUT, TIOCLBIS, (char *)&pending_input);
        !           257: }
        !           258: 
        !           259: static
        !           260: beep()
        !           261: {
        !           262: 
        !           263:        if (adrof("nobeep") == 0)
        !           264:                (void) write(SHOUT, "\007", 1);
        !           265: }
        !           266: 
        !           267: /*
        !           268:  * Erase that silly ^[ and
        !           269:  * print the recognized part of the string
        !           270:  */
        !           271: static
        !           272: print_recognized_stuff(recognized_part)
        !           273:        char *recognized_part;
        !           274: {
        !           275: 
        !           276:        /* An optimized erasing of that silly ^[ */
        !           277:        switch (strlen(recognized_part)) {
        !           278: 
        !           279:        case 0:                         /* erase two characters: ^[ */
        !           280:                printf("\210\210  \210\210");
        !           281:                break;
        !           282: 
        !           283:        case 1:                         /* overstrike the ^, erase the [ */
        !           284:                printf("\210\210%s \210", recognized_part);
        !           285:                break;
        !           286: 
        !           287:        default:                        /* overstrike both characters ^[ */
        !           288:                printf("\210\210%s", recognized_part);
        !           289:                break;
        !           290:        }
        !           291:        flush();
        !           292: }
        !           293: 
        !           294: /*
        !           295:  * Parse full path in file into 2 parts: directory and file names
        !           296:  * Should leave final slash (/) at end of dir.
        !           297:  */
        !           298: static
        !           299: extract_dir_and_name(path, dir, name)
        !           300:        char *path, *dir, *name;
        !           301: {
        !           302:        register char  *p;
        !           303: 
        !           304:        p = rindex(path, '/');
        !           305:        if (p == NULL) {
        !           306:                copyn(name, path, MAXNAMLEN);
        !           307:                dir[0] = '\0';
        !           308:        } else {
        !           309:                copyn(name, ++p, MAXNAMLEN);
        !           310:                copyn(dir, path, p - path);
        !           311:        }
        !           312: }
        !           313: 
        !           314: static char *
        !           315: getentry(dir_fd, looking_for_lognames)
        !           316:        DIR *dir_fd;
        !           317: {
        !           318:        register struct passwd *pw;
        !           319:        register struct direct *dirp;
        !           320: 
        !           321:        if (looking_for_lognames) {
        !           322:                if ((pw = getpwent()) == NULL)
        !           323:                        return (NULL);
        !           324:                return (pw->pw_name);
        !           325:        }
        !           326:        if (dirp = readdir(dir_fd))
        !           327:                return (dirp->d_name);
        !           328:        return (NULL);
        !           329: }
        !           330: 
        !           331: static
        !           332: free_items(items)
        !           333:        register char **items;
        !           334: {
        !           335:        register int i;
        !           336: 
        !           337:        for (i = 0; items[i]; i++)
        !           338:                free(items[i]);
        !           339:        free((char *)items);
        !           340: }
        !           341: 
        !           342: #define FREE_ITEMS(items) { \
        !           343:        long omask;\
        !           344: \
        !           345:        omask = sigblock(sigmask(SIGINT));\
        !           346:        free_items(items);\
        !           347:        items = NULL;\
        !           348:        (void) sigsetmask(omask);\
        !           349: }
        !           350: 
        !           351: /*
        !           352:  * Perform a RECOGNIZE or LIST command on string "word".
        !           353:  */
        !           354: static
        !           355: search(word, command, max_word_length)
        !           356:        char *word;
        !           357:        COMMAND command;
        !           358: {
        !           359:        static char **items = NULL;
        !           360:        register DIR *dir_fd;
        !           361:        register numitems = 0, ignoring = TRUE, nignored = 0;
        !           362:        register name_length, looking_for_lognames;
        !           363:        char tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1];
        !           364:        char name[MAXNAMLEN + 1], extended_name[MAXNAMLEN+1];
        !           365:        char *entry;
        !           366: #define MAXITEMS 1024
        !           367: 
        !           368:        if (items != NULL)
        !           369:                FREE_ITEMS(items);
        !           370: 
        !           371:        looking_for_lognames = (*word == '~') && (index(word, '/') == NULL);
        !           372:        if (looking_for_lognames) {
        !           373:                (void) setpwent();
        !           374:                copyn(name, &word[1], MAXNAMLEN);       /* name sans ~ */
        !           375:        } else {
        !           376:                extract_dir_and_name(word, dir, name);
        !           377:                if (tilde(tilded_dir, dir) == 0)
        !           378:                        return (0);
        !           379:                dir_fd = opendir(*tilded_dir ? tilded_dir : ".");
        !           380:                if (dir_fd == NULL)
        !           381:                        return (0);
        !           382:        }
        !           383: 
        !           384: again: /* search for matches */
        !           385:        name_length = strlen(name);
        !           386:        for (numitems = 0; entry = getentry(dir_fd, looking_for_lognames); ) {
        !           387:                if (!is_prefix(name, entry))
        !           388:                        continue;
        !           389:                /* Don't match . files on null prefix match */
        !           390:                if (name_length == 0 && entry[0] == '.' &&
        !           391:                    !looking_for_lognames)
        !           392:                        continue;
        !           393:                if (command == LIST) {
        !           394:                        if (numitems >= MAXITEMS) {
        !           395:                                printf ("\nYikes!! Too many %s!!\n",
        !           396:                                    looking_for_lognames ?
        !           397:                                        "names in password file":"files");
        !           398:                                break;
        !           399:                        }
        !           400:                        if (items == NULL)
        !           401:                                items = (char **) calloc(sizeof (items[1]),
        !           402:                                    MAXITEMS);
        !           403:                        items[numitems] = xalloc((unsigned)strlen(entry) + 1);
        !           404:                        copyn(items[numitems], entry, MAXNAMLEN);
        !           405:                        numitems++;
        !           406:                } else {                        /* RECOGNIZE command */
        !           407:                        if (ignoring && ignored(entry))
        !           408:                                nignored++;
        !           409:                        else if (recognize(extended_name,
        !           410:                            entry, name_length, ++numitems))
        !           411:                                break;
        !           412:                }
        !           413:        }
        !           414:        if (ignoring && numitems == 0 && nignored > 0) {
        !           415:                ignoring = FALSE;
        !           416:                nignored = 0;
        !           417:                if (looking_for_lognames)
        !           418:                        (void) setpwent();
        !           419:                else
        !           420:                        rewinddir(dir_fd);
        !           421:                goto again;
        !           422:        }
        !           423: 
        !           424:        if (looking_for_lognames)
        !           425:                (void) endpwent();
        !           426:        else
        !           427:                closedir(dir_fd);
        !           428:        if (numitems == 0)
        !           429:                return (0);
        !           430:        if (command == RECOGNIZE) {
        !           431:                if (looking_for_lognames)
        !           432:                         copyn(word, "~", 1);
        !           433:                else
        !           434:                        /* put back dir part */
        !           435:                        copyn(word, dir, max_word_length);
        !           436:                /* add extended name */
        !           437:                catn(word, extended_name, max_word_length);
        !           438:                return (numitems);
        !           439:        }
        !           440:        else {                          /* LIST */
        !           441:                qsort((char *)items, numitems, sizeof(items[1]), sortscmp);
        !           442:                print_by_column(looking_for_lognames ? NULL : tilded_dir,
        !           443:                    items, numitems);
        !           444:                if (items != NULL)
        !           445:                        FREE_ITEMS(items);
        !           446:        }
        !           447:        return (0);
        !           448: }
        !           449: 
        !           450: /*
        !           451:  * Object: extend what user typed up to an ambiguity.
        !           452:  * Algorithm:
        !           453:  * On first match, copy full entry (assume it'll be the only match) 
        !           454:  * On subsequent matches, shorten extended_name to the first
        !           455:  * character mismatch between extended_name and entry.
        !           456:  * If we shorten it back to the prefix length, stop searching.
        !           457:  */
        !           458: static
        !           459: recognize(extended_name, entry, name_length, numitems)
        !           460:        char *extended_name, *entry;
        !           461: {
        !           462: 
        !           463:        if (numitems == 1)                      /* 1st match */
        !           464:                copyn(extended_name, entry, MAXNAMLEN);
        !           465:        else {                                  /* 2nd & subsequent matches */
        !           466:                register char *x, *ent;
        !           467:                register int len = 0;
        !           468: 
        !           469:                x = extended_name;
        !           470:                for (ent = entry; *x && *x == *ent++; x++, len++)
        !           471:                        ;
        !           472:                *x = '\0';                      /* Shorten at 1st char diff */
        !           473:                if (len == name_length)         /* Ambiguous to prefix? */
        !           474:                        return (-1);            /* So stop now and save time */
        !           475:        }
        !           476:        return (0);
        !           477: }
        !           478: 
        !           479: /*
        !           480:  * Return true if check matches initial chars in template.
        !           481:  * This differs from PWB imatch in that if check is null
        !           482:  * it matches anything.
        !           483:  */
        !           484: static
        !           485: is_prefix(check, template)
        !           486:        register char *check, *template;
        !           487: {
        !           488: 
        !           489:        do
        !           490:                if (*check == 0)
        !           491:                        return (TRUE);
        !           492:        while (*check++ == *template++);
        !           493:        return (FALSE);
        !           494: }
        !           495: 
        !           496: /*
        !           497:  *  Return true if the chars in template appear at the
        !           498:  *  end of check, I.e., are it's suffix.
        !           499:  */
        !           500: static
        !           501: is_suffix(check, template)
        !           502:        char *check, *template;
        !           503: {
        !           504:        register char *c, *t;
        !           505: 
        !           506:        for (c = check; *c++;)
        !           507:                ;
        !           508:        for (t = template; *t++;)
        !           509:                ;
        !           510:        for (;;) {
        !           511:                if (t == template)
        !           512:                        return 1;
        !           513:                if (c == check || *--t != *--c)
        !           514:                        return 0;
        !           515:        }
        !           516: }
        !           517: 
        !           518: tenex(inputline, inputline_size)
        !           519:        char *inputline;
        !           520:        int inputline_size;
        !           521: {
        !           522:        register int numitems, num_read;
        !           523: 
        !           524:        setup_tty(ON);
        !           525:        while ((num_read = read(SHIN, inputline, inputline_size)) > 0) {
        !           526:                static char *delims = " '\"\t;&<>()|^%";
        !           527:                register char *str_end, *word_start, last_char, should_retype;
        !           528:                register int space_left;
        !           529:                COMMAND command;
        !           530: 
        !           531:                last_char = inputline[num_read - 1] & 0177;
        !           532: 
        !           533:                if (last_char == '\n' || num_read == inputline_size)
        !           534:                        break;
        !           535:                command = (last_char == ESC) ? RECOGNIZE : LIST;
        !           536:                if (command == LIST)
        !           537:                        cshputchar('\n');
        !           538:                str_end = &inputline[num_read];
        !           539:                if (last_char == ESC)
        !           540:                        --str_end;              /* wipeout trailing cmd char */
        !           541:                *str_end = '\0';
        !           542:                /*
        !           543:                 * Find LAST occurence of a delimiter in the inputline.
        !           544:                 * The word start is one character past it.
        !           545:                 */
        !           546:                for (word_start = str_end; word_start > inputline; --word_start)
        !           547:                        if (index(delims, word_start[-1]))
        !           548:                                break;
        !           549:                space_left = inputline_size - (word_start - inputline) - 1;
        !           550:                numitems = search(word_start, command, space_left);
        !           551: 
        !           552:                if (command == RECOGNIZE) {
        !           553:                        /* print from str_end on */
        !           554:                        print_recognized_stuff(str_end);
        !           555:                        if (numitems != 1)      /* Beep = No match/ambiguous */
        !           556:                                beep();
        !           557:                }
        !           558: 
        !           559:                /*
        !           560:                 * Tabs in the input line cause trouble after a pushback.
        !           561:                 * tty driver won't backspace over them because column
        !           562:                 * positions are now incorrect. This is solved by retyping
        !           563:                 * over current line.
        !           564:                 */
        !           565:                should_retype = FALSE;
        !           566:                if (index(inputline, '\t')) {   /* tab char in input line? */
        !           567:                        back_to_col_1();
        !           568:                        should_retype = TRUE;
        !           569:                }
        !           570:                if (command == LIST)            /* Always retype after a LIST */
        !           571:                        should_retype = TRUE;
        !           572:                if (should_retype)
        !           573:                        printprompt();
        !           574:                pushback(inputline);
        !           575:                if (should_retype)
        !           576:                        retype();
        !           577:        }
        !           578:        setup_tty(OFF);
        !           579:        return (num_read);
        !           580: }
        !           581: 
        !           582: static
        !           583: ignored(entry)
        !           584:        register char *entry;
        !           585: {
        !           586:        struct varent *vp;
        !           587:        register char **cp;
        !           588: 
        !           589:        if ((vp = adrof("fignore")) == NULL || (cp = vp->vec) == NULL)
        !           590:                return (FALSE);
        !           591:        for (; *cp != NULL; cp++)
        !           592:                if (is_suffix(entry, *cp))
        !           593:                        return (TRUE);
        !           594:        return (FALSE);
        !           595: }
        !           596: #endif FILEC

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.