|
|
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: char copyright[] = ! 9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ ! 10: All rights reserved.\n"; ! 11: #endif not lint ! 12: ! 13: #ifndef lint ! 14: static char sccsid[] = "@(#)man.c 5.12 (Berkeley) 3/20/86"; ! 15: #endif not lint ! 16: ! 17: #include <stdio.h> ! 18: #include <ctype.h> ! 19: #include <sgtty.h> ! 20: #include <sys/param.h> ! 21: #include <sys/stat.h> ! 22: #include <signal.h> ! 23: #include <strings.h> ! 24: ! 25: /* ! 26: * man ! 27: * link also to apropos and whatis ! 28: * This version uses more for underlining and paging. ! 29: */ ! 30: #define NROFFCAT "nroff -h -man" /* for nroffing to cat file */ ! 31: #define NROFF "nroff -man" /* for nroffing to tty */ ! 32: #define MORE "more -s" /* paging filter */ ! 33: #define CAT_ "/bin/cat" /* for when output is not a tty */ ! 34: #define CAT_S "/bin/cat -s" /* for '-' opt (no more) */ ! 35: ! 36: #define TROFFCMD "vtroff -man %s" ! 37: ! 38: #define ALLSECT "1nl6823457po" /* order to look through sections */ ! 39: #define SECT1 "1nlo" /* sections to look at if 1 is specified */ ! 40: #define SUBSEC1 "cg" /* subsections to try in section 1 */ ! 41: #define SUBSEC3 "sxmncf" ! 42: #define SUBSEC4 "pfn" ! 43: #define SUBSEC8 "cv" ! 44: ! 45: #define WHATIS "whatis" ! 46: ! 47: int nomore; ! 48: char *CAT = CAT_; ! 49: char *manpath = "/usr/man"; ! 50: char *strcpy(); ! 51: char *strcat(); ! 52: char *getenv(); ! 53: char *calloc(); ! 54: char *trim(); ! 55: int remove(); ! 56: int apropos(); ! 57: int whatis(); ! 58: int section; ! 59: int subsec; ! 60: int troffit; ! 61: int mypid; ! 62: ! 63: #define eq(a,b) (strcmp(a,b) == 0) ! 64: ! 65: main(argc, argv) ! 66: int argc; ! 67: char *argv[]; ! 68: { ! 69: char *mp; ! 70: ! 71: if ((mp = getenv("MANPATH")) != NULL) ! 72: manpath = mp; ! 73: umask(0); ! 74: mypid = getpid(); ! 75: if (strcmp(argv[0], "apropos") == 0) { ! 76: runpath(argc-1, argv+1, apropos); ! 77: exit(0); ! 78: } ! 79: if (strcmp(argv[0], "whatis") == 0) { ! 80: runpath(argc-1, argv+1, whatis); ! 81: exit(0); ! 82: } ! 83: if (argc <= 1) { ! 84: fprintf(stderr, "Usage: man [ section ] name ...\n"); ! 85: exit(1); ! 86: } ! 87: argc--, argv++; ! 88: while (argc > 0 && argv[0][0] == '-') { ! 89: switch(argv[0][1]) { ! 90: ! 91: case 0: ! 92: nomore++; ! 93: CAT = CAT_S; ! 94: break; ! 95: ! 96: case 't': ! 97: troffit++; ! 98: break; ! 99: ! 100: case 'k': ! 101: apropos(argc-1, argv+1); ! 102: exit(0); ! 103: ! 104: case 'f': ! 105: whatis(argc-1, argv+1); ! 106: exit(0); ! 107: ! 108: case 'P': /* backwards compatibility */ ! 109: case 'M': ! 110: if (argc < 2) { ! 111: fprintf(stderr, "%s: missing path\n", *argv); ! 112: exit(1); ! 113: } ! 114: argc--, argv++; ! 115: manpath = *argv; ! 116: break; ! 117: } ! 118: argc--, argv++; ! 119: } ! 120: if (troffit == 0 && nomore == 0 && !isatty(1)) ! 121: nomore++; ! 122: section = 0; ! 123: do { ! 124: if (eq(argv[0], "local")) { ! 125: section = 'l'; ! 126: goto sectin; ! 127: } else if (eq(argv[0], "new")) { ! 128: section = 'n'; ! 129: goto sectin; ! 130: } else if (eq(argv[0], "old")) { ! 131: section = 'o'; ! 132: goto sectin; ! 133: } else if (eq(argv[0], "public")) { ! 134: section = 'p'; ! 135: goto sectin; ! 136: } else if (isdigit(argv[0][0]) && ! 137: (argv[0][1] == 0 || argv[0][2] == 0)) { ! 138: section = argv[0][0]; ! 139: subsec = argv[0][1]; ! 140: sectin: ! 141: argc--, argv++; ! 142: if (argc == 0) { ! 143: fprintf(stderr, ! 144: "But what do you want from section %s?\n", ! 145: argv[-1]); ! 146: exit(1); ! 147: } ! 148: continue; ! 149: } ! 150: manual(section, argv[0]); ! 151: argc--, argv++; ! 152: } while (argc > 0); ! 153: exit(0); ! 154: } ! 155: ! 156: runpath(ac, av, f) ! 157: int ac; ! 158: char *av[]; ! 159: int (*f)(); ! 160: { ! 161: ! 162: if (ac > 0 && strcmp(av[0], "-M") == 0 || strcmp(av[0], "-P") == 0) { ! 163: if (ac < 2) { ! 164: fprintf(stderr, "%s: missing path\n", av[0]); ! 165: exit(1); ! 166: } ! 167: manpath = av[1]; ! 168: ac -= 2, av += 2; ! 169: } ! 170: (*f)(ac, av); ! 171: exit(0); ! 172: } ! 173: ! 174: manual(sec, name) ! 175: char sec, *name; ! 176: { ! 177: char section = sec; ! 178: char work[100], work2[100]; ! 179: char path[MAXPATHLEN+1], realname[MAXPATHLEN+1]; ! 180: char cmdbuf[150]; ! 181: int ss = 0; ! 182: struct stat stbuf, stbuf2; ! 183: int last; ! 184: char *sp = ALLSECT; ! 185: FILE *it; ! 186: char abuf[BUFSIZ]; ! 187: ! 188: strcpy(work, "manx/"); ! 189: strcat(work, name); ! 190: strcat(work, ".x"); ! 191: last = strlen(work) - 1; ! 192: if (section == '1') { ! 193: sp = SECT1; ! 194: section = 0; ! 195: } ! 196: if (section == 0) { /* no section or section 1 given */ ! 197: for (section = *sp++; section; section = *sp++) { ! 198: work[3] = section; ! 199: work[last] = section; ! 200: work[last+1] = 0; ! 201: work[last+2] = 0; ! 202: if (pathstat(work, path, &stbuf)) ! 203: break; ! 204: if (work[last] >= '1' && work[last] <= '8') { ! 205: char *cp; ! 206: search: ! 207: switch (work[last]) { ! 208: case '1': cp = SUBSEC1; break; ! 209: case '3': cp = SUBSEC3; break; ! 210: case '4': cp = SUBSEC4; break; ! 211: case '8': cp = SUBSEC8; break; ! 212: default: cp = ""; break; ! 213: } ! 214: while (*cp) { ! 215: work[last+1] = *cp++; ! 216: if (pathstat(work, path, &stbuf)) { ! 217: ss = work[last+1]; ! 218: goto found; ! 219: } ! 220: } ! 221: if (ss == 0) ! 222: work[last+1] = 0; ! 223: } ! 224: } ! 225: if (section == 0) { ! 226: if (sec == 0) ! 227: printf("No manual entry for %s.\n", name); ! 228: else ! 229: printf("No entry for %s in section %c%s.\n", ! 230: name, sec, " of the manual"); ! 231: return; ! 232: } ! 233: } else { /* section given */ ! 234: work[3] = section; ! 235: work[last] = section; ! 236: work[last+1] = subsec; ! 237: work[last+2] = 0; ! 238: if (!pathstat(work, path, &stbuf)) { ! 239: if ((section >= '1' && section <= '8') && subsec == 0) { ! 240: sp = "\0"; ! 241: goto search; ! 242: } ! 243: else if (section == 'o') { /* XXX */ ! 244: char *cp; ! 245: char sec; ! 246: for (sec = '0'; sec <= '8'; sec++) { ! 247: work[last] = sec; ! 248: if (pathstat(work, path, &stbuf)) ! 249: goto found; ! 250: switch (work[last]) { ! 251: case '1': cp = SUBSEC1; break; ! 252: case '3': cp = SUBSEC3; break; ! 253: case '4': cp = SUBSEC4; break; ! 254: case '8': cp = SUBSEC8; break; ! 255: default: cp = ""; break; ! 256: } ! 257: while (*cp) { ! 258: work[last+1] = *cp++; ! 259: if (pathstat(work, path, &stbuf)) { ! 260: ss = work[last+1]; ! 261: goto found; ! 262: } ! 263: } ! 264: if (ss == 0) ! 265: work[last+1] = 0; ! 266: } ! 267: } ! 268: printf("No entry for %s in section %c", name, section); ! 269: if (subsec) ! 270: putchar(subsec); ! 271: printf(" of the manual.\n"); ! 272: return; ! 273: } ! 274: } ! 275: found: ! 276: sprintf(realname, "%s/%s", path, work); ! 277: if (troffit) { ! 278: troff(path, work); ! 279: return; ! 280: } ! 281: if (!nomore) { ! 282: if ((it = fopen(realname, "r")) == NULL) { ! 283: goto catit; ! 284: } ! 285: if (fgets(abuf, BUFSIZ-1, it) && ! 286: strncmp(abuf, ".so ", 4) == 0) { ! 287: register char *cp = abuf+4; ! 288: char *dp; ! 289: ! 290: while (*cp && *cp != '\n') ! 291: cp++; ! 292: *cp = 0; ! 293: while (cp > abuf && *--cp != '/') ! 294: ; ! 295: dp = ".so man"; ! 296: if (cp != abuf+strlen(dp)+1) { ! 297: tohard: ! 298: fclose(it); ! 299: nomore = 1; ! 300: strcpy(work, abuf+4); ! 301: goto hardway; ! 302: } ! 303: for (cp = abuf; *cp == *dp && *cp; cp++, dp++) ! 304: ; ! 305: if (*dp) ! 306: goto tohard; ! 307: strcpy(work, cp-3); ! 308: } ! 309: fclose(it); ! 310: } ! 311: catit: ! 312: strcpy(work2, "cat"); ! 313: work2[3] = work[3]; ! 314: work2[4] = 0; ! 315: sprintf(realname, "%s/%s", path, work2); ! 316: if (stat(realname, &stbuf2) < 0) ! 317: goto hardway; ! 318: strcpy(work2+4, work+4); ! 319: sprintf(realname, "%s/%s", path, work2); ! 320: if (stat(realname, &stbuf2) < 0 || stbuf2.st_mtime < stbuf.st_mtime) { ! 321: if (nomore) ! 322: goto hardway; ! 323: printf("Reformatting page. Wait..."); ! 324: fflush(stdout); ! 325: unlink(work2); ! 326: if (signal(SIGINT, SIG_IGN) == SIG_DFL) { ! 327: (void) signal(SIGINT, remove); ! 328: (void) signal(SIGQUIT, remove); ! 329: (void) signal(SIGTERM, remove); ! 330: } ! 331: sprintf(cmdbuf, "%s %s/%s > /tmp/man%d; trap '' 1 15", ! 332: NROFFCAT, path, work, mypid); ! 333: if (system(cmdbuf)) { ! 334: printf(" aborted (sorry)\n"); ! 335: remove(); ! 336: /*NOTREACHED*/ ! 337: } ! 338: sprintf(cmdbuf, "/bin/mv -f /tmp/man%d %s/%s 2>/dev/null", ! 339: mypid, path, work2); ! 340: if (system(cmdbuf)) { ! 341: sprintf(path, "/"); ! 342: sprintf(work2, "tmp/man%d", mypid); ! 343: } ! 344: printf(" done\n"); ! 345: } ! 346: strcpy(work, work2); ! 347: hardway: ! 348: nroff(path, work); ! 349: if (work2[0] == 't') ! 350: remove(); ! 351: } ! 352: ! 353: /* ! 354: * Use the manpath to look for ! 355: * the file name. The result of ! 356: * stat is returned in stbuf, the ! 357: * successful path in path. ! 358: */ ! 359: pathstat(name, path, stbuf) ! 360: char *name, path[]; ! 361: struct stat *stbuf; ! 362: { ! 363: char *cp, *tp, *ep; ! 364: char **cpp; ! 365: static char *manpaths[] = {"man", "cat", 0}; ! 366: static char *nopaths[] = {"", 0}; ! 367: ! 368: if (strncmp(name, "man", 3) == 0) ! 369: cpp = manpaths; ! 370: else ! 371: cpp = nopaths; ! 372: for ( ; *cpp ; cpp++) { ! 373: for (cp = manpath; cp && *cp; cp = tp) { ! 374: tp = index(cp, ':'); ! 375: if (tp) { ! 376: if (tp == cp) { ! 377: sprintf(path, "%s%s", *cpp, ! 378: name+strlen(*cpp)); ! 379: } ! 380: else { ! 381: sprintf(path, "%.*s/%s%s", tp-cp, cp, ! 382: *cpp, name+strlen(*cpp)); ! 383: } ! 384: ep = path + (tp-cp); ! 385: tp++; ! 386: } else { ! 387: sprintf(path, "%s/%s%s", cp, *cpp, ! 388: name+strlen(*cpp)); ! 389: ep = path + strlen(cp); ! 390: } ! 391: if (stat(path, stbuf) >= 0) { ! 392: *ep = '\0'; ! 393: return (1); ! 394: } ! 395: } ! 396: } ! 397: return (0); ! 398: } ! 399: ! 400: nroff(pp, wp) ! 401: char *pp, *wp; ! 402: { ! 403: char cmd[BUFSIZ]; ! 404: ! 405: chdir(pp); ! 406: if (wp[0] == 'c' || wp[0] == 't') ! 407: sprintf(cmd, "%s %s", nomore? CAT : MORE, wp); ! 408: else ! 409: sprintf(cmd, nomore? "%s %s" : "%s %s|%s", NROFF, wp, MORE); ! 410: (void) system(cmd); ! 411: } ! 412: ! 413: troff(pp, wp) ! 414: char *pp, *wp; ! 415: { ! 416: char cmdbuf[BUFSIZ]; ! 417: ! 418: chdir(pp); ! 419: sprintf(cmdbuf, TROFFCMD, wp); ! 420: (void) system(cmdbuf); ! 421: } ! 422: ! 423: any(c, sp) ! 424: register int c; ! 425: register char *sp; ! 426: { ! 427: register int d; ! 428: ! 429: while (d = *sp++) ! 430: if (c == d) ! 431: return (1); ! 432: return (0); ! 433: } ! 434: ! 435: remove() ! 436: { ! 437: char name[15]; ! 438: ! 439: sprintf(name, "/tmp/man%d", mypid); ! 440: unlink(name); ! 441: exit(1); ! 442: } ! 443: ! 444: unsigned int ! 445: blklen(ip) ! 446: register char **ip; ! 447: { ! 448: register unsigned int i = 0; ! 449: ! 450: while (*ip++) ! 451: i++; ! 452: return (i); ! 453: } ! 454: ! 455: apropos(argc, argv) ! 456: int argc; ! 457: char **argv; ! 458: { ! 459: char buf[BUFSIZ], file[MAXPATHLEN+1]; ! 460: char *gotit, *cp, *tp; ! 461: register char **vp; ! 462: ! 463: if (argc == 0) { ! 464: fprintf(stderr, "apropos what?\n"); ! 465: exit(1); ! 466: } ! 467: gotit = calloc(1, blklen(argv)); ! 468: for (cp = manpath; cp; cp = tp) { ! 469: tp = index(cp, ':'); ! 470: if (tp) { ! 471: if (tp == cp) ! 472: strcpy(file, WHATIS); ! 473: else ! 474: sprintf(file, "%.*s/%s", tp-cp, cp, WHATIS); ! 475: tp++; ! 476: } else ! 477: sprintf(file, "%s/%s", cp, WHATIS); ! 478: if (freopen(file, "r", stdin) == NULL) ! 479: continue; ! 480: while (fgets(buf, sizeof buf, stdin) != NULL) ! 481: for (vp = argv; *vp; vp++) ! 482: if (match(buf, *vp)) { ! 483: printf("%s", buf); ! 484: gotit[vp - argv] = 1; ! 485: for (vp++; *vp; vp++) ! 486: if (match(buf, *vp)) ! 487: gotit[vp - argv] = 1; ! 488: break; ! 489: } ! 490: } ! 491: for (vp = argv; *vp; vp++) ! 492: if (gotit[vp - argv] == 0) ! 493: printf("%s: nothing appropriate\n", *vp); ! 494: } ! 495: ! 496: match(bp, str) ! 497: register char *bp; ! 498: char *str; ! 499: { ! 500: ! 501: for (;;) { ! 502: if (*bp == 0) ! 503: return (0); ! 504: if (amatch(bp, str)) ! 505: return (1); ! 506: bp++; ! 507: } ! 508: } ! 509: ! 510: amatch(cp, dp) ! 511: register char *cp, *dp; ! 512: { ! 513: ! 514: while (*cp && *dp && lmatch(*cp, *dp)) ! 515: cp++, dp++; ! 516: if (*dp == 0) ! 517: return (1); ! 518: return (0); ! 519: } ! 520: ! 521: lmatch(c, d) ! 522: register int c, d; ! 523: { ! 524: ! 525: if (c == d) ! 526: return (1); ! 527: if (!isalpha(c) || !isalpha(d)) ! 528: return (0); ! 529: if (islower(c)) ! 530: c = toupper(c); ! 531: if (islower(d)) ! 532: d = toupper(d); ! 533: return (c == d); ! 534: } ! 535: ! 536: whatis(argc, argv) ! 537: int argc; ! 538: char **argv; ! 539: { ! 540: register char *gotit, **vp; ! 541: char buf[BUFSIZ], file[MAXPATHLEN+1], *cp, *tp; ! 542: ! 543: if (argc == 0) { ! 544: fprintf(stderr, "whatis what?\n"); ! 545: exit(1); ! 546: } ! 547: for (vp = argv; *vp; vp++) ! 548: *vp = trim(*vp); ! 549: gotit = calloc(1, blklen(argv)); ! 550: for (cp = manpath; cp; cp = tp) { ! 551: tp = index(cp, ':'); ! 552: if (tp) { ! 553: if (tp == cp) ! 554: strcpy(file, WHATIS); ! 555: else ! 556: sprintf(file, "%.*s/%s", tp-cp, cp, WHATIS); ! 557: tp++; ! 558: } else ! 559: sprintf(file, "%s/%s", cp, WHATIS); ! 560: if (freopen(file, "r", stdin) == NULL) ! 561: continue; ! 562: while (fgets(buf, sizeof buf, stdin) != NULL) ! 563: for (vp = argv; *vp; vp++) ! 564: if (wmatch(buf, *vp)) { ! 565: printf("%s", buf); ! 566: gotit[vp - argv] = 1; ! 567: for (vp++; *vp; vp++) ! 568: if (wmatch(buf, *vp)) ! 569: gotit[vp - argv] = 1; ! 570: break; ! 571: } ! 572: } ! 573: for (vp = argv; *vp; vp++) ! 574: if (gotit[vp - argv] == 0) ! 575: printf("%s: not found\n", *vp); ! 576: } ! 577: ! 578: wmatch(buf, str) ! 579: char *buf, *str; ! 580: { ! 581: register char *bp, *cp; ! 582: ! 583: bp = buf; ! 584: again: ! 585: cp = str; ! 586: while (*bp && *cp && lmatch(*bp, *cp)) ! 587: bp++, cp++; ! 588: if (*cp == 0 && (*bp == '(' || *bp == ',' || *bp == '\t' || *bp == ' ')) ! 589: return (1); ! 590: while (isalpha(*bp) || isdigit(*bp)) ! 591: bp++; ! 592: if (*bp != ',') ! 593: return (0); ! 594: bp++; ! 595: while (isspace(*bp)) ! 596: bp++; ! 597: goto again; ! 598: } ! 599: ! 600: char * ! 601: trim(cp) ! 602: register char *cp; ! 603: { ! 604: register char *dp; ! 605: ! 606: for (dp = cp; *dp; dp++) ! 607: if (*dp == '/') ! 608: cp = dp + 1; ! 609: if (cp[0] != '.') { ! 610: if (cp + 3 <= dp && dp[-2] == '.' && ! 611: any(dp[-1], "cosa12345678npP")) ! 612: dp[-2] = 0; ! 613: if (cp + 4 <= dp && dp[-3] == '.' && ! 614: any(dp[-2], "13") && isalpha(dp[-1])) ! 615: dp[-3] = 0; ! 616: } ! 617: return (cp); ! 618: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.