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

Defined functions

add defined in line 317; used 1 times
cat defined in line 290; used 1 times
getsect defined in line 353; used 4 times
jump defined in line 416; used 2 times
main defined in line 57; never used
man defined in line 159; used 1 times
manual defined in line 246; used 3 times
setmachine defined in line 438; used 1 times
usage defined in line 451; used 2 times

Defined variables

command defined in line 44; used 9 times
copyright defined in line 19; never used
defpath defined in line 45; used 5 times
how defined in line 51; used 10 times
locpath defined in line 46; used 3 times
machine defined in line 47; used 5 times
manpath defined in line 48; used 6 times
newpath defined in line 49; used 3 times
pager defined in line 50; used 9 times
sccsid defined in line 25; never used

Defined macros

ALL defined in line 53; used 4 times
CAT defined in line 54; used 4 times
DEF_PAGER defined in line 36; used 1 times
DEF_PATH defined in line 37; used 1 times
LOCAL_PATH defined in line 38; used 1 times
NEW_PATH defined in line 39; used 1 times
NO defined in line 41; never used
WHERE defined in line 55; used 3 times
YES defined in line 42; never used
Last modified: 1999-11-26
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4250
Valid CSS Valid XHTML 1.0 Strict