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: }

Defined functions

amatch defined in line 510; used 1 times
any defined in line 423; used 2 times
apropos defined in line 455; used 3 times
blklen defined in line 444; used 2 times
lmatch defined in line 521; used 2 times
main defined in line 65; never used
manual defined in line 174; used 1 times
match defined in line 496; used 2 times
nroff defined in line 400; used 1 times
pathstat defined in line 359; used 5 times
remove defined in line 435; used 6 times
runpath defined in line 156; used 2 times
trim defined in line 600; used 2 times
troff defined in line 413; used 1 times
whatis defined in line 536; used 3 times
wmatch defined in line 578; used 2 times

Defined variables

CAT defined in line 48; used 2 times
copyright defined in line 8; never used
manpath defined in line 49; used 6 times
mypid defined in line 61; used 5 times
nomore defined in line 47; used 8 times
sccsid defined in line 14; never used
section defined in line 58; used 23 times
subsec defined in line 59; used 5 times
troffit defined in line 60; used 3 times

Defined macros

ALLSECT defined in line 38; used 1 times
CAT_ defined in line 33; used 1 times
  • in line 48
CAT_S defined in line 34; used 1 times
  • in line 93
MORE defined in line 32; used 2 times
NROFF defined in line 31; used 1 times
NROFFCAT defined in line 30; used 1 times
SECT1 defined in line 39; used 1 times
SUBSEC1 defined in line 40; used 2 times
SUBSEC3 defined in line 41; used 2 times
SUBSEC4 defined in line 42; used 2 times
SUBSEC8 defined in line 43; used 2 times
TROFFCMD defined in line 36; used 1 times
WHATIS defined in line 45; used 6 times
eq defined in line 63; used 4 times
Last modified: 1986-03-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2720
Valid CSS Valid XHTML 1.0 Strict