# 2.11BSD#431 - /usr/src/ucb/man/man.c

##### Functions

    main              X
    setmachine        X

##### Variables

    copyright         X

##### Macros

    ALL               X
    CAT               X
    DEF_PAGER         X
    DEF_PATH          X
    LOCAL_PATH        X
    NEW_PATH          X
    NO                X
    WHERE             X
    YES               X

       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

- in line 274

cat defined in line 290; used 1 times

- in line 272

getsect defined in line 353; used 4 times

- in line 164, 178, 187, 205

jump defined in line 416; used 2 times

- in line 83-86(2)

main defined in line 57; never used
man defined in line 159; used 1 times

- in line 140

manual defined in line 246; used 3 times

- in line 211-215(3)

setmachine defined in line 438; used 1 times

- in line 135

usage defined in line 451; used 2 times

- in line 97-102(2)

#### Defined variables

command defined in line 44; used 9 times

- in line 142-143(2), 327-341(7)

copyright defined in line 19; never used
defpath defined in line 45; used 5 times

- in line 73, 136-137(3), 168

how defined in line 51; used 10 times

- in line 69, 76, 93, 104-106(2), 214-217(2), 269-275(3)

locpath defined in line 46; used 3 times

- in line 138, 177, 228

machine defined in line 47; used 5 times

- in line 134, 265, 443-444(3)

manpath defined in line 48; used 6 times

- in line 168, 177, 186, 228-230(2), 258

newpath defined in line 49; used 3 times

- in line 139, 186, 230

pager defined in line 50; used 9 times

- in line 107, 114-133(7), 332

sccsid defined in line 25; never used

#### Defined macros

ALL defined in line 53; used 4 times

- in line 76, 93, 214, 275

CAT defined in line 54; used 4 times

- in line 69, 104-106(2), 271

DEF_PAGER defined in line 36; used 1 times

- in line 133

DEF_PATH defined in line 37; used 1 times

- in line 137

LOCAL_PATH defined in line 38; used 1 times

- in line 138

NEW_PATH defined in line 39; used 1 times

- in line 139

NO defined in line 41; never used
WHERE defined in line 55; used 3 times

- in line 93, 217, 269

YES defined in line 42; never used

Last modified: 1999-11-26 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2009 |