[BACK]Return to man.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / man

Annotation of src/usr.bin/man/man.c, Revision 1.1

1.1     ! deraadt     1: /*     $NetBSD: man.c,v 1.7 1995/09/28 06:05:34 tls Exp $      */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1987, 1993, 1994, 1995
        !             5:  *     The Regents of the University of California.  All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. All advertising materials mentioning features or use of this software
        !            16:  *    must display the following acknowledgement:
        !            17:  *     This product includes software developed by the University of
        !            18:  *     California, Berkeley and its contributors.
        !            19:  * 4. Neither the name of the University nor the names of its contributors
        !            20:  *    may be used to endorse or promote products derived from this software
        !            21:  *    without specific prior written permission.
        !            22:  *
        !            23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            33:  * SUCH DAMAGE.
        !            34:  */
        !            35:
        !            36: #ifndef lint
        !            37: static char copyright[] =
        !            38: "@(#) Copyright (c) 1987, 1993, 1994, 1995\n\
        !            39:        The Regents of the University of California.  All rights reserved.\n";
        !            40: #endif /* not lint */
        !            41:
        !            42: #ifndef lint
        !            43: #if 0
        !            44: static char sccsid[] = "@(#)man.c      8.17 (Berkeley) 1/31/95";
        !            45: #else
        !            46: static char rcsid[] = "$NetBSD: man.c,v 1.7 1995/09/28 06:05:34 tls Exp $";
        !            47: #endif
        !            48: #endif /* not lint */
        !            49:
        !            50: #include <sys/param.h>
        !            51: #include <sys/queue.h>
        !            52:
        !            53: #include <ctype.h>
        !            54: #include <err.h>
        !            55: #include <errno.h>
        !            56: #include <fcntl.h>
        !            57: #include <fnmatch.h>
        !            58: #include <glob.h>
        !            59: #include <signal.h>
        !            60: #include <stdio.h>
        !            61: #include <stdlib.h>
        !            62: #include <string.h>
        !            63: #include <unistd.h>
        !            64:
        !            65: #include "config.h"
        !            66: #include "pathnames.h"
        !            67:
        !            68: int f_all, f_where;
        !            69:
        !            70: static void     build_page __P((char *, char **));
        !            71: static void     cat __P((char *));
        !            72: static char    *check_pager __P((char *));
        !            73: static int      cleanup __P((void));
        !            74: static void     how __P((char *));
        !            75: static void     jump __P((char **, char *, char *));
        !            76: static int      manual __P((char *, TAG *, glob_t *));
        !            77: static void     onsig __P((int));
        !            78: static void     usage __P((void));
        !            79:
        !            80: int
        !            81: main(argc, argv)
        !            82:        int argc;
        !            83:        char *argv[];
        !            84: {
        !            85:        extern char *optarg;
        !            86:        extern int optind;
        !            87:        TAG *defp, *defnewp, *section, *sectnewp, *subp;
        !            88:        ENTRY *e_defp, *e_sectp, *e_subp, *ep;
        !            89:        glob_t pg;
        !            90:        size_t len;
        !            91:        int ch, f_cat, f_how, found;
        !            92:        char **ap, *cmd, *machine, *p, *p_add, *p_path, *pager, *slashp;
        !            93:        char *conffile, buf[MAXPATHLEN * 2];
        !            94:
        !            95:        f_cat = f_how = 0;
        !            96:        conffile = p_add = p_path = NULL;
        !            97:        while ((ch = getopt(argc, argv, "-aC:cfhkM:m:P:w")) != EOF)
        !            98:                switch (ch) {
        !            99:                case 'a':
        !           100:                        f_all = 1;
        !           101:                        break;
        !           102:                case 'C':
        !           103:                        conffile = optarg;
        !           104:                        break;
        !           105:                case 'c':
        !           106:                case '-':               /* Deprecated. */
        !           107:                        f_cat = 1;
        !           108:                        break;
        !           109:                case 'h':
        !           110:                        f_how = 1;
        !           111:                        break;
        !           112:                case 'm':
        !           113:                        p_add = optarg;
        !           114:                        break;
        !           115:                case 'M':
        !           116:                case 'P':               /* Backward compatibility. */
        !           117:                        p_path = optarg;
        !           118:                        break;
        !           119:                /*
        !           120:                 * The -f and -k options are backward compatible,
        !           121:                 * undocumented ways of calling whatis(1) and apropos(1).
        !           122:                 */
        !           123:                case 'f':
        !           124:                        jump(argv, "-f", "whatis");
        !           125:                        /* NOTREACHED */
        !           126:                case 'k':
        !           127:                        jump(argv, "-k", "apropos");
        !           128:                        /* NOTREACHED */
        !           129:                case 'w':
        !           130:                        f_all = f_where = 1;
        !           131:                        break;
        !           132:                case '?':
        !           133:                default:
        !           134:                        usage();
        !           135:                }
        !           136:        argc -= optind;
        !           137:        argv += optind;
        !           138:
        !           139:        if (!*argv)
        !           140:                usage();
        !           141:
        !           142:        if (!f_cat && !f_how && !f_where)
        !           143:                if (!isatty(1))
        !           144:                        f_cat = 1;
        !           145:                else if ((pager = getenv("PAGER")) != NULL)
        !           146:                        pager = check_pager(pager);
        !           147:                else
        !           148:                        pager = _PATH_PAGER;
        !           149:
        !           150:        /* Read the configuration file. */
        !           151:        config(conffile);
        !           152:
        !           153:        /* Get the machine type. */
        !           154:        if ((machine = getenv("MACHINE")) == NULL)
        !           155:                machine = MACHINE;
        !           156:
        !           157:        /* If there's no _default list, create an empty one. */
        !           158:        if ((defp = getlist("_default")) == NULL)
        !           159:                defp = addlist("_default");
        !           160:
        !           161:        /*
        !           162:         * 1: If the user specified a MANPATH variable, or set the -M
        !           163:         *    option, we replace the _default list with the user's list,
        !           164:         *    appending the entries in the _subdir list and the machine.
        !           165:         */
        !           166:        if (p_path == NULL)
        !           167:                p_path = getenv("MANPATH");
        !           168:        if (p_path != NULL) {
        !           169:                while ((e_defp = defp->list.tqh_first) != NULL) {
        !           170:                        free(e_defp->s);
        !           171:                        TAILQ_REMOVE(&defp->list, e_defp, q);
        !           172:                }
        !           173:                for (p = strtok(p_path, ":");
        !           174:                    p != NULL; p = strtok(NULL, ":")) {
        !           175:                        slashp = p[strlen(p) - 1] == '/' ? "" : "/";
        !           176:                        e_subp = (subp = getlist("_subdir")) == NULL ?
        !           177:                            NULL : subp->list.tqh_first;
        !           178:                        for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
        !           179:                                (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
        !           180:                                    p, slashp, e_subp->s, machine);
        !           181:                                if ((ep = malloc(sizeof(ENTRY))) == NULL ||
        !           182:                                    (ep->s = strdup(buf)) == NULL)
        !           183:                                        err(1, NULL);
        !           184:                                TAILQ_INSERT_TAIL(&defp->list, ep, q);
        !           185:                        }
        !           186:                }
        !           187:        }
        !           188:
        !           189:        /*
        !           190:         * 2: If the user did not specify MANPATH, -M or a section, rewrite
        !           191:         *    the _default list to include the _subdir list and the machine.
        !           192:         */
        !           193:        if (argv[1] == NULL)
        !           194:                section = NULL;
        !           195:        else if ((section = getlist(*argv)) != NULL)
        !           196:                ++argv;
        !           197:        if (p_path == NULL && section == NULL) {
        !           198:                defnewp = addlist("_default_new");
        !           199:                e_defp =
        !           200:                    defp->list.tqh_first == NULL ? NULL : defp->list.tqh_first;
        !           201:                for (; e_defp != NULL; e_defp = e_defp->q.tqe_next) {
        !           202:                        slashp =
        !           203:                            e_defp->s[strlen(e_defp->s) - 1] == '/' ? "" : "/";
        !           204:                        e_subp = (subp = getlist("_subdir")) == NULL ?
        !           205:                            NULL : subp->list.tqh_first;
        !           206:                        for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
        !           207:                                (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
        !           208:                                e_defp->s, slashp, e_subp->s, machine);
        !           209:                                if ((ep = malloc(sizeof(ENTRY))) == NULL ||
        !           210:                                    (ep->s = strdup(buf)) == NULL)
        !           211:                                        err(1, NULL);
        !           212:                                TAILQ_INSERT_TAIL(&defnewp->list, ep, q);
        !           213:                        }
        !           214:                }
        !           215:                defp = getlist("_default");
        !           216:                while ((e_defp = defp->list.tqh_first) != NULL) {
        !           217:                        free(e_defp->s);
        !           218:                        TAILQ_REMOVE(&defp->list, e_defp, q);
        !           219:                }
        !           220:                free(defp->s);
        !           221:                TAILQ_REMOVE(&head, defp, q);
        !           222:                defnewp = getlist("_default_new");
        !           223:                free(defnewp->s);
        !           224:                defnewp->s = "_default";
        !           225:                defp = defnewp;
        !           226:        }
        !           227:
        !           228:        /*
        !           229:         * 3: If the user set the -m option, insert the user's list before
        !           230:         *    whatever list we have, again appending the _subdir list and
        !           231:         *    the machine.
        !           232:         */
        !           233:        if (p_add != NULL)
        !           234:                for (p = strtok(p_add, ":"); p != NULL; p = strtok(NULL, ":")) {
        !           235:                        slashp = p[strlen(p) - 1] == '/' ? "" : "/";
        !           236:                        e_subp = (subp = getlist("_subdir")) == NULL ?
        !           237:                            NULL : subp->list.tqh_first;
        !           238:                        for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
        !           239:                                (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
        !           240:                                    p, slashp, e_subp->s, machine);
        !           241:                                if ((ep = malloc(sizeof(ENTRY))) == NULL ||
        !           242:                                    (ep->s = strdup(buf)) == NULL)
        !           243:                                        err(1, NULL);
        !           244:                                TAILQ_INSERT_HEAD(&defp->list, ep, q);
        !           245:                        }
        !           246:                }
        !           247:
        !           248:        /*
        !           249:         * 4: If no -m was specified, and a section was, rewrite the section's
        !           250:         *    paths (if they have a trailing slash) to append the _subdir list
        !           251:         *    and the machine.  This then becomes the _default list.
        !           252:         */
        !           253:        if (p_add == NULL && section != NULL) {
        !           254:                sectnewp = addlist("_section_new");
        !           255:                for (e_sectp = section->list.tqh_first;
        !           256:                    e_sectp != NULL; e_sectp = e_sectp->q.tqe_next) {
        !           257:                        if (e_sectp->s[strlen(e_sectp->s) - 1] != '/') {
        !           258:                                (void)snprintf(buf, sizeof(buf),
        !           259:                                    "%s{/%s,}", e_sectp->s, machine);
        !           260:                                if ((ep = malloc(sizeof(ENTRY))) == NULL ||
        !           261:                                    (ep->s = strdup(buf)) == NULL)
        !           262:                                        err(1, NULL);
        !           263:                                TAILQ_INSERT_TAIL(&sectnewp->list, ep, q);
        !           264:                                continue;
        !           265:                        }
        !           266:                        e_subp = (subp = getlist("_subdir")) == NULL ?
        !           267:                            NULL : subp->list.tqh_first;
        !           268:                        for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
        !           269:                                (void)snprintf(buf, sizeof(buf), "%s%s{/%s,}",
        !           270:                                    e_sectp->s, e_subp->s, machine);
        !           271:                                if ((ep = malloc(sizeof(ENTRY))) == NULL ||
        !           272:                                    (ep->s = strdup(buf)) == NULL)
        !           273:                                        err(1, NULL);
        !           274:                                TAILQ_INSERT_TAIL(&sectnewp->list, ep, q);
        !           275:                        }
        !           276:                }
        !           277:                sectnewp->s = section->s;
        !           278:                defp = sectnewp;
        !           279:                TAILQ_REMOVE(&head, section, q);
        !           280:        }
        !           281:
        !           282:        /*
        !           283:         * 5: Search for the files.  Set up an interrupt handler, so the
        !           284:         *    temporary files go away.
        !           285:         */
        !           286:        (void)signal(SIGINT, onsig);
        !           287:        (void)signal(SIGHUP, onsig);
        !           288:
        !           289:        memset(&pg, 0, sizeof(pg));
        !           290:        for (found = 0; *argv; ++argv)
        !           291:                if (manual(*argv, defp, &pg))
        !           292:                        found = 1;
        !           293:
        !           294:        /* 6: If nothing found, we're done. */
        !           295:        if (!found) {
        !           296:                (void)cleanup();
        !           297:                exit (1);
        !           298:        }
        !           299:
        !           300:        /* 7: If it's simple, display it fast. */
        !           301:        if (f_cat) {
        !           302:                for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
        !           303:                        if (**ap == '\0')
        !           304:                                continue;
        !           305:                        cat(*ap);
        !           306:                }
        !           307:                exit (cleanup());
        !           308:        }
        !           309:        if (f_how) {
        !           310:                for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
        !           311:                        if (**ap == '\0')
        !           312:                                continue;
        !           313:                        how(*ap);
        !           314:                }
        !           315:                exit(cleanup());
        !           316:        }
        !           317:        if (f_where) {
        !           318:                for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
        !           319:                        if (**ap == '\0')
        !           320:                                continue;
        !           321:                        (void)printf("%s\n", *ap);
        !           322:                }
        !           323:                exit(cleanup());
        !           324:        }
        !           325:
        !           326:        /*
        !           327:         * 8: We display things in a single command; build a list of things
        !           328:         *    to display.
        !           329:         */
        !           330:        for (ap = pg.gl_pathv, len = strlen(pager) + 1; *ap != NULL; ++ap) {
        !           331:                if (**ap == '\0')
        !           332:                        continue;
        !           333:                len += strlen(*ap) + 1;
        !           334:        }
        !           335:        if ((cmd = malloc(len)) == NULL) {
        !           336:                warn(NULL);
        !           337:                (void)cleanup();
        !           338:                exit(1);
        !           339:        }
        !           340:        p = cmd;
        !           341:        len = strlen(pager);
        !           342:        memmove(p, pager, len);
        !           343:        p += len;
        !           344:        *p++ = ' ';
        !           345:        for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
        !           346:                if (**ap == '\0')
        !           347:                        continue;
        !           348:                len = strlen(*ap);
        !           349:                memmove(p, *ap, len);
        !           350:                p += len;
        !           351:                *p++ = ' ';
        !           352:        }
        !           353:        *p = '\0';
        !           354:
        !           355:        /* Use system(3) in case someone's pager is "pager arg1 arg2". */
        !           356:        (void)system(cmd);
        !           357:
        !           358:        exit(cleanup());
        !           359: }
        !           360:
        !           361: /*
        !           362:  * manual --
        !           363:  *     Search the manuals for the pages.
        !           364:  */
        !           365: static int
        !           366: manual(page, tag, pg)
        !           367:        char *page;
        !           368:        TAG *tag;
        !           369:        glob_t *pg;
        !           370: {
        !           371:        ENTRY *ep, *e_sufp, *e_tag;
        !           372:        TAG *missp, *sufp;
        !           373:        int anyfound, cnt, found;
        !           374:        char *p, buf[128];
        !           375:
        !           376:        anyfound = 0;
        !           377:        buf[0] = '*';
        !           378:
        !           379:        /* For each element in the list... */
        !           380:        e_tag = tag == NULL ? NULL : tag->list.tqh_first;
        !           381:        for (; e_tag != NULL; e_tag = e_tag->q.tqe_next) {
        !           382:                (void)snprintf(buf, sizeof(buf), "%s/%s.*", e_tag->s, page);
        !           383:                if (glob(buf,
        !           384:                    GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT | GLOB_QUOTE,
        !           385:                    NULL, pg)) {
        !           386:                        warn("globbing");
        !           387:                        (void)cleanup();
        !           388:                        exit(1);
        !           389:                }
        !           390:                if (pg->gl_matchc == 0)
        !           391:                        continue;
        !           392:
        !           393:                /* Find out if it's really a man page. */
        !           394:                for (cnt = pg->gl_pathc - pg->gl_matchc;
        !           395:                    cnt < pg->gl_pathc; ++cnt) {
        !           396:
        !           397:                        /*
        !           398:                         * Try the _suffix key words first.
        !           399:                         *
        !           400:                         * XXX
        !           401:                         * Older versions of man.conf didn't have the suffix
        !           402:                         * key words, it was assumed that everything was a .0.
        !           403:                         * We just test for .0 first, it's fast and probably
        !           404:                         * going to hit.
        !           405:                         */
        !           406:                        (void)snprintf(buf, sizeof(buf), "*/%s.0", page);
        !           407:                        if (!fnmatch(buf, pg->gl_pathv[cnt], 0))
        !           408:                                goto next;
        !           409:
        !           410:                        e_sufp = (sufp = getlist("_suffix")) == NULL ?
        !           411:                            NULL : sufp->list.tqh_first;
        !           412:                        for (found = 0;
        !           413:                            e_sufp != NULL; e_sufp = e_sufp->q.tqe_next) {
        !           414:                                (void)snprintf(buf,
        !           415:                                     sizeof(buf), "*/%s%s", page, e_sufp->s);
        !           416:                                if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) {
        !           417:                                        found = 1;
        !           418:                                        break;
        !           419:                                }
        !           420:                        }
        !           421:                        if (found)
        !           422:                                goto next;
        !           423:
        !           424:                        /* Try the _build key words next. */
        !           425:                        e_sufp = (sufp = getlist("_build")) == NULL ?
        !           426:                            NULL : sufp->list.tqh_first;
        !           427:                        for (found = 0;
        !           428:                            e_sufp != NULL; e_sufp = e_sufp->q.tqe_next) {
        !           429:                                for (p = e_sufp->s;
        !           430:                                    *p != '\0' && !isspace(*p); ++p);
        !           431:                                if (*p == '\0')
        !           432:                                        continue;
        !           433:                                *p = '\0';
        !           434:                                (void)snprintf(buf,
        !           435:                                     sizeof(buf), "*/%s%s", page, e_sufp->s);
        !           436:                                if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) {
        !           437:                                        if (!f_where)
        !           438:                                                build_page(p + 1,
        !           439:                                                    &pg->gl_pathv[cnt]);
        !           440:                                        *p = ' ';
        !           441:                                        found = 1;
        !           442:                                        break;
        !           443:                                }
        !           444:                                *p = ' ';
        !           445:                        }
        !           446:                        if (found) {
        !           447: next:                          anyfound = 1;
        !           448:                                if (!f_all) {
        !           449:                                        /* Delete any other matches. */
        !           450:                                        while (++cnt< pg->gl_pathc)
        !           451:                                                pg->gl_pathv[cnt] = "";
        !           452:                                        break;
        !           453:                                }
        !           454:                                continue;
        !           455:                        }
        !           456:
        !           457:                        /* It's not a man page, forget about it. */
        !           458:                        pg->gl_pathv[cnt] = "";
        !           459:                }
        !           460:
        !           461:                if (anyfound && !f_all)
        !           462:                        break;
        !           463:        }
        !           464:
        !           465:        /* If not found, enter onto the missing list. */
        !           466:        if (!anyfound) {
        !           467:                if ((missp = getlist("_missing")) == NULL)
        !           468:                        missp = addlist("_missing");
        !           469:                if ((ep = malloc(sizeof(ENTRY))) == NULL ||
        !           470:                    (ep->s = strdup(page)) == NULL) {
        !           471:                        warn(NULL);
        !           472:                        (void)cleanup();
        !           473:                        exit(1);
        !           474:                }
        !           475:                TAILQ_INSERT_TAIL(&missp->list, ep, q);
        !           476:        }
        !           477:        return (anyfound);
        !           478: }
        !           479:
        !           480: /*
        !           481:  * build_page --
        !           482:  *     Build a man page for display.
        !           483:  */
        !           484: static void
        !           485: build_page(fmt, pathp)
        !           486:        char *fmt, **pathp;
        !           487: {
        !           488:        static int warned;
        !           489:        ENTRY *ep;
        !           490:        TAG *intmpp;
        !           491:        int fd, n;
        !           492:        char *p, *b;
        !           493:        char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[sizeof(_PATH_TMP)];
        !           494:
        !           495:        /* Let the user know this may take awhile. */
        !           496:        if (!warned) {
        !           497:                warned = 1;
        !           498:                warnx("Formatting manual page...");
        !           499:        }
        !           500:
        !           501:        /*
        !           502:         * Historically man chdir'd to the root of the man tree.
        !           503:         * This was used in man pages that contained relative ".so"
        !           504:         * directives (including other man pages for command aliases etc.)
        !           505:         * It even went one step farther, by examining the first line
        !           506:         * of the man page and parsing the .so filename so it would
        !           507:         * make hard(?) links to the cat'ted man pages for space savings.
        !           508:         * (We don't do that here, but we could).
        !           509:         */
        !           510:
        !           511:        /* copy and find the end */
        !           512:        for (b = buf, p = *pathp; (*b++ = *p++) != '\0';)
        !           513:                continue;
        !           514:
        !           515:        /* skip the last two path components, page name and man[n] */
        !           516:        for (--b, n = 2; b != buf; b--)
        !           517:                if (*b == '/')
        !           518:                        if (--n == 0) {
        !           519:                                *b = '\0';
        !           520:                                (void) chdir(buf);
        !           521:                        }
        !           522:
        !           523:
        !           524:        /* Add a remove-when-done list. */
        !           525:        if ((intmpp = getlist("_intmp")) == NULL)
        !           526:                intmpp = addlist("_intmp");
        !           527:
        !           528:        /* Move to the printf(3) format string. */
        !           529:        for (; *fmt && isspace(*fmt); ++fmt);
        !           530:
        !           531:        /*
        !           532:         * Get a temporary file and build a version of the file
        !           533:         * to display.  Replace the old file name with the new one.
        !           534:         */
        !           535:        (void)strcpy(tpath, _PATH_TMP);
        !           536:        if ((fd = mkstemp(tpath)) == -1) {
        !           537:                warn("%s", tpath);
        !           538:                (void)cleanup();
        !           539:                exit(1);
        !           540:        }
        !           541:        (void)snprintf(buf, sizeof(buf), "%s > %s", fmt, tpath);
        !           542:        (void)snprintf(cmd, sizeof(cmd), buf, *pathp);
        !           543:        (void)system(cmd);
        !           544:        (void)close(fd);
        !           545:        if ((*pathp = strdup(tpath)) == NULL) {
        !           546:                warn(NULL);
        !           547:                (void)cleanup();
        !           548:                exit(1);
        !           549:        }
        !           550:
        !           551:        /* Link the built file into the remove-when-done list. */
        !           552:        if ((ep = malloc(sizeof(ENTRY))) == NULL) {
        !           553:                warn(NULL);
        !           554:                (void)cleanup();
        !           555:                exit(1);
        !           556:        }
        !           557:        ep->s = *pathp;
        !           558:        TAILQ_INSERT_TAIL(&intmpp->list, ep, q);
        !           559: }
        !           560:
        !           561: /*
        !           562:  * how --
        !           563:  *     display how information
        !           564:  */
        !           565: static void
        !           566: how(fname)
        !           567:        char *fname;
        !           568: {
        !           569:        FILE *fp;
        !           570:
        !           571:        int lcnt, print;
        !           572:        char *p, buf[256];
        !           573:
        !           574:        if (!(fp = fopen(fname, "r"))) {
        !           575:                warn("%s", fname);
        !           576:                (void)cleanup();
        !           577:                exit (1);
        !           578:        }
        !           579: #define        S1      "SYNOPSIS"
        !           580: #define        S2      "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"
        !           581: #define        D1      "DESCRIPTION"
        !           582: #define        D2      "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN"
        !           583:        for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) {
        !           584:                if (!strncmp(buf, S1, sizeof(S1) - 1) ||
        !           585:                    !strncmp(buf, S2, sizeof(S2) - 1)) {
        !           586:                        print = 1;
        !           587:                        continue;
        !           588:                } else if (!strncmp(buf, D1, sizeof(D1) - 1) ||
        !           589:                    !strncmp(buf, D2, sizeof(D2) - 1))
        !           590:                        return;
        !           591:                if (!print)
        !           592:                        continue;
        !           593:                if (*buf == '\n')
        !           594:                        ++lcnt;
        !           595:                else {
        !           596:                        for(; lcnt; --lcnt)
        !           597:                                (void)putchar('\n');
        !           598:                        for (p = buf; isspace(*p); ++p);
        !           599:                        (void)fputs(p, stdout);
        !           600:                }
        !           601:        }
        !           602:        (void)fclose(fp);
        !           603: }
        !           604:
        !           605: /*
        !           606:  * cat --
        !           607:  *     cat out the file
        !           608:  */
        !           609: static void
        !           610: cat(fname)
        !           611:        char *fname;
        !           612: {
        !           613:        int fd, n;
        !           614:        char buf[2048];
        !           615:
        !           616:        if ((fd = open(fname, O_RDONLY, 0)) < 0) {
        !           617:                warn("%s", fname);
        !           618:                (void)cleanup();
        !           619:                exit(1);
        !           620:        }
        !           621:        while ((n = read(fd, buf, sizeof(buf))) > 0)
        !           622:                if (write(STDOUT_FILENO, buf, n) != n) {
        !           623:                        warn("write");
        !           624:                        (void)cleanup();
        !           625:                        exit (1);
        !           626:                }
        !           627:        if (n == -1) {
        !           628:                warn("read");
        !           629:                (void)cleanup();
        !           630:                exit(1);
        !           631:        }
        !           632:        (void)close(fd);
        !           633: }
        !           634:
        !           635: /*
        !           636:  * check_pager --
        !           637:  *     check the user supplied page information
        !           638:  */
        !           639: static char *
        !           640: check_pager(name)
        !           641:        char *name;
        !           642: {
        !           643:        char *p, *save;
        !           644:
        !           645:        /*
        !           646:         * if the user uses "more", we make it "more -s"; watch out for
        !           647:         * PAGER = "mypager /usr/ucb/more"
        !           648:         */
        !           649:        for (p = name; *p && !isspace(*p); ++p);
        !           650:        for (; p > name && *p != '/'; --p);
        !           651:        if (p != name)
        !           652:                ++p;
        !           653:
        !           654:        /* make sure it's "more", not "morex" */
        !           655:        if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){
        !           656:                save = name;
        !           657:                /* allocate space to add the "-s" */
        !           658:                if (!(name =
        !           659:                    malloc((u_int)(strlen(save) + sizeof("-s") + 1))))
        !           660:                        err(1, NULL);
        !           661:                (void)sprintf(name, "%s %s", save, "-s");
        !           662:        }
        !           663:        return(name);
        !           664: }
        !           665:
        !           666: /*
        !           667:  * jump --
        !           668:  *     strip out flag argument and jump
        !           669:  */
        !           670: static void
        !           671: jump(argv, flag, name)
        !           672:        char **argv, *flag, *name;
        !           673: {
        !           674:        char **arg;
        !           675:
        !           676:        argv[0] = name;
        !           677:        for (arg = argv + 1; *arg; ++arg)
        !           678:                if (!strcmp(*arg, flag))
        !           679:                        break;
        !           680:        for (; *arg; ++arg)
        !           681:                arg[0] = arg[1];
        !           682:        execvp(name, argv);
        !           683:        (void)fprintf(stderr, "%s: Command not found.\n", name);
        !           684:        exit(1);
        !           685: }
        !           686:
        !           687: /*
        !           688:  * onsig --
        !           689:  *     If signaled, delete the temporary files.
        !           690:  */
        !           691: static void
        !           692: onsig(signo)
        !           693:        int signo;
        !           694: {
        !           695:        (void)cleanup();
        !           696:
        !           697:        (void)signal(signo, SIG_DFL);
        !           698:        (void)kill(getpid(), signo);
        !           699:
        !           700:        /* NOTREACHED */
        !           701:        exit (1);
        !           702: }
        !           703:
        !           704: /*
        !           705:  * cleanup --
        !           706:  *     Clean up temporary files, show any error messages.
        !           707:  */
        !           708: static int
        !           709: cleanup()
        !           710: {
        !           711:        TAG *intmpp, *missp;
        !           712:        ENTRY *ep;
        !           713:        int rval;
        !           714:
        !           715:        rval = 0;
        !           716:        ep = (missp = getlist("_missing")) == NULL ?
        !           717:            NULL : missp->list.tqh_first;
        !           718:        if (ep != NULL)
        !           719:                for (; ep != NULL; ep = ep->q.tqe_next) {
        !           720:                        warnx("no entry for %s in the manual.", ep->s);
        !           721:                        rval = 1;
        !           722:                }
        !           723:
        !           724:        ep = (intmpp = getlist("_intmp")) == NULL ?
        !           725:            NULL : intmpp->list.tqh_first;
        !           726:        for (; ep != NULL; ep = ep->q.tqe_next)
        !           727:                (void)unlink(ep->s);
        !           728:        return (rval);
        !           729: }
        !           730:
        !           731: /*
        !           732:  * usage --
        !           733:  *     print usage message and die
        !           734:  */
        !           735: static void
        !           736: usage()
        !           737: {
        !           738:        (void)fprintf(stderr,
        !           739:     "usage: man [-achw] [-C file] [-M path] [-m path] [section] title ...\n");
        !           740:        exit(1);
        !           741: }