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