Annotation of 43BSDTahoe/ucb/man/man.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.