|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1987 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that the above copyright notice and this paragraph are ! 7: * duplicated in all such forms and that any documentation, ! 8: * advertising materials, and other materials related to such ! 9: * distribution and use acknowledge that the software was developed ! 10: * by the University of California, Berkeley. The name of the ! 11: * University may not be used to endorse or promote products derived ! 12: * from this software without specific prior written permission. ! 13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 16: */ ! 17: ! 18: #ifndef lint ! 19: char copyright[] = ! 20: "@(#) Copyright (c) 1987 Regents of the University of California.\n\ ! 21: All rights reserved.\n"; ! 22: #endif /* not lint */ ! 23: ! 24: #ifndef lint ! 25: static char sccsid[] = "@(#)man.c 5.17 (Berkeley) 6/29/88"; ! 26: #endif /* not lint */ ! 27: ! 28: #include <sys/param.h> ! 29: #include <sys/file.h> ! 30: #include <stdio.h> ! 31: #include <ctype.h> ! 32: ! 33: #define DEF_PAGER "/usr/ucb/more -s" ! 34: #define DEF_PATH "/usr/man:/usr/new/man:/usr/local/man" ! 35: #define LOCAL_PATH "/usr/local/man" ! 36: #define NEW_PATH "/usr/new/man" ! 37: ! 38: #define NO 0 ! 39: #define YES 1 ! 40: ! 41: static char *command, /* command buffer */ ! 42: *defpath, /* default search path */ ! 43: *locpath, /* local search path */ ! 44: *machine, /* machine type */ ! 45: *manpath, /* current search path */ ! 46: *newpath, /* new search path */ ! 47: *pager, /* requested pager */ ! 48: how; /* how to display */ ! 49: ! 50: #define ALL 0x1 /* show all man pages */ ! 51: #define CAT 0x2 /* copy file to stdout */ ! 52: #define WHERE 0x4 /* just tell me where */ ! 53: ! 54: main(argc, argv) ! 55: int argc; ! 56: register char **argv; ! 57: { ! 58: extern char *optarg; ! 59: extern int optind; ! 60: int ch; ! 61: char *getenv(), *malloc(); ! 62: ! 63: while ((ch = getopt(argc, argv, "-M:P:afkw")) != EOF) ! 64: switch((char)ch) { ! 65: case '-': ! 66: how |= CAT; ! 67: break; ! 68: case 'M': ! 69: case 'P': /* backward compatibility */ ! 70: defpath = optarg; ! 71: break; ! 72: case 'a': ! 73: how |= ALL; ! 74: break; ! 75: /* ! 76: * "man -f" and "man -k" are backward contemptible, ! 77: * undocumented ways of calling whatis(1) and apropos(1). ! 78: */ ! 79: case 'f': ! 80: jump(argv, "-f", "whatis"); ! 81: /*NOTREACHED*/ ! 82: case 'k': ! 83: jump(argv, "-k", "apropos"); ! 84: /*NOTREACHED*/ ! 85: /* ! 86: * Deliberately undocumented; really only useful when ! 87: * you're moving man pages around. Not worth adding. ! 88: */ ! 89: case 'w': ! 90: how |= WHERE | ALL; ! 91: break; ! 92: case '?': ! 93: default: ! 94: usage(); ! 95: } ! 96: argv += optind; ! 97: ! 98: if (!*argv) ! 99: usage(); ! 100: ! 101: if (!(how & CAT)) ! 102: if (!isatty(1)) ! 103: how |= CAT; ! 104: else if (pager = getenv("PAGER")) { ! 105: register char *p; ! 106: ! 107: /* ! 108: * if the user uses "more", we make it "more -s" ! 109: * watch out for PAGER = "mypager /usr/ucb/more" ! 110: */ ! 111: for (p = pager; *p && !isspace(*p); ++p); ! 112: for (; p > pager && *p != '/'; --p); ! 113: if (p != pager) ! 114: ++p; ! 115: /* make sure it's "more", not "morex" */ ! 116: if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ ! 117: char *opager = pager; ! 118: /* ! 119: * allocate space to add the "-s" ! 120: */ ! 121: if (!(pager = malloc((u_int)(strlen(opager) ! 122: + sizeof("-s") + 1)))) { ! 123: fputs("man: out of space.\n", stderr); ! 124: exit(1); ! 125: } ! 126: (void)sprintf(pager, "%s %s", opager, "-s"); ! 127: } ! 128: } ! 129: else ! 130: pager = DEF_PAGER; ! 131: if (!(machine = getenv("MACHINE"))) ! 132: machine = MACHINE; ! 133: if (!defpath && !(defpath = getenv("MANPATH"))) ! 134: defpath = DEF_PATH; ! 135: locpath = LOCAL_PATH; ! 136: newpath = NEW_PATH; ! 137: man(argv); ! 138: /* use system(3) in case someone's pager is "pager arg1 arg2" */ ! 139: if (command) ! 140: (void)system(command); ! 141: exit(0); ! 142: } ! 143: ! 144: typedef struct { ! 145: char *name, *msg; ! 146: } DIR; ! 147: static DIR list1[] = { /* section one list */ ! 148: "cat1", "1st", "cat8", "8th", "cat6", "6th", ! 149: "cat.old", "old", NULL, NULL, ! 150: }, list2[] = { /* rest of the list */ ! 151: "cat2", "2nd", "cat3", "3rd", "cat4", "4th", ! 152: "cat5", "5th", "cat7", "7th", "cat3f", "3rd (F)", ! 153: NULL, NULL, ! 154: }, list3[2]; /* single section */ ! 155: ! 156: static ! 157: man(argv) ! 158: char **argv; ! 159: { ! 160: register char *p; ! 161: DIR *section, *getsect(); ! 162: int res; ! 163: ! 164: for (; *argv; ++argv) { ! 165: manpath = defpath; ! 166: section = NULL; ! 167: switch(**argv) { ! 168: case 'l': /* local */ ! 169: /* support the "{l,local,n,new}###" syntax */ ! 170: for (p = *argv; isalpha(*p); ++p); ! 171: if (!strncmp(*argv, "l", p - *argv) || ! 172: !strncmp(*argv, "local", p - *argv)) { ! 173: ++argv; ! 174: manpath = locpath; ! 175: section = getsect(p); ! 176: } ! 177: break; ! 178: case 'n': /* new */ ! 179: for (p = *argv; isalpha(*p); ++p); ! 180: if (!strncmp(*argv, "n", p - *argv) || ! 181: !strncmp(*argv, "new", p - *argv)) { ! 182: ++argv; ! 183: manpath = newpath; ! 184: section = getsect(p); ! 185: } ! 186: break; ! 187: /* ! 188: * old isn't really a separate section of the manual, ! 189: * and its entries are all in a single directory. ! 190: */ ! 191: case 'o': /* old */ ! 192: for (p = *argv; isalpha(*p); ++p); ! 193: if (!strncmp(*argv, "o", p - *argv) || ! 194: !strncmp(*argv, "old", p - *argv)) { ! 195: ++argv; ! 196: list3[0] = list1[3]; ! 197: section = list3; ! 198: } ! 199: break; ! 200: case '1': case '2': case '3': case '4': ! 201: case '5': case '6': case '7': case '8': ! 202: if (section = getsect(*argv)) ! 203: ++argv; ! 204: } ! 205: ! 206: if (*argv) { ! 207: if (section) ! 208: res = manual(section, *argv); ! 209: else { ! 210: res = manual(list1, *argv); ! 211: if (!res || (how & ALL)) ! 212: res += manual(list2, *argv); ! 213: } ! 214: if (res || how&WHERE) ! 215: continue; ! 216: } ! 217: ! 218: fputs("man: ", stderr); ! 219: if (*argv) ! 220: fprintf(stderr, "no entry for %s in the ", *argv); ! 221: else ! 222: fputs("what do you want from the ", stderr); ! 223: if (section) ! 224: fprintf(stderr, "%s section of the ", section->msg); ! 225: if (manpath == locpath) ! 226: fputs("local ", stderr); ! 227: else if (manpath == newpath) ! 228: fputs("new ", stderr); ! 229: if (*argv) ! 230: fputs("manual.\n", stderr); ! 231: else ! 232: fputs("manual?\n", stderr); ! 233: exit(1); ! 234: } ! 235: } ! 236: ! 237: /* ! 238: * manual -- ! 239: * given a directory list and a file name find a file that ! 240: * matches; check ${directory}/${dir}/{file name} and ! 241: * ${directory}/${dir}/${machine}/${file name}. ! 242: */ ! 243: static ! 244: manual(section, name) ! 245: DIR *section; ! 246: char *name; ! 247: { ! 248: register char *beg, *end; ! 249: register DIR *dp; ! 250: register int res; ! 251: char fname[MAXPATHLEN + 1], *index(); ! 252: ! 253: for (beg = manpath, res = 0;; beg = end + 1) { ! 254: if (end = index(beg, ':')) ! 255: *end = '\0'; ! 256: for (dp = section; dp->name; ++dp) { ! 257: (void)sprintf(fname, "%s/%s/%s.0", beg, dp->name, name); ! 258: if (access(fname, R_OK)) { ! 259: (void)sprintf(fname, "%s/%s/%s/%s.0", beg, ! 260: dp->name, machine, name); ! 261: if (access(fname, R_OK)) ! 262: continue; ! 263: } ! 264: if (how & WHERE) ! 265: printf("man: found in %s.\n", fname); ! 266: else if (how & CAT) ! 267: cat(fname); ! 268: else ! 269: add(fname); ! 270: if (!(how & ALL)) ! 271: return(1); ! 272: res = 1; ! 273: } ! 274: if (!end) ! 275: return(res); ! 276: *end = ':'; ! 277: } ! 278: /*NOTREACHED*/ ! 279: } ! 280: ! 281: /* ! 282: * cat -- ! 283: * cat out the file ! 284: */ ! 285: static ! 286: cat(fname) ! 287: char *fname; ! 288: { ! 289: register int fd, n; ! 290: char buf[BUFSIZ]; ! 291: ! 292: if (!(fd = open(fname, O_RDONLY, 0))) { ! 293: perror("man: open"); ! 294: exit(1); ! 295: } ! 296: while ((n = read(fd, buf, sizeof(buf))) > 0) ! 297: if (write(1, buf, n) != n) { ! 298: perror("man: write"); ! 299: exit(1); ! 300: } ! 301: if (n == -1) { ! 302: perror("man: read"); ! 303: exit(1); ! 304: } ! 305: (void)close(fd); ! 306: } ! 307: ! 308: /* ! 309: * add -- ! 310: * add a file name to the list for future paging ! 311: */ ! 312: static ! 313: add(fname) ! 314: char *fname; ! 315: { ! 316: static u_int buflen; ! 317: static int len; ! 318: static char *cp; ! 319: int flen; ! 320: char *malloc(), *realloc(), *strcpy(); ! 321: ! 322: if (!command) { ! 323: if (!(command = malloc(buflen = 1024))) { ! 324: fputs("man: out of space.\n", stderr); ! 325: exit(1); ! 326: } ! 327: len = strlen(strcpy(command, pager)); ! 328: cp = command + len; ! 329: } ! 330: flen = strlen(fname); ! 331: if (len + flen + 2 > buflen) { /* +2 == space, EOS */ ! 332: if (!(command = realloc(command, buflen += 1024))) { ! 333: fputs("man: out of space.\n", stderr); ! 334: exit(1); ! 335: } ! 336: cp = command + len; ! 337: } ! 338: *cp++ = ' '; ! 339: len += flen + 1; /* +1 = space */ ! 340: (void)strcpy(cp, fname); ! 341: cp += flen; ! 342: } ! 343: ! 344: /* ! 345: * getsect -- ! 346: * return a point to the section structure for a particular suffix ! 347: */ ! 348: static DIR * ! 349: getsect(s) ! 350: char *s; ! 351: { ! 352: switch(*s++) { ! 353: case '1': ! 354: if (!*s) ! 355: return(list1); ! 356: break; ! 357: case '2': ! 358: if (!*s) { ! 359: list3[0] = list2[0]; ! 360: return(list3); ! 361: } ! 362: break; ! 363: /* sect. 3 requests are for either section 3, or section 3[fF]. */ ! 364: case '3': ! 365: if (!*s) { ! 366: list3[0] = list2[1]; ! 367: return(list3); ! 368: } ! 369: else if ((*s == 'f' || *s == 'F') && !*++s) { ! 370: list3[0] = list2[5]; ! 371: return(list3); ! 372: } ! 373: break; ! 374: case '4': ! 375: if (!*s) { ! 376: list3[0] = list2[2]; ! 377: return(list3); ! 378: } ! 379: break; ! 380: case '5': ! 381: if (!*s) { ! 382: list3[0] = list2[3]; ! 383: return(list3); ! 384: } ! 385: break; ! 386: case '6': ! 387: if (!*s) { ! 388: list3[0] = list1[2]; ! 389: return(list3); ! 390: } ! 391: break; ! 392: case '7': ! 393: if (!*s) { ! 394: list3[0] = list2[4]; ! 395: return(list3); ! 396: } ! 397: break; ! 398: case '8': ! 399: if (!*s) { ! 400: list3[0] = list1[1]; ! 401: return(list3); ! 402: } ! 403: } ! 404: return((DIR *)NULL); ! 405: } ! 406: ! 407: /* ! 408: * jump -- ! 409: * strip out flag argument and jump ! 410: */ ! 411: static ! 412: jump(argv, flag, name) ! 413: char **argv, *name; ! 414: register char *flag; ! 415: { ! 416: register char **arg; ! 417: ! 418: argv[0] = name; ! 419: for (arg = argv + 1; *arg; ++arg) ! 420: if (!strcmp(*arg, flag)) ! 421: break; ! 422: for (; *arg; ++arg) ! 423: arg[0] = arg[1]; ! 424: execvp(name, argv); ! 425: fprintf(stderr, "%s: Command not found.\n", name); ! 426: exit(1); ! 427: } ! 428: ! 429: /* ! 430: * usage -- ! 431: * print usage and die ! 432: */ ! 433: static ! 434: usage() ! 435: { ! 436: fputs("usage: man [-] [-a] [-M path] [section] title ...\n", stderr); ! 437: exit(1); ! 438: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.