1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.file.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */
   2: /*
   3:  * sh.file.c: File completion for csh.
   4:  */
   5: /*-
   6:  * Copyright (c) 1980, 1991 The Regents of the University of California.
   7:  * All rights reserved.
   8:  *
   9:  * Redistribution and use in source and binary forms, with or without
  10:  * modification, are permitted provided that the following conditions
  11:  * are met:
  12:  * 1. Redistributions of source code must retain the above copyright
  13:  *    notice, this list of conditions and the following disclaimer.
  14:  * 2. Redistributions in binary form must reproduce the above copyright
  15:  *    notice, this list of conditions and the following disclaimer in the
  16:  *    documentation and/or other materials provided with the distribution.
  17:  * 3. All advertising materials mentioning features or use of this software
  18:  *    must display the following acknowledgement:
  19:  *	This product includes software developed by the University of
  20:  *	California, Berkeley and its contributors.
  21:  * 4. Neither the name of the University nor the names of its contributors
  22:  *    may be used to endorse or promote products derived from this software
  23:  *    without specific prior written permission.
  24:  *
  25:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35:  * SUCH DAMAGE.
  36:  */
  37: #ifdef FILEC
  38: #include "config.h"
  39: #ifndef lint
  40: static char *rcsid()
  41:     { return "$Id: sh.file.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; }
  42: #endif
  43: 
  44: #include "sh.h"
  45: 
  46: /*
  47:  * Tenex style file name recognition, .. and more.
  48:  * History:
  49:  *	Author: Ken Greer, Sept. 1975, CMU.
  50:  *	Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
  51:  */
  52: 
  53: #define ON  1
  54: #define OFF 0
  55: #ifndef TRUE
  56: #define TRUE 1
  57: #endif
  58: #ifndef FALSE
  59: #define FALSE 0
  60: #endif
  61: 
  62: #define ESC '\033'
  63: 
  64: typedef enum {
  65:     LIST, RECOGNIZE
  66: }       COMMAND;
  67: 
  68: static  void     setup_tty      __P((int));
  69: static  void     back_to_col_1      __P((void));
  70: static  void     pushback       __P((Char *));
  71: static  void     catn           __P((Char *, Char *, int));
  72: static  void     copyn          __P((Char *, Char *, int));
  73: static  Char     filetype       __P((Char *, Char *));
  74: static  void     print_by_column    __P((Char *, Char *[], int));
  75: static  Char    *tilde          __P((Char *, Char *));
  76: static  void     retype         __P((void));
  77: static  void     beep           __P((void));
  78: static  void     print_recog_stuff  __P((Char *));
  79: static  void     extract_dir_and_name   __P((Char *, Char *, Char *));
  80: static  Char    *getentry       __P((DIR *, int));
  81: static  void     free_items     __P((Char **));
  82: static  int  tsearch        __P((Char *, COMMAND, int));
  83: static  int  recognize      __P((Char *, Char *, int, int));
  84: static  int  is_prefix      __P((Char *, Char *));
  85: static  int  is_suffix      __P((Char *, Char *));
  86: static  int  ignored        __P((Char *));
  87: 
  88: 
  89: /*
  90:  * Put this here so the binary can be patched with adb to enable file
  91:  * completion by default.  Filec controls completion, nobeep controls
  92:  * ringing the terminal bell on incomplete expansions.
  93:  */
  94: bool    filec = 0;
  95: 
  96: static void
  97: setup_tty(on)
  98:     int     on;
  99: {
 100: #ifdef TERMIOS
 101:     static struct termios tchars;
 102: 
 103:     if (on) {
 104:     (void) tcgetattr(SHIN, &tchars);
 105:     tchars.c_cc[VEOL] = ESC;
 106:     if (tchars.c_lflag & ICANON)
 107:         on = TCSANOW;
 108:     else {
 109:         on = TCSAFLUSH;
 110:         tchars.c_lflag |= ICANON;
 111:     }
 112:         (void) tcsetattr(SHIN, on, &tchars);
 113:     }
 114:     else {
 115:     tchars.c_cc[VEOL] = _POSIX_VDISABLE;
 116:     (void) tcsetattr(SHIN, TCSANOW, &tchars);
 117:     }
 118: #else
 119:     struct sgttyb sgtty;
 120:     static struct tchars tchars;/* INT, QUIT, XON, XOFF, EOF, BRK */
 121: 
 122:     if (on) {
 123:     (void) ioctl(SHIN, TIOCGETC, (ioctl_t) & tchars);
 124:     tchars.t_brkc = ESC;
 125:     (void) ioctl(SHIN, TIOCSETC, (ioctl_t) & tchars);
 126:     /*
 127: 	 * This must be done after every command: if the tty gets into raw or
 128: 	 * cbreak mode the user can't even type 'reset'.
 129: 	 */
 130:     (void) ioctl(SHIN, TIOCGETP, (ioctl_t) & sgtty);
 131:     if (sgtty.sg_flags & (RAW | CBREAK)) {
 132:         sgtty.sg_flags &= ~(RAW | CBREAK);
 133:         (void) ioctl(SHIN, TIOCSETP, (ioctl_t) & sgtty);
 134:     }
 135:     }
 136:     else {
 137:     tchars.t_brkc = -1;
 138:     (void) ioctl(SHIN, TIOCSETC, (ioctl_t) & tchars);
 139:     }
 140: #endif
 141: }
 142: 
 143: /*
 144:  * Move back to beginning of current line
 145:  */
 146: static void
 147: back_to_col_1()
 148: {
 149: #ifdef TERMIOS
 150:     struct termios tty, tty_normal;
 151:     sigmask_t     omask;
 152: 
 153:     omask = sigblock(sigmask(SIGINT));
 154:     (void) tcgetattr(SHOUT, &tty);
 155:     tty_normal = tty;
 156:     tty.c_iflag &= ~INLCR;
 157:     tty.c_oflag &= ~ONLCR;
 158:     (void) tcsetattr(SHOUT, TCSANOW, &tty);
 159:     (void) write(SHOUT, "\r", 1);
 160:     (void) tcsetattr(SHOUT, TCSANOW, &tty_normal);
 161:     (void) sigsetmask(omask);
 162: #else
 163:     struct sgttyb tty, tty_normal;
 164:     sigmask_t     omask;
 165: 
 166:     omask = sigblock(sigmask(SIGINT));
 167:     (void) ioctl(SHIN, TIOCGETP, (ioctl_t) & tty);
 168:     tty_normal = tty;
 169:     tty.sg_flags &= ~CRMOD;
 170:     (void) ioctl(SHIN, TIOCSETN, (ioctl_t) & tty);
 171:     (void) write(SHOUT, "\r", 1);
 172:     (void) ioctl(SHIN, TIOCSETN, (ioctl_t) & tty_normal);
 173:     (void) sigsetmask(omask);
 174: #endif
 175: }
 176: 
 177: /*
 178:  * Push string contents back into tty queue
 179:  */
 180: static void
 181: pushback(string)
 182:     Char   *string;
 183: {
 184: #ifdef TERMIOS
 185:     register Char *p;
 186:     struct termios tty, tty_normal;
 187:     sigmask_t     omask;
 188:     char    c;
 189: 
 190:     omask = sigblock(sigmask(SIGINT));
 191:     (void) tcgetattr(SHOUT, &tty);
 192:     tty_normal = tty;
 193:     tty.c_lflag &= ~(ECHOKE | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOCTL);
 194:     (void) tcsetattr(SHOUT, TCSANOW, &tty);
 195: 
 196:     for (p = string; c = *p; p++)
 197:     (void) ioctl(SHOUT, TIOCSTI, (ioctl_t) & c);
 198:     (void) tcsetattr(SHOUT, TCSANOW, &tty_normal);
 199:     (void) sigsetmask(omask);
 200: #else
 201:     register Char *p;
 202:     struct sgttyb tty, tty_normal;
 203:     sigmask_t     omask;
 204:     char    c;
 205: 
 206:     omask = sigblock(sigmask(SIGINT));
 207:     (void) ioctl(SHOUT, TIOCGETP, (ioctl_t) & tty);
 208:     tty_normal = tty;
 209:     tty.sg_flags &= ~ECHO;
 210:     (void) ioctl(SHOUT, TIOCSETN, (ioctl_t) & tty);
 211: 
 212:     for (p = string; c = *p; p++)
 213:     (void) ioctl(SHOUT, TIOCSTI, (ioctl_t) & c);
 214:     (void) ioctl(SHOUT, TIOCSETN, (ioctl_t) & tty_normal);
 215:     (void) sigsetmask(omask);
 216: #endif
 217: }
 218: 
 219: /*
 220:  * Concatenate src onto tail of des.
 221:  * Des is a string whose maximum length is count.
 222:  * Always null terminate.
 223:  */
 224: static void
 225: catn(des, src, count)
 226:     register Char *des, *src;
 227:     register count;
 228: {
 229:     while (--count >= 0 && *des)
 230:     des++;
 231:     while (--count >= 0)
 232:     if ((*des++ = *src++) == 0)
 233:         return;
 234:     *des = '\0';
 235: }
 236: 
 237: /*
 238:  * Like strncpy but always leave room for trailing \0
 239:  * and always null terminate.
 240:  */
 241: static void
 242: copyn(des, src, count)
 243:     register Char *des, *src;
 244:     register count;
 245: {
 246:     while (--count >= 0)
 247:     if ((*des++ = *src++) == 0)
 248:         return;
 249:     *des = '\0';
 250: }
 251: 
 252: static  Char
 253: filetype(dir, file)
 254:     Char   *dir, *file;
 255: {
 256:     Char    path[MAXPATHLEN];
 257:     struct stat statb;
 258: 
 259:     catn(Strcpy(path, dir), file, sizeof(path) / sizeof(Char));
 260:     if (lstat(short2str(path), &statb) == 0) {
 261:     switch (statb.st_mode & S_IFMT) {
 262:     case S_IFDIR:
 263:         return ('/');
 264: 
 265:     case S_IFLNK:
 266:         if (stat(short2str(path), &statb) == 0 &&   /* follow it out */
 267:         S_ISDIR(statb.st_mode))
 268:         return ('>');
 269:         else
 270:         return ('@');
 271: 
 272:     case S_IFSOCK:
 273:         return ('=');
 274: 
 275:     default:
 276:         if (statb.st_mode & 0111)
 277:         return ('*');
 278:     }
 279:     }
 280:     return (' ');
 281: }
 282: 
 283: static struct winsize win;
 284: 
 285: /*
 286:  * Print sorted down columns
 287:  */
 288: static void
 289: print_by_column(dir, items, count)
 290:     Char   *dir, *items[];
 291:     int     count;
 292: {
 293:     register int i, rows, r, c, maxwidth = 0, columns;
 294: 
 295:     if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & win) < 0 || win.ws_col == 0)
 296:     win.ws_col = 80;
 297:     for (i = 0; i < count; i++)
 298:     maxwidth = maxwidth > (r = Strlen(items[i])) ? maxwidth : r;
 299:     maxwidth += 2;      /* for the file tag and space */
 300:     columns = win.ws_col / maxwidth;
 301:     if (columns == 0)
 302:     columns = 1;
 303:     rows = (count + (columns - 1)) / columns;
 304:     for (r = 0; r < rows; r++) {
 305:     for (c = 0; c < columns; c++) {
 306:         i = c * rows + r;
 307:         if (i < count) {
 308:         register int w;
 309: 
 310:         xprintf("%s", short2str(items[i]));
 311:         xputchar(dir ? filetype(dir, items[i]) : ' ');
 312:         if (c < columns - 1) {  /* last column? */
 313:             w = Strlen(items[i]) + 1;
 314:             for (; w < maxwidth; w++)
 315:             xputchar(' ');
 316:         }
 317:         }
 318:     }
 319:     xputchar('\r');
 320:     xputchar('\n');
 321:     }
 322: }
 323: 
 324: /*
 325:  * Expand file name with possible tilde usage
 326:  *	~person/mumble
 327:  * expands to
 328:  *	home_directory_of_person/mumble
 329:  */
 330: static Char *
 331: tilde(new, old)
 332:     Char   *new, *old;
 333: {
 334:     register Char *o, *p;
 335:     register struct passwd *pw;
 336:     static Char person[40];
 337: 
 338:     if (old[0] != '~')
 339:     return (Strcpy(new, old));
 340: 
 341:     for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++);
 342:     *p = '\0';
 343:     if (person[0] == '\0')
 344:     (void) Strcpy(new, value(STRhome));
 345:     else {
 346:     pw = getpwnam(short2str(person));
 347:     if (pw == NULL)
 348:         return (NULL);
 349:     (void) Strcpy(new, str2short(pw->pw_dir));
 350:     }
 351:     (void) Strcat(new, o);
 352:     return (new);
 353: }
 354: 
 355: /*
 356:  * Cause pending line to be printed
 357:  */
 358: static void
 359: retype()
 360: {
 361: #ifdef TERMIOS
 362:     struct termios tty;
 363: 
 364:     (void) tcgetattr(SHOUT, &tty);
 365:     tty.c_lflag |= PENDIN;
 366:     (void) tcsetattr(SHOUT, TCSANOW, &tty);
 367: #else
 368:     int     pending_input = LPENDIN;
 369: 
 370:     (void) ioctl(SHOUT, TIOCLBIS, (ioctl_t) & pending_input);
 371: #endif
 372: }
 373: 
 374: static void
 375: beep()
 376: {
 377:     if (adrof(STRnobeep) == 0)
 378:     (void) write(SHOUT, "\007", 1);
 379: }
 380: 
 381: /*
 382:  * Erase that silly ^[ and
 383:  * print the recognized part of the string
 384:  */
 385: static void
 386: print_recog_stuff(recog_part)
 387:     Char   *recog_part;
 388: {
 389:     /* An optimized erasing of that silly ^[ */
 390:     putraw('\b');
 391:     putraw('\b');
 392:     switch (Strlen(recog_part)) {
 393: 
 394:     case 0:         /* erase two Characters: ^[ */
 395:     putraw(' ');
 396:     putraw(' ');
 397:     putraw('\b');
 398:     putraw('\b');
 399:     break;
 400: 
 401:     case 1:         /* overstrike the ^, erase the [ */
 402:     xprintf("%s", short2str(recog_part));
 403:     putraw(' ');
 404:     putraw('\b');
 405:     break;
 406: 
 407:     default:            /* overstrike both Characters ^[ */
 408:     xprintf("%s", short2str(recog_part));
 409:     break;
 410:     }
 411:     flush();
 412: }
 413: 
 414: /*
 415:  * Parse full path in file into 2 parts: directory and file names
 416:  * Should leave final slash (/) at end of dir.
 417:  */
 418: static void
 419: extract_dir_and_name(path, dir, name)
 420:     Char   *path, *dir, *name;
 421: {
 422:     register Char *p;
 423: 
 424:     p = Strrchr(path, '/');
 425:     if (p == NULL) {
 426:     copyn(name, path, MAXNAMLEN);
 427:     dir[0] = '\0';
 428:     }
 429:     else {
 430:     copyn(name, ++p, MAXNAMLEN);
 431:     copyn(dir, path, p - path);
 432:     }
 433: }
 434: 
 435: static Char *
 436: getentry(dir_fd, look_lognames)
 437:     DIR    *dir_fd;
 438:     int     look_lognames;
 439: {
 440:     register struct passwd *pw;
 441:     register struct dirent *dirp;
 442: 
 443:     if (look_lognames) {
 444:     if ((pw = getpwent()) == NULL)
 445:         return (NULL);
 446:     return (str2short(pw->pw_name));
 447:     }
 448:     if (dirp = readdir(dir_fd))
 449:     return (str2short(dirp->d_name));
 450:     return (NULL);
 451: }
 452: 
 453: static void
 454: free_items(items)
 455:     register Char **items;
 456: {
 457:     register int i;
 458: 
 459:     for (i = 0; items[i]; i++)
 460:     xfree((ptr_t) items[i]);
 461:     xfree((ptr_t) items);
 462: }
 463: 
 464: #define FREE_ITEMS(items) { \
 465:     sigmask_t omask;\
 466: \
 467:     omask = sigblock(sigmask(SIGINT));\
 468:     free_items(items);\
 469:     items = NULL;\
 470:     (void) sigsetmask(omask);\
 471: }
 472: 
 473: /*
 474:  * Perform a RECOGNIZE or LIST command on string "word".
 475:  */
 476: static int
 477: tsearch(word, command, max_word_length)
 478:     Char   *word;
 479:     int     max_word_length;
 480:     COMMAND command;
 481: {
 482:     static Char **items = NULL;
 483:     register DIR *dir_fd;
 484:     register numitems = 0, ignoring = TRUE, nignored = 0;
 485:     register name_length, look_lognames;
 486:     Char    tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1];
 487:     Char    name[MAXNAMLEN + 1], extended_name[MAXNAMLEN + 1];
 488:     Char   *entry;
 489: 
 490: #define MAXITEMS 1024
 491: 
 492:     if (items != NULL)
 493:     FREE_ITEMS(items);
 494: 
 495:     look_lognames = (*word == '~') && (Strchr(word, '/') == NULL);
 496:     if (look_lognames) {
 497:     (void) setpwent();
 498:     copyn(name, &word[1], MAXNAMLEN);   /* name sans ~ */
 499:     dir_fd = NULL;
 500:     }
 501:     else {
 502:     extract_dir_and_name(word, dir, name);
 503:     if (tilde(tilded_dir, dir) == 0)
 504:         return (0);
 505:     dir_fd = opendir(*tilded_dir ? short2str(tilded_dir) : ".");
 506:     if (dir_fd == NULL)
 507:         return (0);
 508:     }
 509: 
 510: again:              /* search for matches */
 511:     name_length = Strlen(name);
 512:     for (numitems = 0; entry = getentry(dir_fd, look_lognames);) {
 513:     if (!is_prefix(name, entry))
 514:         continue;
 515:     /* Don't match . files on null prefix match */
 516:     if (name_length == 0 && entry[0] == '.' &&
 517:         !look_lognames)
 518:         continue;
 519:     if (command == LIST) {
 520:         if (numitems >= MAXITEMS) {
 521:         xprintf("\nYikes!! Too many %s!!\n",
 522:             look_lognames ?
 523:             "names in password file" : "files");
 524:         break;
 525:         }
 526:         if (items == NULL)
 527:         items = (Char **) xcalloc(sizeof(items[0]), MAXITEMS);
 528:         items[numitems] = (Char *) xmalloc((size_t) (Strlen(entry) + 1) *
 529:                            sizeof(Char));
 530:         copyn(items[numitems], entry, MAXNAMLEN);
 531:         numitems++;
 532:     }
 533:     else {          /* RECOGNIZE command */
 534:         if (ignoring && ignored(entry))
 535:         nignored++;
 536:         else if (recognize(extended_name,
 537:                    entry, name_length, ++numitems))
 538:         break;
 539:     }
 540:     }
 541:     if (ignoring && numitems == 0 && nignored > 0) {
 542:     ignoring = FALSE;
 543:     nignored = 0;
 544:     if (look_lognames)
 545:         (void) setpwent();
 546:     else
 547:         rewinddir(dir_fd);
 548:     goto again;
 549:     }
 550: 
 551:     if (look_lognames)
 552:     (void) endpwent();
 553:     else
 554:     (void) closedir(dir_fd);
 555:     if (numitems == 0)
 556:     return (0);
 557:     if (command == RECOGNIZE) {
 558:     if (look_lognames)
 559:         copyn(word, STRtilde, 1);
 560:     else
 561:         /* put back dir part */
 562:         copyn(word, dir, max_word_length);
 563:     /* add extended name */
 564:     catn(word, extended_name, max_word_length);
 565:     return (numitems);
 566:     }
 567:     else {          /* LIST */
 568:     qsort((ptr_t) items, numitems, sizeof(items[0]), sortscmp);
 569:     print_by_column(look_lognames ? NULL : tilded_dir,
 570:             items, numitems);
 571:     if (items != NULL)
 572:         FREE_ITEMS(items);
 573:     }
 574:     return (0);
 575: }
 576: 
 577: /*
 578:  * Object: extend what user typed up to an ambiguity.
 579:  * Algorithm:
 580:  * On first match, copy full entry (assume it'll be the only match)
 581:  * On subsequent matches, shorten extended_name to the first
 582:  * Character mismatch between extended_name and entry.
 583:  * If we shorten it back to the prefix length, stop searching.
 584:  */
 585: static int
 586: recognize(extended_name, entry, name_length, numitems)
 587:     Char   *extended_name, *entry;
 588:     int     name_length, numitems;
 589: {
 590:     if (numitems == 1)      /* 1st match */
 591:     copyn(extended_name, entry, MAXNAMLEN);
 592:     else {          /* 2nd & subsequent matches */
 593:     register Char *x, *ent;
 594:     register int len = 0;
 595: 
 596:     x = extended_name;
 597:     for (ent = entry; *x && *x == *ent++; x++, len++);
 598:     *x = '\0';      /* Shorten at 1st Char diff */
 599:     if (len == name_length) /* Ambiguous to prefix? */
 600:         return (-1);    /* So stop now and save time */
 601:     }
 602:     return (0);
 603: }
 604: 
 605: /*
 606:  * Return true if check matches initial Chars in template.
 607:  * This differs from PWB imatch in that if check is null
 608:  * it matches anything.
 609:  */
 610: static int
 611: is_prefix(check, template)
 612:     register Char *check, *template;
 613: {
 614:     do
 615:     if (*check == 0)
 616:         return (TRUE);
 617:     while (*check++ == *template++);
 618:     return (FALSE);
 619: }
 620: 
 621: /*
 622:  *  Return true if the Chars in template appear at the
 623:  *  end of check, I.e., are it's suffix.
 624:  */
 625: static int
 626: is_suffix(check, template)
 627:     Char   *check, *template;
 628: {
 629:     register Char *c, *t;
 630: 
 631:     for (c = check; *c++;);
 632:     for (t = template; *t++;);
 633:     for (;;) {
 634:     if (t == template)
 635:         return 1;
 636:     if (c == check || *--t != *--c)
 637:         return 0;
 638:     }
 639: }
 640: 
 641: int
 642: tenex(in_line, in_li_size)
 643:     Char   *in_line;
 644:     int     in_li_size;
 645: {
 646:     register int numitems, num_read;
 647:     char    tin_line[BUFSIZ];
 648: 
 649: 
 650:     setup_tty(ON);
 651: 
 652:     while ((num_read = read(SHIN, tin_line, BUFSIZ)) > 0) {
 653:     int     i;
 654:     static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<',
 655:     '>', '(', ')', '|', '^', '%', '\0'};
 656:     register Char *str_end, *word_start, last_Char, should_retype;
 657:     register int space_left;
 658:     COMMAND command;
 659: 
 660:     for (i = 0; i < num_read; i++)
 661:         in_line[i] = (unsigned char) tin_line[i];
 662:     last_Char = in_line[num_read - 1] & ASCII;
 663: 
 664:     if (last_Char == '\n' || num_read == in_li_size)
 665:         break;
 666:     command = (last_Char == ESC) ? RECOGNIZE : LIST;
 667:     if (command == LIST)
 668:         xputchar('\n');
 669:     str_end = &in_line[num_read];
 670:     if (last_Char == ESC)
 671:         --str_end;      /* wipeout trailing cmd Char */
 672:     *str_end = '\0';
 673:     /*
 674: 	 * Find LAST occurence of a delimiter in the in_line. The word start
 675: 	 * is one Character past it.
 676: 	 */
 677:     for (word_start = str_end; word_start > in_line; --word_start)
 678:         if (Strchr(delims, word_start[-1]))
 679:         break;
 680:     space_left = in_li_size - (word_start - in_line) - 1;
 681:     numitems = tsearch(word_start, command, space_left);
 682: 
 683:     if (command == RECOGNIZE) {
 684:         /* print from str_end on */
 685:         print_recog_stuff(str_end);
 686:         if (numitems != 1)  /* Beep = No match/ambiguous */
 687:         beep();
 688:     }
 689: 
 690:     /*
 691: 	 * Tabs in the input line cause trouble after a pushback. tty driver
 692: 	 * won't backspace over them because column positions are now
 693: 	 * incorrect. This is solved by retyping over current line.
 694: 	 */
 695:     should_retype = FALSE;
 696:     if (Strchr(in_line, '\t')) {    /* tab Char in input line? */
 697:         back_to_col_1();
 698:         should_retype = TRUE;
 699:     }
 700:     if (command == LIST)    /* Always retype after a LIST */
 701:         should_retype = TRUE;
 702:     if (should_retype)
 703:         printprompt();
 704:     pushback(in_line);
 705:     if (should_retype)
 706:         retype();
 707:     }
 708:     setup_tty(OFF);
 709:     return (num_read);
 710: }
 711: 
 712: static int
 713: ignored(entry)
 714:     register Char *entry;
 715: {
 716:     struct varent *vp;
 717:     register Char **cp;
 718: 
 719:     if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL)
 720:     return (FALSE);
 721:     for (; *cp != NULL; cp++)
 722:     if (is_suffix(entry, *cp))
 723:         return (TRUE);
 724:     return (FALSE);
 725: }
 726: #endif				/* FILEC */

Defined functions

back_to_col_1 defined in line 146; used 1 times
beep defined in line 374; used 1 times
catn defined in line 224; used 2 times
copyn defined in line 241; used 8 times
extract_dir_and_name defined in line 418; used 1 times
filetype defined in line 252; used 1 times
free_items defined in line 453; used 1 times
getentry defined in line 435; used 1 times
ignored defined in line 712; used 1 times
is_prefix defined in line 610; used 1 times
is_suffix defined in line 625; used 1 times
print_by_column defined in line 288; used 1 times
print_recog_stuff defined in line 385; used 1 times
pushback defined in line 180; used 1 times
rcsid defined in line 40; never used
recognize defined in line 585; used 1 times
retype defined in line 358; used 1 times
setup_tty defined in line 96; used 2 times
tenex defined in line 641; never used
tilde defined in line 330; used 1 times
tsearch defined in line 476; used 1 times

Defined variables

filec defined in line 94; never used
win defined in line 283; used 4 times

Defined typedef's

COMMAND defined in line 66; used 3 times

Defined macros

ESC defined in line 62; used 4 times
FALSE defined in line 59; used 6 times
FREE_ITEMS defined in line 464; used 2 times
MAXITEMS defined in line 490; used 2 times
OFF defined in line 54; used 1 times
ON defined in line 53; used 1 times
TRUE defined in line 56; used 6 times
Last modified: 1991-08-30
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 24
Valid CSS Valid XHTML 1.0 Strict