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