1: /*
   2:  * Copyright (c) 1985 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[] = "@(#)interactive.c	5.3 (Berkeley) 7/21/85";
   9: #endif not lint
  10: 
  11: #include "restore.h"
  12: #include <protocols/dumprestore.h>
  13: #include <setjmp.h>
  14: 
  15: #define round(a, b) (((a) + (b) - 1) / (b) * (b))
  16: 
  17: /*
  18:  * Things to handle interruptions.
  19:  */
  20: static jmp_buf reset;
  21: static char *nextarg = NULL;
  22: 
  23: /*
  24:  * Structure and routines associated with listing directories.
  25:  */
  26: struct afile {
  27:     ino_t   fnum;       /* inode number of file */
  28:     char    *fname;     /* file name */
  29:     short   fflags;     /* extraction flags, if any */
  30:     char    ftype;      /* file type, e.g. LEAF or NODE */
  31: };
  32: struct arglist {
  33:     struct afile    *head;  /* start of argument list */
  34:     struct afile    *last;  /* end of argument list */
  35:     struct afile    *base;  /* current list arena */
  36:     int     nent;   /* maximum size of list */
  37:     char        *cmd;   /* the current command */
  38: };
  39: extern int fcmp();
  40: extern char *fmtentry();
  41: char *copynext();
  42: 
  43: /*
  44:  * Read and execute commands from the terminal.
  45:  */
  46: runcmdshell()
  47: {
  48:     register struct entry *np;
  49:     ino_t ino;
  50:     static struct arglist alist = { 0, 0, 0, 0, 0 };
  51:     char curdir[MAXPATHLEN];
  52:     char name[MAXPATHLEN];
  53:     char cmd[BUFSIZ];
  54: 
  55:     canon("/", curdir);
  56: loop:
  57:     if (setjmp(reset) != 0) {
  58:         for (; alist.head < alist.last; alist.head++)
  59:             freename(alist.head->fname);
  60:         nextarg = NULL;
  61:         volno = 0;
  62:     }
  63:     getcmd(curdir, cmd, name, &alist);
  64:     switch (cmd[0]) {
  65:     /*
  66: 	 * Add elements to the extraction list.
  67: 	 */
  68:     case 'a':
  69:         ino = dirlookup(name);
  70:         if (ino == 0)
  71:             break;
  72:         if (mflag)
  73:             pathcheck(name);
  74:         treescan(name, ino, addfile);
  75:         break;
  76:     /*
  77: 	 * Change working directory.
  78: 	 */
  79:     case 'c':
  80:         ino = dirlookup(name);
  81:         if (ino == 0)
  82:             break;
  83:         if (inodetype(ino) == LEAF) {
  84:             fprintf(stderr, "%s: not a directory\n", name);
  85:             break;
  86:         }
  87:         (void) strcpy(curdir, name);
  88:         break;
  89:     /*
  90: 	 * Delete elements from the extraction list.
  91: 	 */
  92:     case 'd':
  93:         np = lookupname(name);
  94:         if (np == NIL || (np->e_flags & NEW) == 0) {
  95:             fprintf(stderr, "%s: not on extraction list\n", name);
  96:             break;
  97:         }
  98:         treescan(name, np->e_ino, deletefile);
  99:         break;
 100:     /*
 101: 	 * Extract the requested list.
 102: 	 */
 103:     case 'e':
 104:         createfiles();
 105:         createlinks();
 106:         setdirmodes();
 107:         if (dflag)
 108:             checkrestore();
 109:         volno = 0;
 110:         break;
 111:     /*
 112: 	 * List available commands.
 113: 	 */
 114:     case 'h':
 115:     case '?':
 116:         fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
 117:             "Available commands are:\n",
 118:             "\tls [arg] - list directory\n",
 119:             "\tcd arg - change directory\n",
 120:             "\tpwd - print current directory\n",
 121:             "\tadd [arg] - add `arg' to list of",
 122:             " files to be extracted\n",
 123:             "\tdelete [arg] - delete `arg' from",
 124:             " list of files to be extracted\n",
 125:             "\textract - extract requested files\n",
 126:             "\tsetmodes - set modes of requested directories\n",
 127:             "\tquit - immediately exit program\n",
 128:             "\tverbose - toggle verbose flag",
 129:             " (useful with ``ls'')\n",
 130:             "\thelp or `?' - print this list\n",
 131:             "If no `arg' is supplied, the current",
 132:             " directory is used\n");
 133:         break;
 134:     /*
 135: 	 * List a directory.
 136: 	 */
 137:     case 'l':
 138:         ino = dirlookup(name);
 139:         if (ino == 0)
 140:             break;
 141:         printlist(name, ino, curdir);
 142:         break;
 143:     /*
 144: 	 * Print current directory.
 145: 	 */
 146:     case 'p':
 147:         if (curdir[1] == '\0')
 148:             fprintf(stderr, "/\n");
 149:         else
 150:             fprintf(stderr, "%s\n", &curdir[1]);
 151:         break;
 152:     /*
 153: 	 * Quit.
 154: 	 */
 155:     case 'q':
 156:     case 'x':
 157:         return;
 158:     /*
 159: 	 * Toggle verbose mode.
 160: 	 */
 161:     case 'v':
 162:         if (vflag) {
 163:             fprintf(stderr, "verbose mode off\n");
 164:             vflag = 0;
 165:             break;
 166:         }
 167:         fprintf(stderr, "verbose mode on\n");
 168:         vflag++;
 169:         break;
 170:     /*
 171: 	 * Just restore requested directory modes.
 172: 	 */
 173:     case 's':
 174:         setdirmodes();
 175:         break;
 176:     /*
 177: 	 * Turn on debugging.
 178: 	 */
 179:     case 'D':
 180:         if (dflag) {
 181:             fprintf(stderr, "debugging mode off\n");
 182:             dflag = 0;
 183:             break;
 184:         }
 185:         fprintf(stderr, "debugging mode on\n");
 186:         dflag++;
 187:         break;
 188:     /*
 189: 	 * Unknown command.
 190: 	 */
 191:     default:
 192:         fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
 193:         break;
 194:     }
 195:     goto loop;
 196: }
 197: 
 198: /*
 199:  * Read and parse an interactive command.
 200:  * The first word on the line is assigned to "cmd". If
 201:  * there are no arguments on the command line, then "curdir"
 202:  * is returned as the argument. If there are arguments
 203:  * on the line they are returned one at a time on each
 204:  * successive call to getcmd. Each argument is first assigned
 205:  * to "name". If it does not start with "/" the pathname in
 206:  * "curdir" is prepended to it. Finally "canon" is called to
 207:  * eliminate any embedded ".." components.
 208:  */
 209: getcmd(curdir, cmd, name, ap)
 210:     char *curdir, *cmd, *name;
 211:     struct arglist *ap;
 212: {
 213:     register char *cp;
 214:     static char input[BUFSIZ];
 215:     char output[BUFSIZ];
 216: #	define rawname input  /* save space by reusing input buffer */
 217: 
 218:     /*
 219: 	 * Check to see if still processing arguments.
 220: 	 */
 221:     if (ap->head != ap->last) {
 222:         strcpy(name, ap->head->fname);
 223:         freename(ap->head->fname);
 224:         ap->head++;
 225:         return;
 226:     }
 227:     if (nextarg != NULL)
 228:         goto getnext;
 229:     /*
 230: 	 * Read a command line and trim off trailing white space.
 231: 	 */
 232:     do  {
 233:         fprintf(stderr, "restore > ");
 234:         (void) fflush(stderr);
 235:         (void) fgets(input, BUFSIZ, terminal);
 236:     } while (!feof(terminal) && input[0] == '\n');
 237:     if (feof(terminal)) {
 238:         (void) strcpy(cmd, "quit");
 239:         return;
 240:     }
 241:     for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
 242:         /* trim off trailing white space and newline */;
 243:     *++cp = '\0';
 244:     /*
 245: 	 * Copy the command into "cmd".
 246: 	 */
 247:     cp = copynext(input, cmd);
 248:     ap->cmd = cmd;
 249:     /*
 250: 	 * If no argument, use curdir as the default.
 251: 	 */
 252:     if (*cp == '\0') {
 253:         (void) strcpy(name, curdir);
 254:         return;
 255:     }
 256:     nextarg = cp;
 257:     /*
 258: 	 * Find the next argument.
 259: 	 */
 260: getnext:
 261:     cp = copynext(nextarg, rawname);
 262:     if (*cp == '\0')
 263:         nextarg = NULL;
 264:     else
 265:         nextarg = cp;
 266:     /*
 267: 	 * If it an absolute pathname, canonicalize it and return it.
 268: 	 */
 269:     if (rawname[0] == '/') {
 270:         canon(rawname, name);
 271:     } else {
 272:         /*
 273: 		 * For relative pathnames, prepend the current directory to
 274: 		 * it then canonicalize and return it.
 275: 		 */
 276:         (void) strcpy(output, curdir);
 277:         (void) strcat(output, "/");
 278:         (void) strcat(output, rawname);
 279:         canon(output, name);
 280:     }
 281:     expandarg(name, ap);
 282:     strcpy(name, ap->head->fname);
 283:     freename(ap->head->fname);
 284:     ap->head++;
 285: #	undef rawname
 286: }
 287: 
 288: /*
 289:  * Strip off the next token of the input.
 290:  */
 291: char *
 292: copynext(input, output)
 293:     char *input, *output;
 294: {
 295:     register char *cp, *bp;
 296:     char quote;
 297: 
 298:     for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
 299:         /* skip to argument */;
 300:     bp = output;
 301:     while (*cp != ' ' && *cp != '\t' && *cp != '\0') {
 302:         /*
 303: 		 * Handle back slashes.
 304: 		 */
 305:         if (*cp == '\\') {
 306:             if (*++cp == '\0') {
 307:                 fprintf(stderr,
 308:                     "command lines cannot be continued\n");
 309:                 continue;
 310:             }
 311:             *bp++ = *cp++;
 312:             continue;
 313:         }
 314:         /*
 315: 		 * The usual unquoted case.
 316: 		 */
 317:         if (*cp != '\'' && *cp != '"') {
 318:             *bp++ = *cp++;
 319:             continue;
 320:         }
 321:         /*
 322: 		 * Handle single and double quotes.
 323: 		 */
 324:         quote = *cp++;
 325:         while (*cp != quote && *cp != '\0')
 326:             *bp++ = *cp++ | 0200;
 327:         if (*cp++ == '\0') {
 328:             fprintf(stderr, "missing %c\n", quote);
 329:             cp--;
 330:             continue;
 331:         }
 332:     }
 333:     *bp = '\0';
 334:     return (cp);
 335: }
 336: 
 337: /*
 338:  * Canonicalize file names to always start with ``./'' and
 339:  * remove any imbedded "." and ".." components.
 340:  */
 341: canon(rawname, canonname)
 342:     char *rawname, *canonname;
 343: {
 344:     register char *cp, *np;
 345:     int len;
 346: 
 347:     if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
 348:         (void) strcpy(canonname, "");
 349:     else if (rawname[0] == '/')
 350:         (void) strcpy(canonname, ".");
 351:     else
 352:         (void) strcpy(canonname, "./");
 353:     (void) strcat(canonname, rawname);
 354:     /*
 355: 	 * Eliminate multiple and trailing '/'s
 356: 	 */
 357:     for (cp = np = canonname; *np != '\0'; cp++) {
 358:         *cp = *np++;
 359:         while (*cp == '/' && *np == '/')
 360:             np++;
 361:     }
 362:     *cp = '\0';
 363:     if (*--cp == '/')
 364:         *cp = '\0';
 365:     /*
 366: 	 * Eliminate extraneous "." and ".." from pathnames.
 367: 	 */
 368:     for (np = canonname; *np != '\0'; ) {
 369:         np++;
 370:         cp = np;
 371:         while (*np != '/' && *np != '\0')
 372:             np++;
 373:         if (np - cp == 1 && *cp == '.') {
 374:             cp--;
 375:             (void) strcpy(cp, np);
 376:             np = cp;
 377:         }
 378:         if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
 379:             cp--;
 380:             while (cp > &canonname[1] && *--cp != '/')
 381:                 /* find beginning of name */;
 382:             (void) strcpy(cp, np);
 383:             np = cp;
 384:         }
 385:     }
 386: }
 387: 
 388: /*
 389:  * globals (file name generation)
 390:  *
 391:  * "*" in params matches r.e ".*"
 392:  * "?" in params matches r.e. "."
 393:  * "[...]" in params matches character class
 394:  * "[...a-z...]" in params matches a through z.
 395:  */
 396: expandarg(arg, ap)
 397:     char *arg;
 398:     register struct arglist *ap;
 399: {
 400:     static struct afile single;
 401:     int size;
 402: 
 403:     ap->head = ap->last = (struct afile *)0;
 404:     size = expand(arg, 0, ap);
 405:     if (size == 0) {
 406:         single.fnum = lookupname(arg)->e_ino;
 407:         single.fname = savename(arg);
 408:         ap->head = &single;
 409:         ap->last = ap->head + 1;
 410:         return;
 411:     }
 412:     qsort((char *)ap->head, ap->last - ap->head, sizeof *ap->head, fcmp);
 413: }
 414: 
 415: /*
 416:  * Expand a file name
 417:  */
 418: expand(as, rflg, ap)
 419:     char *as;
 420:     int rflg;
 421:     register struct arglist *ap;
 422: {
 423:     int     count, size;
 424:     char        dir = 0;
 425:     char        *rescan = 0;
 426:     DIR     *dirp;
 427:     register char   *s, *cs;
 428:     int     sindex, rindex, lindex;
 429:     struct direct   *dp;
 430:     register char   slash;
 431:     register char   *rs;
 432:     register char   c;
 433: 
 434:     /*
 435: 	 * check for meta chars
 436: 	 */
 437:     s = cs = as;
 438:     slash = 0;
 439:     while (*cs != '*' && *cs != '?' && *cs != '[') {
 440:         if (*cs++ == 0) {
 441:             if (rflg && slash)
 442:                 break;
 443:             else
 444:                 return (0) ;
 445:         } else if (*cs == '/') {
 446:             slash++;
 447:         }
 448:     }
 449:     for (;;) {
 450:         if (cs == s) {
 451:             s = "";
 452:             break;
 453:         } else if (*--cs == '/') {
 454:             *cs = 0;
 455:             if (s == cs)
 456:                 s = "/";
 457:             break;
 458:         }
 459:     }
 460:     if ((dirp = rst_opendir(s)) != NULL)
 461:         dir++;
 462:     count = 0;
 463:     if (*cs == 0)
 464:         *cs++ = 0200;
 465:     if (dir) {
 466:         /*
 467: 		 * check for rescan
 468: 		 */
 469:         rs = cs;
 470:         do {
 471:             if (*rs == '/') {
 472:                 rescan = rs;
 473:                 *rs = 0;
 474:             }
 475:         } while (*rs++);
 476:         sindex = ap->last - ap->head;
 477:         while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) {
 478:             if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
 479:                 continue;
 480:             if ((*dp->d_name == '.' && *cs != '.'))
 481:                 continue;
 482:             if (gmatch(dp->d_name, cs)) {
 483:                 if (addg(dp, s, rescan, ap) < 0)
 484:                     return (-1);
 485:                 count++;
 486:             }
 487:         }
 488:         if (rescan) {
 489:             rindex = sindex;
 490:             lindex = ap->last - ap->head;
 491:             if (count) {
 492:                 count = 0;
 493:                 while (rindex < lindex) {
 494:                     size = expand(ap->head[rindex].fname,
 495:                         1, ap);
 496:                     if (size < 0)
 497:                         return (size);
 498:                     count += size;
 499:                     rindex++;
 500:                 }
 501:             }
 502:             bcopy((char *)&ap->head[lindex],
 503:                  (char *)&ap->head[sindex],
 504:                  (ap->last - &ap->head[rindex]) * sizeof *ap->head);
 505:             ap->last -= lindex - sindex;
 506:             *rescan = '/';
 507:         }
 508:     }
 509:     s = as;
 510:     while (c = *s)
 511:         *s++ = (c&0177 ? c : '/');
 512:     return (count);
 513: }
 514: 
 515: /*
 516:  * Check for a name match
 517:  */
 518: gmatch(s, p)
 519:     register char   *s, *p;
 520: {
 521:     register int    scc;
 522:     char        c;
 523:     char        ok;
 524:     int     lc;
 525: 
 526:     if (scc = *s++)
 527:         if ((scc &= 0177) == 0)
 528:             scc = 0200;
 529:     switch (c = *p++) {
 530: 
 531:     case '[':
 532:         ok = 0;
 533:         lc = 077777;
 534:         while (c = *p++) {
 535:             if (c == ']') {
 536:                 return (ok ? gmatch(s, p) : 0);
 537:             } else if (c == '-') {
 538:                 if (lc <= scc && scc <= (*p++))
 539:                     ok++ ;
 540:             } else {
 541:                 if (scc == (lc = (c&0177)))
 542:                     ok++ ;
 543:             }
 544:         }
 545:         return (0);
 546: 
 547:     default:
 548:         if ((c&0177) != scc)
 549:             return (0) ;
 550:         /* falls through */
 551: 
 552:     case '?':
 553:         return (scc ? gmatch(s, p) : 0);
 554: 
 555:     case '*':
 556:         if (*p == 0)
 557:             return (1) ;
 558:         s--;
 559:         while (*s) {
 560:             if (gmatch(s++, p))
 561:                 return (1);
 562:         }
 563:         return (0);
 564: 
 565:     case 0:
 566:         return (scc == 0);
 567:     }
 568: }
 569: 
 570: /*
 571:  * Construct a matched name.
 572:  */
 573: addg(dp, as1, as3, ap)
 574:     struct direct   *dp;
 575:     char        *as1, *as3;
 576:     struct arglist  *ap;
 577: {
 578:     register char   *s1, *s2;
 579:     register int    c;
 580:     char        buf[BUFSIZ];
 581: 
 582:     s2 = buf;
 583:     s1 = as1;
 584:     while (c = *s1++) {
 585:         if ((c &= 0177) == 0) {
 586:             *s2++ = '/';
 587:             break;
 588:         }
 589:         *s2++ = c;
 590:     }
 591:     s1 = dp->d_name;
 592:     while (*s2 = *s1++)
 593:         s2++;
 594:     if (s1 = as3) {
 595:         *s2++ = '/';
 596:         while (*s2++ = *++s1)
 597:             /* void */;
 598:     }
 599:     if (mkentry(buf, dp->d_ino, ap) == FAIL)
 600:         return (-1);
 601: }
 602: 
 603: /*
 604:  * Do an "ls" style listing of a directory
 605:  */
 606: printlist(name, ino, basename)
 607:     char *name;
 608:     ino_t ino;
 609:     char *basename;
 610: {
 611:     register struct afile *fp;
 612:     register struct direct *dp;
 613:     static struct arglist alist = { 0, 0, 0, 0, "ls" };
 614:     struct afile single;
 615:     DIR *dirp;
 616: 
 617:     if ((dirp = rst_opendir(name)) == NULL) {
 618:         single.fnum = ino;
 619:         single.fname = savename(name + strlen(basename) + 1);
 620:         alist.head = &single;
 621:         alist.last = alist.head + 1;
 622:     } else {
 623:         alist.head = (struct afile *)0;
 624:         fprintf(stderr, "%s:\n", name);
 625:         while (dp = rst_readdir(dirp)) {
 626:             if (dp == NULL || dp->d_ino == 0)
 627:                 break;
 628:             if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
 629:                 continue;
 630:             if (vflag == 0 &&
 631:                 (strcmp(dp->d_name, ".") == 0 ||
 632:                  strcmp(dp->d_name, "..") == 0))
 633:                 continue;
 634:             if (!mkentry(dp->d_name, dp->d_ino, &alist))
 635:                 return;
 636:         }
 637:     }
 638:     if (alist.head != 0) {
 639:         qsort((char *)alist.head, alist.last - alist.head,
 640:             sizeof *alist.head, fcmp);
 641:         formatf(&alist);
 642:         for (fp = alist.head; fp < alist.last; fp++)
 643:             freename(fp->fname);
 644:     }
 645:     if (dirp != NULL)
 646:         fprintf(stderr, "\n");
 647: }
 648: 
 649: /*
 650:  * Read the contents of a directory.
 651:  */
 652: mkentry(name, ino, ap)
 653:     char *name;
 654:     ino_t ino;
 655:     register struct arglist *ap;
 656: {
 657:     register struct afile *fp;
 658: 
 659:     if (ap->base == NULL) {
 660:         ap->nent = 20;
 661:         ap->base = (struct afile *)calloc((unsigned)ap->nent,
 662:             sizeof (struct afile));
 663:         if (ap->base == NULL) {
 664:             fprintf(stderr, "%s: out of memory\n", ap->cmd);
 665:             return (FAIL);
 666:         }
 667:     }
 668:     if (ap->head == 0)
 669:         ap->head = ap->last = ap->base;
 670:     fp = ap->last;
 671:     fp->fnum = ino;
 672:     fp->fname = savename(name);
 673:     fp++;
 674:     if (fp == ap->head + ap->nent) {
 675:         ap->base = (struct afile *)realloc((char *)ap->base,
 676:             (unsigned)(2 * ap->nent * sizeof (struct afile)));
 677:         if (ap->base == 0) {
 678:             fprintf(stderr, "%s: out of memory\n", ap->cmd);
 679:             return (FAIL);
 680:         }
 681:         ap->head = ap->base;
 682:         fp = ap->head + ap->nent;
 683:         ap->nent *= 2;
 684:     }
 685:     ap->last = fp;
 686:     return (GOOD);
 687: }
 688: 
 689: /*
 690:  * Print out a pretty listing of a directory
 691:  */
 692: formatf(ap)
 693:     register struct arglist *ap;
 694: {
 695:     register struct afile *fp;
 696:     struct entry *np;
 697:     int width = 0, w, nentry = ap->last - ap->head;
 698:     int i, j, len, columns, lines;
 699:     char *cp;
 700: 
 701:     if (ap->head == ap->last)
 702:         return;
 703:     for (fp = ap->head; fp < ap->last; fp++) {
 704:         fp->ftype = inodetype(fp->fnum);
 705:         np = lookupino(fp->fnum);
 706:         if (np != NIL)
 707:             fp->fflags = np->e_flags;
 708:         else
 709:             fp->fflags = 0;
 710:         len = strlen(fmtentry(fp));
 711:         if (len > width)
 712:             width = len;
 713:     }
 714:     width += 2;
 715:     columns = 80 / width;
 716:     if (columns == 0)
 717:         columns = 1;
 718:     lines = (nentry + columns - 1) / columns;
 719:     for (i = 0; i < lines; i++) {
 720:         for (j = 0; j < columns; j++) {
 721:             fp = ap->head + j * lines + i;
 722:             cp = fmtentry(fp);
 723:             fprintf(stderr, "%s", cp);
 724:             if (fp + lines >= ap->last) {
 725:                 fprintf(stderr, "\n");
 726:                 break;
 727:             }
 728:             w = strlen(cp);
 729:             while (w < width) {
 730:                 w++;
 731:                 fprintf(stderr, " ");
 732:             }
 733:         }
 734:     }
 735: }
 736: 
 737: /*
 738:  * Comparison routine for qsort.
 739:  */
 740: fcmp(f1, f2)
 741:     register struct afile *f1, *f2;
 742: {
 743: 
 744:     return (strcmp(f1->fname, f2->fname));
 745: }
 746: 
 747: /*
 748:  * Format a directory entry.
 749:  */
 750: char *
 751: fmtentry(fp)
 752:     register struct afile *fp;
 753: {
 754:     static char fmtres[BUFSIZ];
 755:     static int precision = 0;
 756:     int i;
 757:     register char *cp, *dp;
 758: 
 759:     if (!vflag) {
 760:         fmtres[0] = '\0';
 761:     } else {
 762:         if (precision == 0)
 763:             for (i = maxino; i > 0; i /= 10)
 764:                 precision++;
 765:         (void) sprintf(fmtres, "%*d ", precision, fp->fnum);
 766:     }
 767:     dp = &fmtres[strlen(fmtres)];
 768:     if (dflag && BIT(fp->fnum, dumpmap) == 0)
 769:         *dp++ = '^';
 770:     else if ((fp->fflags & NEW) != 0)
 771:         *dp++ = '*';
 772:     else
 773:         *dp++ = ' ';
 774:     for (cp = fp->fname; *cp; cp++)
 775:         if (!vflag && (*cp < ' ' || *cp >= 0177))
 776:             *dp++ = '?';
 777:         else
 778:             *dp++ = *cp;
 779:     if (fp->ftype == NODE)
 780:         *dp++ = '/';
 781:     *dp++ = 0;
 782:     return (fmtres);
 783: }
 784: 
 785: /*
 786:  * respond to interrupts
 787:  */
 788: onintr()
 789: {
 790:     if (command == 'i')
 791:         longjmp(reset, 1);
 792:     if (reply("restore interrupted, continue") == FAIL)
 793:         done(1);
 794: }

Defined functions

addg defined in line 573; used 1 times
canon defined in line 341; used 5 times
copynext defined in line 291; used 3 times
expand defined in line 418; used 2 times
expandarg defined in line 396; used 1 times
fcmp defined in line 740; used 3 times
fmtentry defined in line 750; used 3 times
formatf defined in line 692; used 1 times
getcmd defined in line 209; used 1 times
  • in line 63
gmatch defined in line 518; used 4 times
mkentry defined in line 652; used 2 times
onintr defined in line 788; used 3 times
printlist defined in line 606; used 1 times
runcmdshell defined in line 46; used 1 times

Defined variables

nextarg defined in line 21; used 6 times
reset defined in line 20; used 2 times
sccsid defined in line 8; never used

Defined struct's

afile defined in line 26; used 32 times
arglist defined in line 32; used 16 times

Defined macros

rawname defined in line 216; used 11 times
round defined in line 15; never used
Last modified: 1985-07-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2446
Valid CSS Valid XHTML 1.0 Strict