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