Annotation of src/usr.bin/man/man.c, Revision 1.41
1.41 ! deraadt 1: /* $OpenBSD: man.c,v 1.40 2010/10/22 14:08:53 mikeb Exp $ */
1.1 deraadt 2: /* $NetBSD: man.c,v 1.7 1995/09/28 06:05:34 tls Exp $ */
3:
4: /*
1.39 schwarze 5: * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
6: *
7: * Permission to use, copy, modify, and distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
20: /*
1.1 deraadt 21: * Copyright (c) 1987, 1993, 1994, 1995
22: * The Regents of the University of California. All rights reserved.
23: *
24: * Redistribution and use in source and binary forms, with or without
25: * modification, are permitted provided that the following conditions
26: * are met:
27: * 1. Redistributions of source code must retain the above copyright
28: * notice, this list of conditions and the following disclaimer.
29: * 2. Redistributions in binary form must reproduce the above copyright
30: * notice, this list of conditions and the following disclaimer in the
31: * documentation and/or other materials provided with the distribution.
1.25 millert 32: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 33: * may be used to endorse or promote products derived from this software
34: * without specific prior written permission.
35: *
36: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
37: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
40: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46: * SUCH DAMAGE.
47: */
48:
49: #include <sys/param.h>
50: #include <sys/queue.h>
51:
52: #include <ctype.h>
53: #include <err.h>
54: #include <errno.h>
55: #include <fcntl.h>
56: #include <fnmatch.h>
57: #include <glob.h>
58: #include <signal.h>
59: #include <stdio.h>
1.11 deraadt 60: #include <libgen.h>
1.1 deraadt 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;
1.39 schwarze 69: static char gbuf[MAXPATHLEN * 2];
70: static TAG *section;
1.1 deraadt 71:
1.8 millert 72: extern char *__progname;
73:
1.39 schwarze 74: static void clearlist(TAG *);
75: static void parse_path(TAG *, char *);
76: static void append_subdirs(TAG *, const char *);
1.20 millert 77: static void build_page(char *, char **);
78: static void cat(char *);
79: static char *check_pager(char *);
1.41 ! deraadt 80: static int cleanup(int);
1.20 millert 81: static void how(char *);
82: static void jump(char **, char *, char *);
83: static int manual(char *, TAG *, glob_t *);
84: static void onsig(int);
85: static void usage(void);
1.1 deraadt 86:
1.19 deraadt 87: sigset_t blocksigs;
88:
1.1 deraadt 89: int
1.21 deraadt 90: main(int argc, char *argv[])
1.1 deraadt 91: {
92: extern char *optarg;
93: extern int optind;
1.39 schwarze 94: TAG *searchlist;
95: ENTRY *ep;
1.1 deraadt 96: glob_t pg;
97: size_t len;
98: int ch, f_cat, f_how, found;
1.39 schwarze 99: char **ap, *cmd, *machine, *p, *p_add, *p_path, *pager, *sflag;
100: char *conffile;
1.11 deraadt 101:
102: if (argv[1] == NULL && strcmp(basename(__progname), "help") == 0) {
103: static char *nargv[3];
104: nargv[0] = "man";
1.15 aaron 105: nargv[1] = "help";
1.11 deraadt 106: nargv[2] = NULL;
107: argv = nargv;
108: argc = 2;
109: }
1.1 deraadt 110:
1.7 millert 111: machine = sflag = NULL;
1.1 deraadt 112: f_cat = f_how = 0;
113: conffile = p_add = p_path = NULL;
1.23 millert 114: while ((ch = getopt(argc, argv, "aC:cfhkM:m:P:s:S:w-")) != -1)
1.1 deraadt 115: switch (ch) {
116: case 'a':
117: f_all = 1;
118: break;
119: case 'C':
120: conffile = optarg;
121: break;
122: case 'c':
123: case '-': /* Deprecated. */
124: f_cat = 1;
125: break;
126: case 'h':
127: f_how = 1;
128: break;
129: case 'm':
130: p_add = optarg;
131: break;
132: case 'M':
133: case 'P': /* Backward compatibility. */
134: p_path = optarg;
135: break;
1.7 millert 136: case 's': /* SVR4 compatibility. */
137: sflag = optarg;
138: break;
139: case 'S':
140: machine = optarg;
141: break;
1.1 deraadt 142: /*
1.22 espie 143: * The -f and -k options are backward compatible
144: * ways of calling whatis(1) and apropos(1).
1.1 deraadt 145: */
146: case 'f':
147: jump(argv, "-f", "whatis");
148: /* NOTREACHED */
149: case 'k':
150: jump(argv, "-k", "apropos");
151: /* NOTREACHED */
152: case 'w':
153: f_all = f_where = 1;
154: break;
155: case '?':
156: default:
157: usage();
158: }
159: argc -= optind;
160: argv += optind;
161:
162: if (!*argv)
163: usage();
164:
1.17 millert 165: if (!f_cat && !f_how && !f_where) {
1.1 deraadt 166: if (!isatty(1))
167: f_cat = 1;
1.27 millert 168: else if ((pager = getenv("MANPAGER")) != NULL &&
169: (*pager != '\0'))
170: pager = check_pager(pager);
1.13 pjanzen 171: else if ((pager = getenv("PAGER")) != NULL && (*pager != '\0'))
1.1 deraadt 172: pager = check_pager(pager);
173: else
174: pager = _PATH_PAGER;
1.17 millert 175: }
1.1 deraadt 176:
177: /* Read the configuration file. */
178: config(conffile);
179:
1.39 schwarze 180: /*
181: * 1: If the user specified a section,
182: * use the section list from the configuration file.
183: * Otherwise, fall back to the default list or to an empty list.
184: */
185: if (sflag && (section = getlist(sflag)) == NULL)
186: errx(1, "unknown manual section `%s'", sflag);
187: else if (argv[1] && (section = getlist(*argv)) != NULL)
188: ++argv;
189:
190: searchlist = section;
191: if (searchlist == NULL)
192: searchlist = getlist("_default");
193: if (searchlist == NULL)
194: searchlist = addlist("_default");
1.1 deraadt 195:
196: /*
1.39 schwarze 197: * 2: If the user set the -M option or defined the MANPATH variable,
198: * clear what we have and take the user's list instead.
1.1 deraadt 199: */
200: if (p_path == NULL)
201: p_path = getenv("MANPATH");
202:
1.39 schwarze 203: if (p_path) {
204: clearlist(searchlist);
205: parse_path(searchlist, p_path);
1.1 deraadt 206: }
207:
208: /*
209: * 3: If the user set the -m option, insert the user's list before
1.39 schwarze 210: * whatever list we have.
1.1 deraadt 211: */
1.39 schwarze 212: if (p_add)
213: parse_path(searchlist, p_add);
214:
1.1 deraadt 215: /*
1.39 schwarze 216: * 4: Append the _subdir list where appropriate,
217: * and always append the machine type.
1.1 deraadt 218: */
1.39 schwarze 219: if (machine || (machine = getenv("MACHINE")))
220: for (p = machine; *p; ++p)
221: *p = tolower(*p);
222: else
223: machine = MACHINE;
224:
225: append_subdirs(searchlist, machine);
1.1 deraadt 226:
227: /*
228: * 5: Search for the files. Set up an interrupt handler, so the
229: * temporary files go away.
230: */
231: (void)signal(SIGINT, onsig);
232: (void)signal(SIGHUP, onsig);
233:
1.19 deraadt 234: sigemptyset(&blocksigs);
235: sigaddset(&blocksigs, SIGINT);
236: sigaddset(&blocksigs, SIGHUP);
237:
1.1 deraadt 238: memset(&pg, 0, sizeof(pg));
239: for (found = 0; *argv; ++argv)
1.39 schwarze 240: if (manual(*argv, searchlist, &pg))
1.1 deraadt 241: found = 1;
242:
243: /* 6: If nothing found, we're done. */
244: if (!found) {
1.41 ! deraadt 245: (void)cleanup(0);
1.1 deraadt 246: exit (1);
247: }
248:
249: /* 7: If it's simple, display it fast. */
250: if (f_cat) {
251: for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
252: if (**ap == '\0')
253: continue;
254: cat(*ap);
255: }
1.41 ! deraadt 256: exit (cleanup(0));
1.1 deraadt 257: }
258: if (f_how) {
259: for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
260: if (**ap == '\0')
261: continue;
262: how(*ap);
263: }
1.41 ! deraadt 264: exit(cleanup(0));
1.1 deraadt 265: }
266: if (f_where) {
267: for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
268: if (**ap == '\0')
269: continue;
1.17 millert 270: (void)puts(*ap);
1.1 deraadt 271: }
1.41 ! deraadt 272: exit(cleanup(0));
1.1 deraadt 273: }
1.17 millert 274:
1.1 deraadt 275: /*
276: * 8: We display things in a single command; build a list of things
277: * to display.
278: */
279: for (ap = pg.gl_pathv, len = strlen(pager) + 1; *ap != NULL; ++ap) {
280: if (**ap == '\0')
281: continue;
282: len += strlen(*ap) + 1;
283: }
284: if ((cmd = malloc(len)) == NULL) {
285: warn(NULL);
1.41 ! deraadt 286: (void)cleanup(0);
1.1 deraadt 287: exit(1);
288: }
289: p = cmd;
290: len = strlen(pager);
1.17 millert 291: memcpy(p, pager, len);
1.1 deraadt 292: p += len;
293: *p++ = ' ';
294: for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
295: if (**ap == '\0')
296: continue;
297: len = strlen(*ap);
1.17 millert 298: memcpy(p, *ap, len);
1.1 deraadt 299: p += len;
300: *p++ = ' ';
301: }
1.12 deraadt 302: *--p = '\0';
1.1 deraadt 303:
304: /* Use system(3) in case someone's pager is "pager arg1 arg2". */
305: (void)system(cmd);
306:
1.41 ! deraadt 307: exit(cleanup(0));
1.39 schwarze 308: }
309:
310: /*
311: * clearlist --
312: * Remove all entries from a list,
313: * but leave the list header intact.
314: */
315: static void
316: clearlist(TAG *t)
317: {
318: ENTRY *e;
319:
320: while ((e = TAILQ_FIRST(&t->list)) != NULL) {
321: free(e->s);
322: TAILQ_REMOVE(&t->list, e, q);
323: free(e);
324: }
325: }
326:
327: /*
328: * parse_path --
329: * Split the -M or -m argument or the MANPATH variable at colons,
330: * and insert the parts into the searchlist.
331: */
332: static void
333: parse_path(TAG *t, char *path)
334: {
335: ENTRY *eplast = NULL, *ep;
336: char *p, *slashp;
337:
338: while ((p = strsep(&path, ":")) != NULL) {
339: if ((ep = malloc(sizeof(ENTRY))) == NULL)
340: err(1, NULL);
341:
342: /*
343: * Bring section specific paths to the same format as
344: * used in the configuration file, ending in /{cat,man}N.
345: */
346: if (section) {
347: slashp = p[strlen(p) - 1] == '/' ? "" : "/";
348: (void)snprintf(gbuf, sizeof(gbuf),
349: "%s%s{cat,man}%s", p, slashp, t->s);
350: if ((ep->s = strdup(gbuf)) == NULL)
351: err(1, NULL);
352: }
353:
354: /* Without a section, subdirs will be appended later. */
355: else
356: if ((ep->s = strdup(p)) == NULL)
357: err(1, NULL);
358:
359: /*
360: * Even in case of -M, inserting in front is fine:
361: * We have just cleared the list.
362: */
363: if (eplast)
364: TAILQ_INSERT_AFTER(&t->list, eplast, ep, q);
365: else
366: TAILQ_INSERT_HEAD(&t->list, ep, q);
367: eplast = ep;
368: }
369: }
370:
371: /*
372: * append_subdirs --
373: * Iterate the searchlist and append section and machine
374: * subdirectories as needed.
375: */
376: static void
377: append_subdirs(TAG *t, const char *machine)
378: {
379: TAG *tsub;
380: ENTRY *eold, *elast, *enew, *esub;
381: char *slashp;
382:
383: eold = elast = TAILQ_FIRST(&t->list);
384: while (eold) {
385:
386: /*
387: * Section subdirectories *not* ending in a slash
388: * only get the machine suffix: They already had
389: * the {cat,man}N part in the configuration file
390: * or got it in parse_path().
391: */
392: if (section && eold->s[strlen(eold->s)-1] != '/') {
393: (void)snprintf(gbuf, sizeof(gbuf), "%s{/%s,}",
394: eold->s, machine);
395: free(eold->s);
396: if ((eold->s = strdup(gbuf)) == NULL)
397: err(1, NULL);
398: eold = elast = TAILQ_NEXT(eold, q);
399: continue;
400: }
401:
402: /*
403: * Without a section, expand each entry using the
404: * subdir list, then drop the original entry.
405: */
406: esub = (tsub = getlist("_subdir")) == NULL ?
407: NULL : TAILQ_FIRST(&tsub->list);
408: while (esub) {
409: slashp = eold->s[strlen(eold->s)-1] == '/' ? "" : "/";
410: (void)snprintf(gbuf, sizeof(gbuf), "%s%s%s{/%s,}",
411: eold->s, slashp, esub->s, machine);
412: if ((enew = malloc(sizeof(ENTRY))) == NULL ||
413: (enew->s = strdup(gbuf)) == NULL)
414: err(1, NULL);
415: TAILQ_INSERT_AFTER(&t->list, elast, enew, q);
416: elast = enew;
417: esub = TAILQ_NEXT(esub, q);
418: }
419: elast = TAILQ_NEXT(elast, q);
420: TAILQ_REMOVE(&t->list, eold, q);
421: eold = elast;
422: }
1.1 deraadt 423: }
424:
425: /*
426: * manual --
427: * Search the manuals for the pages.
428: */
429: static int
1.26 deraadt 430: manual(char *page, TAG *tag, glob_t *pg)
1.1 deraadt 431: {
432: ENTRY *ep, *e_sufp, *e_tag;
433: TAG *missp, *sufp;
434: int anyfound, cnt, found;
1.6 deraadt 435: char *p, buf[MAXPATHLEN];
1.1 deraadt 436:
437: anyfound = 0;
438: buf[0] = '*';
439:
440: /* For each element in the list... */
1.29 otto 441: e_tag = tag == NULL ? NULL : TAILQ_FIRST(&tag->list);
442: for (; e_tag != NULL; e_tag = TAILQ_NEXT(e_tag, q)) {
1.1 deraadt 443: (void)snprintf(buf, sizeof(buf), "%s/%s.*", e_tag->s, page);
444: if (glob(buf,
445: GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT | GLOB_QUOTE,
446: NULL, pg)) {
447: warn("globbing");
1.41 ! deraadt 448: (void)cleanup(0);
1.1 deraadt 449: exit(1);
450: }
451: if (pg->gl_matchc == 0)
452: continue;
453:
454: /* Find out if it's really a man page. */
455: for (cnt = pg->gl_pathc - pg->gl_matchc;
456: cnt < pg->gl_pathc; ++cnt) {
457:
458: /*
459: * Try the _suffix key words first.
460: *
461: * XXX
462: * Older versions of man.conf didn't have the suffix
463: * key words, it was assumed that everything was a .0.
464: * We just test for .0 first, it's fast and probably
465: * going to hit.
466: */
467: (void)snprintf(buf, sizeof(buf), "*/%s.0", page);
468: if (!fnmatch(buf, pg->gl_pathv[cnt], 0))
469: goto next;
470:
471: e_sufp = (sufp = getlist("_suffix")) == NULL ?
1.29 otto 472: NULL : TAILQ_FIRST(&sufp->list);
1.1 deraadt 473: for (found = 0;
1.29 otto 474: e_sufp != NULL; e_sufp = TAILQ_NEXT(e_sufp, q)) {
1.1 deraadt 475: (void)snprintf(buf,
476: sizeof(buf), "*/%s%s", page, e_sufp->s);
477: if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) {
478: found = 1;
479: break;
480: }
481: }
482: if (found)
483: goto next;
484:
485: /* Try the _build key words next. */
486: e_sufp = (sufp = getlist("_build")) == NULL ?
1.29 otto 487: NULL : TAILQ_FIRST(&sufp->list);
1.1 deraadt 488: for (found = 0;
1.29 otto 489: e_sufp != NULL; e_sufp = TAILQ_NEXT(e_sufp, q)) {
1.1 deraadt 490: for (p = e_sufp->s;
491: *p != '\0' && !isspace(*p); ++p);
492: if (*p == '\0')
493: continue;
494: *p = '\0';
495: (void)snprintf(buf,
496: sizeof(buf), "*/%s%s", page, e_sufp->s);
497: if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) {
498: if (!f_where)
499: build_page(p + 1,
500: &pg->gl_pathv[cnt]);
501: *p = ' ';
502: found = 1;
503: break;
504: }
505: *p = ' ';
506: }
507: if (found) {
508: next: anyfound = 1;
509: if (!f_all) {
510: /* Delete any other matches. */
511: while (++cnt< pg->gl_pathc)
512: pg->gl_pathv[cnt] = "";
513: break;
514: }
515: continue;
516: }
517:
518: /* It's not a man page, forget about it. */
519: pg->gl_pathv[cnt] = "";
520: }
521:
522: if (anyfound && !f_all)
523: break;
524: }
525:
526: /* If not found, enter onto the missing list. */
527: if (!anyfound) {
1.19 deraadt 528: sigset_t osigs;
529:
530: sigprocmask(SIG_BLOCK, &blocksigs, &osigs);
531:
1.1 deraadt 532: if ((missp = getlist("_missing")) == NULL)
533: missp = addlist("_missing");
534: if ((ep = malloc(sizeof(ENTRY))) == NULL ||
535: (ep->s = strdup(page)) == NULL) {
536: warn(NULL);
1.41 ! deraadt 537: (void)cleanup(0);
1.1 deraadt 538: exit(1);
539: }
540: TAILQ_INSERT_TAIL(&missp->list, ep, q);
1.19 deraadt 541: sigprocmask(SIG_SETMASK, &osigs, NULL);
1.1 deraadt 542: }
543: return (anyfound);
544: }
545:
1.17 millert 546: /*
1.1 deraadt 547: * build_page --
548: * Build a man page for display.
549: */
550: static void
1.21 deraadt 551: build_page(char *fmt, char **pathp)
1.1 deraadt 552: {
553: ENTRY *ep;
554: TAG *intmpp;
555: int fd, n;
556: char *p, *b;
1.4 deraadt 557: char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[MAXPATHLEN];
1.19 deraadt 558: sigset_t osigs;
1.1 deraadt 559:
560: /*
1.17 millert 561: * Historically man chdir'd to the root of the man tree.
1.1 deraadt 562: * This was used in man pages that contained relative ".so"
563: * directives (including other man pages for command aliases etc.)
564: * It even went one step farther, by examining the first line
565: * of the man page and parsing the .so filename so it would
566: * make hard(?) links to the cat'ted man pages for space savings.
567: * (We don't do that here, but we could).
568: */
1.17 millert 569:
1.1 deraadt 570: /* copy and find the end */
571: for (b = buf, p = *pathp; (*b++ = *p++) != '\0';)
572: continue;
1.17 millert 573:
1.1 deraadt 574: /* skip the last two path components, page name and man[n] */
575: for (--b, n = 2; b != buf; b--)
576: if (*b == '/')
577: if (--n == 0) {
578: *b = '\0';
579: (void) chdir(buf);
580: }
581:
582:
583: /* Add a remove-when-done list. */
1.19 deraadt 584: sigprocmask(SIG_BLOCK, &blocksigs, &osigs);
1.1 deraadt 585: if ((intmpp = getlist("_intmp")) == NULL)
586: intmpp = addlist("_intmp");
1.19 deraadt 587: sigprocmask(SIG_SETMASK, &osigs, NULL);
1.1 deraadt 588:
589: /* Move to the printf(3) format string. */
1.16 deraadt 590: for (; *fmt && isspace(*fmt); ++fmt)
591: ;
1.1 deraadt 592:
593: /*
594: * Get a temporary file and build a version of the file
595: * to display. Replace the old file name with the new one.
596: */
1.18 deraadt 597: (void)strlcpy(tpath, _PATH_TMPFILE, sizeof(tpath));
1.1 deraadt 598: if ((fd = mkstemp(tpath)) == -1) {
599: warn("%s", tpath);
1.41 ! deraadt 600: (void)cleanup(0);
1.1 deraadt 601: exit(1);
602: }
603: (void)snprintf(buf, sizeof(buf), "%s > %s", fmt, tpath);
604: (void)snprintf(cmd, sizeof(cmd), buf, *pathp);
605: (void)system(cmd);
606: (void)close(fd);
607: if ((*pathp = strdup(tpath)) == NULL) {
608: warn(NULL);
1.41 ! deraadt 609: (void)cleanup(0);
1.1 deraadt 610: exit(1);
611: }
612:
613: /* Link the built file into the remove-when-done list. */
614: if ((ep = malloc(sizeof(ENTRY))) == NULL) {
615: warn(NULL);
1.41 ! deraadt 616: (void)cleanup(0);
1.1 deraadt 617: exit(1);
618: }
619: ep->s = *pathp;
1.41 ! deraadt 620:
! 621: sigprocmask(SIG_BLOCK, &blocksigs, &osigs);
1.1 deraadt 622: TAILQ_INSERT_TAIL(&intmpp->list, ep, q);
1.41 ! deraadt 623: sigprocmask(SIG_SETMASK, &osigs, NULL);
1.1 deraadt 624: }
625:
626: /*
627: * how --
628: * display how information
629: */
630: static void
1.21 deraadt 631: how(char *fname)
1.1 deraadt 632: {
633: FILE *fp;
634:
635: int lcnt, print;
636: char *p, buf[256];
637:
638: if (!(fp = fopen(fname, "r"))) {
639: warn("%s", fname);
1.41 ! deraadt 640: (void)cleanup(0);
1.1 deraadt 641: exit (1);
642: }
643: #define S1 "SYNOPSIS"
644: #define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"
645: for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) {
646: if (!strncmp(buf, S1, sizeof(S1) - 1) ||
647: !strncmp(buf, S2, sizeof(S2) - 1)) {
648: print = 1;
649: continue;
1.34 otto 650: } else if (print) {
651: char *p = buf;
652: int allcaps = 0;
653:
654: while (*p) {
655: if (!allcaps && isalpha(*p))
656: allcaps = 1;
657: if (isalpha(*p) && !isupper(*p)) {
658: allcaps = 0;
659: break;
660: }
661: p++;
662: }
663: if (allcaps) {
664: (void)fclose(fp);
665: return;
666: }
1.32 jasper 667: }
1.1 deraadt 668: if (!print)
669: continue;
670: if (*buf == '\n')
671: ++lcnt;
672: else {
1.17 millert 673: while (lcnt) {
674: --lcnt;
1.1 deraadt 675: (void)putchar('\n');
1.17 millert 676: }
677: for (p = buf; isspace(*p); ++p)
678: ;
1.1 deraadt 679: (void)fputs(p, stdout);
680: }
681: }
682: (void)fclose(fp);
683: }
684:
685: /*
686: * cat --
687: * cat out the file
688: */
689: static void
1.21 deraadt 690: cat(char *fname)
1.1 deraadt 691: {
692: int fd, n;
693: char buf[2048];
694:
695: if ((fd = open(fname, O_RDONLY, 0)) < 0) {
696: warn("%s", fname);
1.41 ! deraadt 697: (void)cleanup(0);
1.1 deraadt 698: exit(1);
699: }
700: while ((n = read(fd, buf, sizeof(buf))) > 0)
701: if (write(STDOUT_FILENO, buf, n) != n) {
702: warn("write");
1.41 ! deraadt 703: (void)cleanup(0);
1.1 deraadt 704: exit (1);
705: }
706: if (n == -1) {
707: warn("read");
1.41 ! deraadt 708: (void)cleanup(0);
1.1 deraadt 709: exit(1);
710: }
711: (void)close(fd);
712: }
713:
714: /*
715: * check_pager --
716: * check the user supplied page information
717: */
718: static char *
1.21 deraadt 719: check_pager(char *name)
1.1 deraadt 720: {
721: char *p, *save;
722:
723: /*
724: * if the user uses "more", we make it "more -s"; watch out for
1.17 millert 725: * PAGER = "mypager /usr/bin/more"
1.1 deraadt 726: */
1.16 deraadt 727: for (p = name; *p && !isspace(*p); ++p)
728: ;
729: for (; p > name && *p != '/'; --p)
730: ;
1.1 deraadt 731: if (p != name)
732: ++p;
733:
734: /* make sure it's "more", not "morex" */
1.27 millert 735: if (!strncmp(p, "more", 4) && (p[4] == '\0' || isspace(p[4]))){
1.1 deraadt 736: save = name;
737: /* allocate space to add the "-s" */
1.31 deraadt 738: if (asprintf(&name, "%s -s", save) == -1)
739: err(1, "asprintf");
1.1 deraadt 740: }
741: return(name);
742: }
743:
744: /*
745: * jump --
746: * strip out flag argument and jump
747: */
748: static void
1.21 deraadt 749: jump(char **argv, char *flag, char *name)
1.1 deraadt 750: {
751: char **arg;
752:
753: argv[0] = name;
754: for (arg = argv + 1; *arg; ++arg)
755: if (!strcmp(*arg, flag))
756: break;
757: for (; *arg; ++arg)
758: arg[0] = arg[1];
759: execvp(name, argv);
760: (void)fprintf(stderr, "%s: Command not found.\n", name);
761: exit(1);
762: }
763:
1.17 millert 764: /*
1.1 deraadt 765: * onsig --
766: * If signaled, delete the temporary files.
767: */
768: static void
1.21 deraadt 769: onsig(int signo)
1.1 deraadt 770: {
1.41 ! deraadt 771: (void)cleanup(1);
1.1 deraadt 772:
773: (void)signal(signo, SIG_DFL);
774: (void)kill(getpid(), signo);
775:
776: /* NOTREACHED */
1.19 deraadt 777: _exit(1);
1.1 deraadt 778: }
779:
780: /*
781: * cleanup --
782: * Clean up temporary files, show any error messages.
783: */
784: static int
1.41 ! deraadt 785: cleanup(int insig)
1.1 deraadt 786: {
787: TAG *intmpp, *missp;
788: ENTRY *ep;
1.41 ! deraadt 789: int rval = 0;
1.1 deraadt 790:
1.41 ! deraadt 791: if (insig == 0) {
! 792: ep = (missp = getlist("_missing")) == NULL ?
! 793: NULL : TAILQ_FIRST(&missp->list);
! 794: if (ep != NULL)
! 795: for (; ep != NULL; ep = TAILQ_NEXT(ep, q)) {
! 796: if (section)
! 797: warnx("no entry for %s in "
! 798: "section %s of the manual.",
! 799: ep->s, section->s);
! 800: else
! 801: warnx("no entry for %s in the manual.",
! 802: ep->s);
! 803: rval = 1;
! 804: }
! 805: }
1.1 deraadt 806:
807: ep = (intmpp = getlist("_intmp")) == NULL ?
1.29 otto 808: NULL : TAILQ_FIRST(&intmpp->list);
809: for (; ep != NULL; ep = TAILQ_NEXT(ep, q))
1.1 deraadt 810: (void)unlink(ep->s);
811: return (rval);
812: }
813:
814: /*
815: * usage --
816: * print usage message and die
817: */
818: static void
1.21 deraadt 819: usage(void)
1.1 deraadt 820: {
1.8 millert 821: (void)fprintf(stderr, "usage: %s [-achw] [-C file] [-M path] [-m path] "
1.35 sobrado 822: "[-S subsection] [-s section]\n\t [section] name ...\n",
1.28 jmc 823: __progname);
1.36 jmc 824: (void)fprintf(stderr, " %s -f command ...\n", __progname);
825: (void)fprintf(stderr, " %s -k keyword ...\n", __progname);
1.1 deraadt 826: exit(1);
827: }