131703Sbostic /* 263537Sbostic * Copyright (c) 1987, 1993 363537Sbostic * The Regents of the University of California. All rights reserved. 433054Sbostic * 542741Sbostic * %sccs.include.redist.c% 631703Sbostic */ 731703Sbostic 831703Sbostic #ifndef lint 963537Sbostic static char copyright[] = 1063537Sbostic "@(#) Copyright (c) 1987, 1993\n\ 1163537Sbostic The Regents of the University of California. All rights reserved.\n"; 1233054Sbostic #endif /* not lint */ 1331703Sbostic 1431703Sbostic #ifndef lint 15*65283Sbostic static char sccsid[] = "@(#)man.c 8.3 (Berkeley) 01/02/94"; 1633054Sbostic #endif /* not lint */ 1731703Sbostic 1831703Sbostic #include <sys/param.h> 19*65283Sbostic #include <sys/queue.h> 2063536Sbostic 2163536Sbostic #include <ctype.h> 22*65283Sbostic #include <err.h> 2340390Sbostic #include <errno.h> 2463536Sbostic #include <fcntl.h> 25*65283Sbostic #include <fnmatch.h> 26*65283Sbostic #include <glob.h> 27*65283Sbostic #include <signal.h> 2863536Sbostic #include <stdio.h> 2963536Sbostic #include <stdlib.h> 3040390Sbostic #include <string.h> 3163536Sbostic #include <unistd.h> 3263536Sbostic 33*65283Sbostic #include "config.h" 3437892Sbostic #include "pathnames.h" 3531703Sbostic 36*65283Sbostic int f_all, f_where; 3731703Sbostic 38*65283Sbostic static void build_page __P((char *, char *)); 39*65283Sbostic static void cat __P((char *)); 40*65283Sbostic static char *check_pager __P((char *)); 41*65283Sbostic static void cleanup __P((void)); 42*65283Sbostic static void how __P((char *)); 43*65283Sbostic static void jump __P((char **, char *, char *)); 44*65283Sbostic static int manual __P((char *, ENTRY *, glob_t *)); 45*65283Sbostic static void onsig __P((int)); 46*65283Sbostic static void usage __P((void)); 4734057Sbostic 48*65283Sbostic int 4931703Sbostic main(argc, argv) 5033354Sbostic int argc; 51*65283Sbostic char *argv[]; 5231703Sbostic { 5334057Sbostic extern char *optarg; 5434057Sbostic extern int optind; 55*65283Sbostic ENTRY *defp, *defnewp, *intmpp; 56*65283Sbostic ENTRY *section, *sectp, *sectnewp, *subp, *tp; 57*65283Sbostic glob_t pg; 58*65283Sbostic size_t len; 59*65283Sbostic int ch, f_cat, f_how, found; 60*65283Sbostic char **ap, *cmd, *machine, *p, *p_add, *p_path, *pager, *slashp; 61*65283Sbostic char buf[MAXPATHLEN * 2]; 6231703Sbostic 63*65283Sbostic f_cat = f_how = 0; 6444938Sbostic while ((ch = getopt(argc, argv, "-acfhkM:m:P:w")) != EOF) 65*65283Sbostic switch (ch) { 6640390Sbostic case 'a': 6740390Sbostic f_all = 1; 6831703Sbostic break; 6940390Sbostic case 'c': 70*65283Sbostic case '-': /* Deprecated. */ 7140390Sbostic f_cat = 1; 7240390Sbostic break; 7344938Sbostic case 'h': 7444938Sbostic f_how = 1; 7544938Sbostic break; 7640390Sbostic case 'm': 77*65283Sbostic p_add = optarg; 7840390Sbostic break; 7931703Sbostic case 'M': 80*65283Sbostic case 'P': /* Backward compatibility. */ 8140390Sbostic p_path = optarg; 8231703Sbostic break; 8342402Sbostic /* 84*65283Sbostic * The -f and -k options are backward compatible, 85*65283Sbostic * undocumented ways of calling whatis(1) and apropos(1). 8642402Sbostic */ 8731703Sbostic case 'f': 8834057Sbostic jump(argv, "-f", "whatis"); 8940390Sbostic /* NOTREACHED */ 9031703Sbostic case 'k': 9134057Sbostic jump(argv, "-k", "apropos"); 9240390Sbostic /* NOTREACHED */ 9332565Sbostic case 'w': 9440390Sbostic f_all = f_where = 1; 9532565Sbostic break; 9631703Sbostic case '?': 9731703Sbostic default: 9834057Sbostic usage(); 9931703Sbostic } 10065282Sbostic argc -= optind; 10134057Sbostic argv += optind; 10231703Sbostic 10334057Sbostic if (!*argv) 10434057Sbostic usage(); 10533354Sbostic 10644938Sbostic if (!f_cat && !f_how) 10731703Sbostic if (!isatty(1)) 10840390Sbostic f_cat = 1; 10940390Sbostic else if (pager = getenv("PAGER")) 11040390Sbostic pager = check_pager(pager); 11131779Sbostic else 11237892Sbostic pager = _PATH_PAGER; 11340390Sbostic 114*65283Sbostic /* Read the configuration file. */ 115*65283Sbostic config(); 116*65283Sbostic 117*65283Sbostic /* If there's no _default list, create an empty one. */ 118*65283Sbostic if ((defp = getlist("_default")) == NULL) 119*65283Sbostic defp = addlist("_default"); 120*65283Sbostic 121*65283Sbostic /* Get the machine type. */ 122*65283Sbostic if ((machine = getenv("MACHINE")) == NULL) 12331703Sbostic machine = MACHINE; 12440390Sbostic 125*65283Sbostic /* 126*65283Sbostic * 1: If the user specified a MANPATH variable, or set the -M 127*65283Sbostic * option, we replace the _default list with the user's list, 128*65283Sbostic * appending the entries in the _subdir list and the machine. 129*65283Sbostic */ 130*65283Sbostic if (p_path == NULL) 131*65283Sbostic p_path = getenv("MANPATH"); 132*65283Sbostic if (p_path != NULL) { 133*65283Sbostic while ((tp = defp->list.qe_next) != NULL) { 134*65283Sbostic free(tp->s); 135*65283Sbostic queue_remove(&defp->list, tp, ENTRY *, list); 136*65283Sbostic } 137*65283Sbostic for (p = strtok(p_path, ":"); 138*65283Sbostic p != NULL; p = strtok(NULL, ":")) { 139*65283Sbostic slashp = p[strlen(p) - 1] == '/' ? "" : "/"; 140*65283Sbostic subp = getlist("_subdir"); 141*65283Sbostic if (subp != NULL) 142*65283Sbostic subp = subp->list.qe_next; 143*65283Sbostic for (; subp != NULL; subp = subp->list.qe_next) { 144*65283Sbostic (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", 145*65283Sbostic p, slashp, subp->s, machine); 146*65283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 147*65283Sbostic (tp->s = strdup(buf)) == NULL) 148*65283Sbostic err(1, NULL); 149*65283Sbostic queue_enter_tail(&defp->list, 150*65283Sbostic tp, ENTRY *, list); 151*65283Sbostic } 152*65283Sbostic } 15342402Sbostic } 15440390Sbostic 155*65283Sbostic /* 156*65283Sbostic * 2: If the user did not specify MANPATH, -M or a section, rewrite 157*65283Sbostic * the _default list to include the _subdir list and the machine. 158*65283Sbostic */ 159*65283Sbostic if ((section = getlist(*argv)) != NULL) 160*65283Sbostic ++argv; 161*65283Sbostic if (p_path == NULL && section == NULL) { 162*65283Sbostic defnewp = addlist("_default_new"); 163*65283Sbostic if (defp->list.qe_next != NULL) 164*65283Sbostic defp = defp->list.qe_next; 165*65283Sbostic for (; defp != NULL; defp = defp->list.qe_next) { 166*65283Sbostic slashp = defp->s[strlen(defp->s) - 1] == '/' ? "" : "/"; 167*65283Sbostic subp = getlist("_subdir"); 168*65283Sbostic if (subp != NULL) 169*65283Sbostic subp = subp->list.qe_next; 170*65283Sbostic for (; subp != NULL; subp = subp->list.qe_next) { 171*65283Sbostic (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", 172*65283Sbostic defp->s, slashp, subp->s, machine); 173*65283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 174*65283Sbostic (tp->s = strdup(buf)) == NULL) 175*65283Sbostic err(1, NULL); 176*65283Sbostic queue_enter_tail(&defnewp->list, 177*65283Sbostic tp, ENTRY *, list); 178*65283Sbostic } 179*65283Sbostic } 180*65283Sbostic defp = getlist("_default"); 181*65283Sbostic while ((tp = defp->list.qe_next) != NULL) { 182*65283Sbostic free(tp->s); 183*65283Sbostic queue_remove(&defp->list, tp, ENTRY *, list); 184*65283Sbostic } 185*65283Sbostic free(defp->s); 186*65283Sbostic queue_remove(&defp->tags, defp, ENTRY *, tags); 187*65283Sbostic defnewp = getlist("_default_new"); 188*65283Sbostic free(defnewp->s); 189*65283Sbostic defnewp->s = "_default"; 190*65283Sbostic defp = defnewp; 191*65283Sbostic } 19244418Strent 193*65283Sbostic /* 194*65283Sbostic * 3: If the user set the -m option, insert the user's list before 195*65283Sbostic * whatever list we have, again appending the _subdir list and 196*65283Sbostic * the machine. 197*65283Sbostic */ 198*65283Sbostic if (p_add != NULL) 199*65283Sbostic for (p = strtok(p_add, ":"); p != NULL; p = strtok(NULL, ":")) { 200*65283Sbostic slashp = p[strlen(p) - 1] == '/' ? "" : "/"; 201*65283Sbostic subp = getlist("_subdir"); 202*65283Sbostic if (subp != NULL) 203*65283Sbostic subp = subp->list.qe_next; 204*65283Sbostic for (; subp != NULL; subp = subp->list.qe_next) { 205*65283Sbostic (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", 206*65283Sbostic p, slashp, subp->s, machine); 207*65283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 208*65283Sbostic (tp->s = strdup(buf)) == NULL) 209*65283Sbostic err(1, NULL); 210*65283Sbostic queue_enter_head(&defp->list, 211*65283Sbostic tp, ENTRY *, list); 212*65283Sbostic } 21344418Strent } 214*65283Sbostic 215*65283Sbostic /* 216*65283Sbostic * 4: If none of MANPATH, -M, or -m were specified, and a section was, 217*65283Sbostic * rewrite the section's paths (if they have a trailing slash) to 218*65283Sbostic * append the _subdir list and the machine. This then becomes the 219*65283Sbostic * _default list. 220*65283Sbostic */ 221*65283Sbostic if (p_path == NULL && p_add == NULL && section != NULL) { 222*65283Sbostic sectnewp = addlist("_section_new"); 223*65283Sbostic if ((sectp = section)->list.qe_next != NULL) 224*65283Sbostic sectp = sectp->list.qe_next; 225*65283Sbostic while (sectp != NULL) { 226*65283Sbostic if (sectp->s[strlen(sectp->s) - 1] != '/') { 227*65283Sbostic tp = sectp; 228*65283Sbostic sectp = sectp->list.qe_next; 229*65283Sbostic queue_remove(§ion->list, tp, ENTRY *, list); 230*65283Sbostic queue_enter_tail(§newp->list, 231*65283Sbostic tp, ENTRY *, list); 232*65283Sbostic continue; 233*65283Sbostic } 234*65283Sbostic subp = getlist("_subdir"); 235*65283Sbostic if (subp != NULL) 236*65283Sbostic subp = subp->list.qe_next; 237*65283Sbostic for (; subp != NULL; subp = subp->list.qe_next) { 238*65283Sbostic (void)snprintf(buf, sizeof(buf), 239*65283Sbostic "%s%s{/%s,}", sectp->s, subp->s, machine); 240*65283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 241*65283Sbostic (tp->s = strdup(buf)) == NULL) 242*65283Sbostic err(1, NULL); 243*65283Sbostic queue_enter_tail(§newp->list, 244*65283Sbostic tp, ENTRY *, list); 245*65283Sbostic } 246*65283Sbostic sectp = sectp->list.qe_next; 247*65283Sbostic } 248*65283Sbostic sectnewp->s = section->s; 249*65283Sbostic defp = sectnewp; 250*65283Sbostic queue_remove(§ion->tags, section, ENTRY *, tags); 25142402Sbostic } 25240390Sbostic 253*65283Sbostic /* 254*65283Sbostic * 5: Search for the files. Set up an interrupt handler, so the 255*65283Sbostic * temporary files go away. 256*65283Sbostic */ 257*65283Sbostic (void)signal(SIGINT, onsig); 258*65283Sbostic 259*65283Sbostic memset(&pg, 0, sizeof(pg)); 260*65283Sbostic for (found = 0; *argv; ++argv) 261*65283Sbostic if (manual(*argv, defp, &pg)) 262*65283Sbostic found = 1; 263*65283Sbostic 264*65283Sbostic /* 265*65283Sbostic * 7: If nothing found, we're done. 266*65283Sbostic */ 267*65283Sbostic if (!found) { 268*65283Sbostic cleanup(); 269*65283Sbostic exit (1); 27042402Sbostic } 27142402Sbostic 272*65283Sbostic /* 8: If it's simple, display it fast. */ 273*65283Sbostic if (f_cat) { 274*65283Sbostic found = 0; 275*65283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 276*65283Sbostic if (*ap == '\0') 277*65283Sbostic continue; 278*65283Sbostic cat(*ap); 279*65283Sbostic if (!f_all) { 280*65283Sbostic found = 1; 281*65283Sbostic break; 282*65283Sbostic } 283*65283Sbostic } 284*65283Sbostic if (!found) { 285*65283Sbostic if (intmpp != NULL) 286*65283Sbostic intmpp = intmpp->list.qe_next; 287*65283Sbostic for (; intmpp != NULL; intmpp = intmpp->list.qe_next) { 288*65283Sbostic cat(intmpp->s); 289*65283Sbostic if (!f_all) 290*65283Sbostic break; 291*65283Sbostic } 292*65283Sbostic } 293*65283Sbostic cleanup(); 294*65283Sbostic exit (0); 295*65283Sbostic } 296*65283Sbostic if (f_how) { 297*65283Sbostic found = 0; 298*65283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 299*65283Sbostic if (*ap == '\0') 300*65283Sbostic continue; 301*65283Sbostic how(*ap); 302*65283Sbostic if (!f_all) { 303*65283Sbostic found = 1; 304*65283Sbostic break; 305*65283Sbostic } 306*65283Sbostic } 307*65283Sbostic if (!found) { 308*65283Sbostic intmpp = getlist("_intmp"); 309*65283Sbostic if (intmpp != NULL) 310*65283Sbostic intmpp = intmpp->list.qe_next; 311*65283Sbostic for (; intmpp != NULL; intmpp = intmpp->list.qe_next) { 312*65283Sbostic how(intmpp->s); 313*65283Sbostic if (!f_all) 314*65283Sbostic break; 315*65283Sbostic } 316*65283Sbostic } 317*65283Sbostic cleanup(); 318*65283Sbostic exit (0); 319*65283Sbostic } 320*65283Sbostic if (f_where) { 321*65283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 322*65283Sbostic if (*ap == '\0') 323*65283Sbostic continue; 324*65283Sbostic (void)printf("%s\n", *ap); 325*65283Sbostic } 326*65283Sbostic intmpp = getlist("_intmp"); 327*65283Sbostic if (intmpp != NULL) 328*65283Sbostic intmpp = intmpp->list.qe_next; 329*65283Sbostic for (; intmpp != NULL; intmpp = intmpp->list.qe_next) 330*65283Sbostic (void)printf("%s\n", intmpp->s); 331*65283Sbostic cleanup(); 332*65283Sbostic exit (0); 333*65283Sbostic } 334*65283Sbostic 335*65283Sbostic /* 336*65283Sbostic * 9: We display things in a single command; build a list of things 337*65283Sbostic * to display. 338*65283Sbostic */ 339*65283Sbostic found = 0; 340*65283Sbostic for (ap = pg.gl_pathv, len = strlen(pager) + 1; *ap != NULL; ++ap) { 341*65283Sbostic if (**ap == '\0') 342*65283Sbostic continue; 343*65283Sbostic len += strlen(*ap) + 1; 344*65283Sbostic if (!f_all) { 345*65283Sbostic found = 1; 346*65283Sbostic break; 347*65283Sbostic } 348*65283Sbostic } 349*65283Sbostic if (!found) { 350*65283Sbostic intmpp = getlist("_intmp"); 351*65283Sbostic if (intmpp != NULL) 352*65283Sbostic intmpp = intmpp->list.qe_next; 353*65283Sbostic for (; intmpp != NULL; intmpp = intmpp->list.qe_next) { 354*65283Sbostic len += strlen(intmpp->s); 355*65283Sbostic if (!f_all) 356*65283Sbostic break; 357*65283Sbostic } 358*65283Sbostic } 359*65283Sbostic 360*65283Sbostic if ((cmd = malloc(len)) == NULL) { 361*65283Sbostic cleanup(); 362*65283Sbostic err(1, NULL); 363*65283Sbostic } 364*65283Sbostic p = cmd; 365*65283Sbostic len = strlen(pager); 366*65283Sbostic memmove(p, pager, len); 367*65283Sbostic p += len; 368*65283Sbostic *p++ = ' '; 369*65283Sbostic found = 0; 370*65283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 371*65283Sbostic if (**ap == '\0') 372*65283Sbostic continue; 373*65283Sbostic len = strlen(*ap); 374*65283Sbostic memmove(p, *ap, len); 375*65283Sbostic p += len; 376*65283Sbostic *p++ = ' '; 377*65283Sbostic if (!f_all) { 378*65283Sbostic found = 1; 379*65283Sbostic break; 380*65283Sbostic } 381*65283Sbostic } 382*65283Sbostic if (!found) { 383*65283Sbostic intmpp = getlist("_intmp"); 384*65283Sbostic if (intmpp != NULL) 385*65283Sbostic intmpp = intmpp->list.qe_next; 386*65283Sbostic for (; intmpp != NULL; intmpp = intmpp->list.qe_next) { 387*65283Sbostic len = strlen(intmpp->s); 388*65283Sbostic memmove(p, intmpp->s, len); 389*65283Sbostic p += len; 390*65283Sbostic *p++ = ' '; 391*65283Sbostic } 392*65283Sbostic } 393*65283Sbostic *p = '\0'; 394*65283Sbostic 395*65283Sbostic /* Use system(3) in case someone's pager is "pager arg1 arg2". */ 396*65283Sbostic (void)system(cmd); 397*65283Sbostic 398*65283Sbostic cleanup(); 39933354Sbostic exit(0); 40033354Sbostic } 40131703Sbostic 40240390Sbostic /* 40331778Sbostic * manual -- 404*65283Sbostic * Search the manuals for the pages. 40531778Sbostic */ 406*65283Sbostic static int 407*65283Sbostic manual(page, list, pg) 408*65283Sbostic char *page; 409*65283Sbostic ENTRY *list; 410*65283Sbostic glob_t *pg; 41131703Sbostic { 412*65283Sbostic ENTRY *listp, *missp, *sufp, *tp; 413*65283Sbostic int anyfound, cnt, found; 414*65283Sbostic char *p, buf[128]; 41531703Sbostic 416*65283Sbostic anyfound = 0; 417*65283Sbostic buf[0] = '*'; 418*65283Sbostic 419*65283Sbostic /* For each element in the list... */ 420*65283Sbostic if (list != NULL) 421*65283Sbostic list = list->list.qe_next; 422*65283Sbostic for (listp = list; listp != NULL; listp = listp->list.qe_next) { 423*65283Sbostic (void)snprintf(buf, sizeof(buf), "%s/%s.*", listp->s, page); 424*65283Sbostic if (glob(buf, 425*65283Sbostic GLOB_APPEND | GLOB_NOSORT | GLOB_BRACE, NULL, pg)) { 426*65283Sbostic cleanup(); 427*65283Sbostic err(1, "globbing"); 428*65283Sbostic } 429*65283Sbostic if (pg->gl_matchc == 0) 430*65283Sbostic continue; 431*65283Sbostic 432*65283Sbostic /* Find out if it's really a man page. */ 433*65283Sbostic for (cnt = 1; cnt <= pg->gl_matchc; ++cnt) { 434*65283Sbostic 435*65283Sbostic /* Try the _suffix key words first. */ 436*65283Sbostic sufp = getlist("_suffix"); 437*65283Sbostic if (sufp != NULL) 438*65283Sbostic sufp = sufp->list.qe_next; 439*65283Sbostic for (found = 0; 440*65283Sbostic sufp != NULL; sufp = sufp->list.qe_next) { 441*65283Sbostic (void)snprintf(buf, 442*65283Sbostic sizeof(buf), "*%s", sufp->s); 443*65283Sbostic if (!fnmatch(buf, 444*65283Sbostic pg->gl_pathv[pg->gl_pathc - cnt], 0)) { 445*65283Sbostic found = 1; 446*65283Sbostic break; 447*65283Sbostic } 448*65283Sbostic } 449*65283Sbostic if (found) { 450*65283Sbostic anyfound = 1; 451*65283Sbostic if (!f_all) 452*65283Sbostic break; 45342402Sbostic continue; 45463515Sbostic } 455*65283Sbostic 456*65283Sbostic /* Try the _build key words next. */ 457*65283Sbostic sufp = getlist("_build"); 458*65283Sbostic if (sufp != NULL) 459*65283Sbostic sufp = sufp->list.qe_next; 460*65283Sbostic for (found = 0; 461*65283Sbostic sufp != NULL; sufp = sufp->list.qe_next) { 462*65283Sbostic for (p = sufp->s; 463*65283Sbostic *p != '\0' && !isspace(*p); ++p); 464*65283Sbostic if (*p == '\0') 465*65283Sbostic continue; 466*65283Sbostic *p = '\0'; 467*65283Sbostic (void)snprintf(buf, 468*65283Sbostic sizeof(buf), "*%s", sufp->s); 469*65283Sbostic if (!fnmatch(buf, 470*65283Sbostic pg->gl_pathv[pg->gl_pathc - cnt], 0)) { 471*65283Sbostic if (!f_where) { 472*65283Sbostic build_page(p + 1, 473*65283Sbostic pg->gl_pathv[pg->gl_pathc - 474*65283Sbostic cnt]); 475*65283Sbostic pg->gl_pathv[pg->gl_pathc - 476*65283Sbostic cnt] = ""; 477*65283Sbostic } 478*65283Sbostic *p = ' '; 479*65283Sbostic found = 1; 480*65283Sbostic break; 481*65283Sbostic } 482*65283Sbostic *p = ' '; 483*65283Sbostic } 484*65283Sbostic if (found) { 485*65283Sbostic anyfound = 1; 486*65283Sbostic if (!f_all) 487*65283Sbostic break; 48842402Sbostic continue; 48963515Sbostic } 490*65283Sbostic 491*65283Sbostic /* It's not a man page, forget about it. */ 492*65283Sbostic pg->gl_pathv[pg->gl_pathc - cnt] = ""; 49342402Sbostic } 49442402Sbostic 495*65283Sbostic if (anyfound && !f_all) 496*65283Sbostic break; 49731703Sbostic } 498*65283Sbostic 499*65283Sbostic /* If not found, enter onto the missing list. */ 500*65283Sbostic if (!anyfound) { 501*65283Sbostic if ((missp = getlist("_missing")) == NULL) 502*65283Sbostic missp = addlist("_missing"); 503*65283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 504*65283Sbostic (tp->s = strdup(page)) == NULL) { 505*65283Sbostic cleanup(); 506*65283Sbostic err(1, NULL); 507*65283Sbostic } 508*65283Sbostic queue_enter_tail(&missp->list, tp, ENTRY *, list); 509*65283Sbostic } 510*65283Sbostic return (anyfound); 51131703Sbostic } 51231703Sbostic 513*65283Sbostic /* 514*65283Sbostic * build_page -- 515*65283Sbostic * Build a man page for display. 516*65283Sbostic */ 517*65283Sbostic static void 518*65283Sbostic build_page(fmt, path) 519*65283Sbostic char *fmt, *path; 520*65283Sbostic { 521*65283Sbostic static int warned; 522*65283Sbostic ENTRY *intmpp, *tp; 523*65283Sbostic int fd; 524*65283Sbostic char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[sizeof(_PATH_TMP)]; 525*65283Sbostic 526*65283Sbostic /* Let the user know this may take awhile. */ 527*65283Sbostic if (!warned) { 528*65283Sbostic warned = 1; 529*65283Sbostic warnx("Formatting manual page..."); 530*65283Sbostic } 531*65283Sbostic 532*65283Sbostic /* Add an "in tmp" list. */ 533*65283Sbostic if ((intmpp = getlist("_intmp")) == NULL) 534*65283Sbostic intmpp = addlist("_intmp"); 535*65283Sbostic 536*65283Sbostic /* Move to the printf(3) format string. */ 537*65283Sbostic for (; *fmt && isspace(*fmt); ++fmt); 538*65283Sbostic 539*65283Sbostic /* 540*65283Sbostic * Get a temporary file and build a version of the file to display. 541*65283Sbostic * Link the built file into the list. 542*65283Sbostic */ 543*65283Sbostic (void)strcpy(tpath, _PATH_TMP); 544*65283Sbostic if ((fd = mkstemp(tpath)) == -1) { 545*65283Sbostic cleanup(); 546*65283Sbostic err(1, "%s", tpath); 547*65283Sbostic } 548*65283Sbostic (void)snprintf(buf, sizeof(buf), "%s > %s", fmt, tpath); 549*65283Sbostic (void)snprintf(cmd, sizeof(cmd), buf, path); 550*65283Sbostic (void)system(cmd); 551*65283Sbostic (void)close(fd); 552*65283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 553*65283Sbostic (tp->s = strdup(tpath)) == NULL) { 554*65283Sbostic cleanup(); 555*65283Sbostic err(1, NULL); 556*65283Sbostic } 557*65283Sbostic queue_enter_tail(&intmpp->list, tp, ENTRY *, list); 558*65283Sbostic } 559*65283Sbostic 56031778Sbostic /* 56144938Sbostic * how -- 56244938Sbostic * display how information 56344938Sbostic */ 564*65283Sbostic static void 56544938Sbostic how(fname) 56644938Sbostic char *fname; 56744938Sbostic { 56844938Sbostic register FILE *fp; 56944938Sbostic 57044938Sbostic register int lcnt, print; 57144938Sbostic register char *p; 57244938Sbostic char buf[BUFSIZ]; 57344938Sbostic 57444938Sbostic if (!(fp = fopen(fname, "r"))) { 575*65283Sbostic cleanup(); 576*65283Sbostic err(1, "%s", fname); 57744938Sbostic } 57844938Sbostic #define S1 "SYNOPSIS" 57944938Sbostic #define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS" 58044938Sbostic #define D1 "DESCRIPTION" 58144938Sbostic #define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" 58244938Sbostic for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) { 58344938Sbostic if (!strncmp(buf, S1, sizeof(S1) - 1) || 58444938Sbostic !strncmp(buf, S2, sizeof(S2) - 1)) { 58544938Sbostic print = 1; 58644938Sbostic continue; 58744938Sbostic } else if (!strncmp(buf, D1, sizeof(D1) - 1) || 58844938Sbostic !strncmp(buf, D2, sizeof(D2) - 1)) 58944938Sbostic return; 59044938Sbostic if (!print) 59144938Sbostic continue; 59244938Sbostic if (*buf == '\n') 59344938Sbostic ++lcnt; 59444938Sbostic else { 59544938Sbostic for(; lcnt; --lcnt) 59644938Sbostic (void)putchar('\n'); 59744938Sbostic for (p = buf; isspace(*p); ++p); 59844938Sbostic (void)fputs(p, stdout); 59944938Sbostic } 60044938Sbostic } 60144938Sbostic (void)fclose(fp); 60244938Sbostic } 603*65283Sbostic 60444938Sbostic /* 60533809Sbostic * cat -- 60633809Sbostic * cat out the file 60731778Sbostic */ 608*65283Sbostic static void 60933809Sbostic cat(fname) 61033809Sbostic char *fname; 61131703Sbostic { 61233809Sbostic register int fd, n; 61333809Sbostic char buf[BUFSIZ]; 61431703Sbostic 61544938Sbostic if ((fd = open(fname, O_RDONLY, 0)) < 0) { 616*65283Sbostic cleanup(); 617*65283Sbostic err(1, "%s", fname); 61831703Sbostic } 61933809Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 620*65283Sbostic if (write(STDOUT_FILENO, buf, n) != n) { 621*65283Sbostic cleanup(); 622*65283Sbostic err(1, "write"); 62333809Sbostic } 62433809Sbostic if (n == -1) { 625*65283Sbostic cleanup(); 626*65283Sbostic err(1, "read"); 62733809Sbostic } 62833809Sbostic (void)close(fd); 62931703Sbostic } 63031703Sbostic 63131778Sbostic /* 63240390Sbostic * check_pager -- 63340390Sbostic * check the user supplied page information 63440390Sbostic */ 635*65283Sbostic static char * 63640390Sbostic check_pager(name) 63740390Sbostic char *name; 63840390Sbostic { 63940390Sbostic register char *p; 64042402Sbostic char *save; 64140390Sbostic 64240390Sbostic /* 64340390Sbostic * if the user uses "more", we make it "more -s"; watch out for 64440390Sbostic * PAGER = "mypager /usr/ucb/more" 64540390Sbostic */ 64640390Sbostic for (p = name; *p && !isspace(*p); ++p); 64740390Sbostic for (; p > name && *p != '/'; --p); 64840390Sbostic if (p != name) 64940390Sbostic ++p; 65040390Sbostic 65140390Sbostic /* make sure it's "more", not "morex" */ 65240390Sbostic if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 65340390Sbostic save = name; 65440390Sbostic /* allocate space to add the "-s" */ 65540390Sbostic if (!(name = 65640390Sbostic malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 657*65283Sbostic err(1, NULL); 65840390Sbostic (void)sprintf(name, "%s %s", save, "-s"); 65940390Sbostic } 66040390Sbostic return(name); 66140390Sbostic } 66240390Sbostic 66340390Sbostic /* 66434057Sbostic * jump -- 66534057Sbostic * strip out flag argument and jump 66634057Sbostic */ 667*65283Sbostic static void 66834057Sbostic jump(argv, flag, name) 669*65283Sbostic char **argv, *flag, *name; 67034057Sbostic { 671*65283Sbostic char **arg; 67234057Sbostic 67334057Sbostic argv[0] = name; 67434057Sbostic for (arg = argv + 1; *arg; ++arg) 67534057Sbostic if (!strcmp(*arg, flag)) 67634057Sbostic break; 67734057Sbostic for (; *arg; ++arg) 67834057Sbostic arg[0] = arg[1]; 67934057Sbostic execvp(name, argv); 68042402Sbostic (void)fprintf(stderr, "%s: Command not found.\n", name); 68134057Sbostic exit(1); 68234057Sbostic } 68334057Sbostic 684*65283Sbostic /* 685*65283Sbostic * onsig -- 686*65283Sbostic * If signaled, delete the temporary files. 687*65283Sbostic */ 688*65283Sbostic static void 689*65283Sbostic onsig(signo) 690*65283Sbostic int signo; 691*65283Sbostic { 692*65283Sbostic cleanup(); 693*65283Sbostic 694*65283Sbostic (void)signal(SIGINT, SIG_DFL); 695*65283Sbostic (void)kill(getpid(), SIGINT); 696*65283Sbostic } 697*65283Sbostic 69834057Sbostic /* 699*65283Sbostic * cleanup -- 700*65283Sbostic * Clean up temporary files, show any error messages. 701*65283Sbostic */ 702*65283Sbostic static void 703*65283Sbostic cleanup() 704*65283Sbostic { 705*65283Sbostic ENTRY *intmpp, *missp; 706*65283Sbostic int sverrno; 707*65283Sbostic 708*65283Sbostic sverrno = errno; 709*65283Sbostic 710*65283Sbostic missp = getlist("_missing"); 711*65283Sbostic if (missp != NULL) 712*65283Sbostic missp = missp->list.qe_next; 713*65283Sbostic if (missp != NULL) 714*65283Sbostic for (; missp != NULL; missp = missp->list.qe_next) 715*65283Sbostic warnx("no entry for %s in the manual.", missp->s); 716*65283Sbostic 717*65283Sbostic intmpp = getlist("_intmp"); 718*65283Sbostic if (intmpp != NULL) 719*65283Sbostic intmpp = intmpp->list.qe_next; 720*65283Sbostic for (; intmpp != NULL; intmpp = intmpp->list.qe_next) 721*65283Sbostic (void)unlink(intmpp->s); 722*65283Sbostic 723*65283Sbostic errno = sverrno; 724*65283Sbostic } 725*65283Sbostic 726*65283Sbostic /* 72734057Sbostic * usage -- 72840390Sbostic * print usage message and die 72934057Sbostic */ 730*65283Sbostic static void 73134057Sbostic usage() 73234057Sbostic { 73340390Sbostic (void)fprintf(stderr, 73440390Sbostic "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); 73534057Sbostic exit(1); 73634057Sbostic } 737