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