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*65289Sbostic static char sccsid[] = "@(#)man.c 8.9 (Berkeley) 01/02/94"; 1633054Sbostic #endif /* not lint */ 1731703Sbostic 1831703Sbostic #include <sys/param.h> 1965283Sbostic #include <sys/queue.h> 2063536Sbostic 2163536Sbostic #include <ctype.h> 2265283Sbostic #include <err.h> 2340390Sbostic #include <errno.h> 2463536Sbostic #include <fcntl.h> 2565283Sbostic #include <fnmatch.h> 2665283Sbostic #include <glob.h> 2765283Sbostic #include <signal.h> 2863536Sbostic #include <stdio.h> 2963536Sbostic #include <stdlib.h> 3040390Sbostic #include <string.h> 3163536Sbostic #include <unistd.h> 3263536Sbostic 3365283Sbostic #include "config.h" 3437892Sbostic #include "pathnames.h" 3531703Sbostic 3665283Sbostic int f_all, f_where; 3731703Sbostic 38*65289Sbostic static void build_page __P((char *, char **)); 3965283Sbostic static void cat __P((char *)); 4065283Sbostic static char *check_pager __P((char *)); 4165283Sbostic static void cleanup __P((void)); 4265283Sbostic static void how __P((char *)); 4365283Sbostic static void jump __P((char **, char *, char *)); 4465283Sbostic static int manual __P((char *, ENTRY *, glob_t *)); 4565283Sbostic static void onsig __P((int)); 4665283Sbostic static void usage __P((void)); 4734057Sbostic 4865283Sbostic int 4931703Sbostic main(argc, argv) 5033354Sbostic int argc; 5165283Sbostic char *argv[]; 5231703Sbostic { 5334057Sbostic extern char *optarg; 5434057Sbostic extern int optind; 55*65289Sbostic ENTRY *defp, *defnewp; 5665283Sbostic ENTRY *section, *sectp, *sectnewp, *subp, *tp; 5765283Sbostic glob_t pg; 5865283Sbostic size_t len; 5965283Sbostic int ch, f_cat, f_how, found; 6065283Sbostic char **ap, *cmd, *machine, *p, *p_add, *p_path, *pager, *slashp; 6165284Sbostic char *conffile, buf[MAXPATHLEN * 2]; 6231703Sbostic 6365284Sbostic conffile = NULL; 6465283Sbostic f_cat = f_how = 0; 6565284Sbostic while ((ch = getopt(argc, argv, "-aC:cfhkM:m:P:w")) != EOF) 6665283Sbostic switch (ch) { 6740390Sbostic case 'a': 6840390Sbostic f_all = 1; 6931703Sbostic break; 7065284Sbostic case 'C': 7165284Sbostic conffile = optarg; 7265284Sbostic break; 7340390Sbostic case 'c': 7465283Sbostic case '-': /* Deprecated. */ 7540390Sbostic f_cat = 1; 7640390Sbostic break; 7744938Sbostic case 'h': 7844938Sbostic f_how = 1; 7944938Sbostic break; 8040390Sbostic case 'm': 8165283Sbostic p_add = optarg; 8240390Sbostic break; 8331703Sbostic case 'M': 8465283Sbostic case 'P': /* Backward compatibility. */ 8540390Sbostic p_path = optarg; 8631703Sbostic break; 8742402Sbostic /* 8865283Sbostic * The -f and -k options are backward compatible, 8965283Sbostic * undocumented ways of calling whatis(1) and apropos(1). 9042402Sbostic */ 9131703Sbostic case 'f': 9234057Sbostic jump(argv, "-f", "whatis"); 9340390Sbostic /* NOTREACHED */ 9431703Sbostic case 'k': 9534057Sbostic jump(argv, "-k", "apropos"); 9640390Sbostic /* NOTREACHED */ 9732565Sbostic case 'w': 9840390Sbostic f_all = f_where = 1; 9932565Sbostic break; 10031703Sbostic case '?': 10131703Sbostic default: 10234057Sbostic usage(); 10331703Sbostic } 10465282Sbostic argc -= optind; 10534057Sbostic argv += optind; 10631703Sbostic 10734057Sbostic if (!*argv) 10834057Sbostic usage(); 10933354Sbostic 11044938Sbostic if (!f_cat && !f_how) 11131703Sbostic if (!isatty(1)) 11240390Sbostic f_cat = 1; 113*65289Sbostic else if ((pager = getenv("PAGER")) != NULL) 11440390Sbostic pager = check_pager(pager); 11531779Sbostic else 11637892Sbostic pager = _PATH_PAGER; 11740390Sbostic 11865283Sbostic /* Read the configuration file. */ 11965284Sbostic config(conffile); 12065283Sbostic 12165283Sbostic /* If there's no _default list, create an empty one. */ 12265283Sbostic if ((defp = getlist("_default")) == NULL) 12365283Sbostic defp = addlist("_default"); 12465283Sbostic 12565283Sbostic /* Get the machine type. */ 12665283Sbostic if ((machine = getenv("MACHINE")) == NULL) 12731703Sbostic machine = MACHINE; 12840390Sbostic 12965283Sbostic /* 13065283Sbostic * 1: If the user specified a MANPATH variable, or set the -M 13165283Sbostic * option, we replace the _default list with the user's list, 13265283Sbostic * appending the entries in the _subdir list and the machine. 13365283Sbostic */ 13465283Sbostic if (p_path == NULL) 13565283Sbostic p_path = getenv("MANPATH"); 13665283Sbostic if (p_path != NULL) { 13765283Sbostic while ((tp = defp->list.qe_next) != NULL) { 13865283Sbostic free(tp->s); 13965283Sbostic queue_remove(&defp->list, tp, ENTRY *, list); 14065283Sbostic } 14165283Sbostic for (p = strtok(p_path, ":"); 14265283Sbostic p != NULL; p = strtok(NULL, ":")) { 14365283Sbostic slashp = p[strlen(p) - 1] == '/' ? "" : "/"; 14465283Sbostic subp = getlist("_subdir"); 14565283Sbostic if (subp != NULL) 14665283Sbostic subp = subp->list.qe_next; 14765283Sbostic for (; subp != NULL; subp = subp->list.qe_next) { 14865283Sbostic (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", 14965283Sbostic p, slashp, subp->s, machine); 15065283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 15165283Sbostic (tp->s = strdup(buf)) == NULL) 15265283Sbostic err(1, NULL); 15365283Sbostic queue_enter_tail(&defp->list, 15465283Sbostic tp, ENTRY *, list); 15565283Sbostic } 15665283Sbostic } 15742402Sbostic } 15840390Sbostic 15965283Sbostic /* 16065283Sbostic * 2: If the user did not specify MANPATH, -M or a section, rewrite 16165283Sbostic * the _default list to include the _subdir list and the machine. 16265283Sbostic */ 16365283Sbostic if ((section = getlist(*argv)) != NULL) 16465283Sbostic ++argv; 16565283Sbostic if (p_path == NULL && section == NULL) { 16665283Sbostic defnewp = addlist("_default_new"); 16765283Sbostic if (defp->list.qe_next != NULL) 16865283Sbostic defp = defp->list.qe_next; 16965283Sbostic for (; defp != NULL; defp = defp->list.qe_next) { 17065283Sbostic slashp = defp->s[strlen(defp->s) - 1] == '/' ? "" : "/"; 17165283Sbostic subp = getlist("_subdir"); 17265283Sbostic if (subp != NULL) 17365283Sbostic subp = subp->list.qe_next; 17465283Sbostic for (; subp != NULL; subp = subp->list.qe_next) { 17565283Sbostic (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", 17665283Sbostic defp->s, slashp, subp->s, machine); 17765283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 17865283Sbostic (tp->s = strdup(buf)) == NULL) 17965283Sbostic err(1, NULL); 18065283Sbostic queue_enter_tail(&defnewp->list, 18165283Sbostic tp, ENTRY *, list); 18265283Sbostic } 18365283Sbostic } 18465283Sbostic defp = getlist("_default"); 18565283Sbostic while ((tp = defp->list.qe_next) != NULL) { 18665283Sbostic free(tp->s); 18765283Sbostic queue_remove(&defp->list, tp, ENTRY *, list); 18865283Sbostic } 18965283Sbostic free(defp->s); 19065283Sbostic queue_remove(&defp->tags, defp, ENTRY *, tags); 19165283Sbostic defnewp = getlist("_default_new"); 19265283Sbostic free(defnewp->s); 19365283Sbostic defnewp->s = "_default"; 19465283Sbostic defp = defnewp; 19565283Sbostic } 19644418Strent 19765283Sbostic /* 19865283Sbostic * 3: If the user set the -m option, insert the user's list before 19965283Sbostic * whatever list we have, again appending the _subdir list and 20065283Sbostic * the machine. 20165283Sbostic */ 20265283Sbostic if (p_add != NULL) 20365283Sbostic for (p = strtok(p_add, ":"); p != NULL; p = strtok(NULL, ":")) { 20465283Sbostic slashp = p[strlen(p) - 1] == '/' ? "" : "/"; 20565283Sbostic subp = getlist("_subdir"); 20665283Sbostic if (subp != NULL) 20765283Sbostic subp = subp->list.qe_next; 20865283Sbostic for (; subp != NULL; subp = subp->list.qe_next) { 20965283Sbostic (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", 21065283Sbostic p, slashp, subp->s, machine); 21165283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 21265283Sbostic (tp->s = strdup(buf)) == NULL) 21365283Sbostic err(1, NULL); 21465283Sbostic queue_enter_head(&defp->list, 21565283Sbostic tp, ENTRY *, list); 21665283Sbostic } 21744418Strent } 21865283Sbostic 21965283Sbostic /* 22065283Sbostic * 4: If none of MANPATH, -M, or -m were specified, and a section was, 22165283Sbostic * rewrite the section's paths (if they have a trailing slash) to 22265283Sbostic * append the _subdir list and the machine. This then becomes the 22365283Sbostic * _default list. 22465283Sbostic */ 22565283Sbostic if (p_path == NULL && p_add == NULL && section != NULL) { 22665283Sbostic sectnewp = addlist("_section_new"); 22765283Sbostic if ((sectp = section)->list.qe_next != NULL) 22865283Sbostic sectp = sectp->list.qe_next; 22965285Sbostic for (; sectp != NULL; sectp = sectp->list.qe_next) { 23065283Sbostic if (sectp->s[strlen(sectp->s) - 1] != '/') { 23165285Sbostic (void)snprintf(buf, sizeof(buf), 23265285Sbostic "%s{/%s,}", sectp->s, machine); 23365285Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 23465285Sbostic (tp->s = strdup(buf)) == NULL) 23565285Sbostic err(1, NULL); 23665283Sbostic queue_enter_tail(§newp->list, 23765283Sbostic tp, ENTRY *, list); 23865283Sbostic continue; 23965283Sbostic } 24065283Sbostic subp = getlist("_subdir"); 24165283Sbostic if (subp != NULL) 24265283Sbostic subp = subp->list.qe_next; 24365283Sbostic for (; subp != NULL; subp = subp->list.qe_next) { 24465283Sbostic (void)snprintf(buf, sizeof(buf), 24565283Sbostic "%s%s{/%s,}", sectp->s, subp->s, machine); 24665283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 24765283Sbostic (tp->s = strdup(buf)) == NULL) 24865283Sbostic err(1, NULL); 24965283Sbostic queue_enter_tail(§newp->list, 25065283Sbostic tp, ENTRY *, list); 25165283Sbostic } 25265283Sbostic } 25365283Sbostic sectnewp->s = section->s; 25465283Sbostic defp = sectnewp; 25565283Sbostic queue_remove(§ion->tags, section, ENTRY *, tags); 25642402Sbostic } 25740390Sbostic 25865283Sbostic /* 25965283Sbostic * 5: Search for the files. Set up an interrupt handler, so the 26065283Sbostic * temporary files go away. 26165283Sbostic */ 26265283Sbostic (void)signal(SIGINT, onsig); 26365283Sbostic 26465283Sbostic memset(&pg, 0, sizeof(pg)); 26565283Sbostic for (found = 0; *argv; ++argv) 26665283Sbostic if (manual(*argv, defp, &pg)) 26765283Sbostic found = 1; 26865283Sbostic 26965283Sbostic /* 27065283Sbostic * 7: If nothing found, we're done. 27165283Sbostic */ 27265283Sbostic if (!found) { 27365283Sbostic cleanup(); 27465283Sbostic exit (1); 27542402Sbostic } 27642402Sbostic 27765283Sbostic /* 8: If it's simple, display it fast. */ 27865283Sbostic if (f_cat) { 27965283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 28065287Sbostic if (**ap == '\0') 28165283Sbostic continue; 28265283Sbostic cat(*ap); 28365283Sbostic } 28465283Sbostic cleanup(); 28565283Sbostic exit (0); 28665283Sbostic } 28765283Sbostic if (f_how) { 28865283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 28965287Sbostic if (**ap == '\0') 29065283Sbostic continue; 29165283Sbostic how(*ap); 29265283Sbostic } 29365283Sbostic cleanup(); 29465283Sbostic exit (0); 29565283Sbostic } 29665283Sbostic if (f_where) { 29765283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 29865287Sbostic if (**ap == '\0') 29965283Sbostic continue; 30065283Sbostic (void)printf("%s\n", *ap); 30165283Sbostic } 30265283Sbostic cleanup(); 30365283Sbostic exit (0); 30465283Sbostic } 30565283Sbostic 30665283Sbostic /* 30765283Sbostic * 9: We display things in a single command; build a list of things 30865283Sbostic * to display. 30965283Sbostic */ 31065283Sbostic for (ap = pg.gl_pathv, len = strlen(pager) + 1; *ap != NULL; ++ap) { 31165283Sbostic if (**ap == '\0') 31265283Sbostic continue; 31365283Sbostic len += strlen(*ap) + 1; 31465283Sbostic } 31565283Sbostic if ((cmd = malloc(len)) == NULL) { 31665283Sbostic cleanup(); 31765283Sbostic err(1, NULL); 31865283Sbostic } 31965283Sbostic p = cmd; 32065283Sbostic len = strlen(pager); 32165283Sbostic memmove(p, pager, len); 32265283Sbostic p += len; 32365283Sbostic *p++ = ' '; 32465283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 32565283Sbostic if (**ap == '\0') 32665283Sbostic continue; 32765283Sbostic len = strlen(*ap); 32865283Sbostic memmove(p, *ap, len); 32965283Sbostic p += len; 33065283Sbostic *p++ = ' '; 33165283Sbostic } 33265283Sbostic *p = '\0'; 33365283Sbostic 33465283Sbostic /* Use system(3) in case someone's pager is "pager arg1 arg2". */ 33565283Sbostic (void)system(cmd); 33665283Sbostic 33765283Sbostic cleanup(); 33833354Sbostic exit(0); 33933354Sbostic } 34031703Sbostic 34140390Sbostic /* 34231778Sbostic * manual -- 34365283Sbostic * Search the manuals for the pages. 34431778Sbostic */ 34565283Sbostic static int 34665283Sbostic manual(page, list, pg) 34765283Sbostic char *page; 34865283Sbostic ENTRY *list; 34965283Sbostic glob_t *pg; 35031703Sbostic { 35165283Sbostic ENTRY *listp, *missp, *sufp, *tp; 35265283Sbostic int anyfound, cnt, found; 35365283Sbostic char *p, buf[128]; 35431703Sbostic 35565283Sbostic anyfound = 0; 35665283Sbostic buf[0] = '*'; 35765283Sbostic 35865283Sbostic /* For each element in the list... */ 35965283Sbostic if (list != NULL) 36065283Sbostic list = list->list.qe_next; 36165283Sbostic for (listp = list; listp != NULL; listp = listp->list.qe_next) { 36265283Sbostic (void)snprintf(buf, sizeof(buf), "%s/%s.*", listp->s, page); 36365283Sbostic if (glob(buf, 36465286Sbostic GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT | GLOB_QUOTE, 36565286Sbostic NULL, pg)) { 36665283Sbostic cleanup(); 36765283Sbostic err(1, "globbing"); 36865283Sbostic } 36965283Sbostic if (pg->gl_matchc == 0) 37065283Sbostic continue; 37165283Sbostic 37265283Sbostic /* Find out if it's really a man page. */ 37365287Sbostic for (cnt = pg->gl_pathc - pg->gl_matchc; 37465287Sbostic cnt < pg->gl_pathc; ++cnt) { 37565283Sbostic 37665285Sbostic /* 37765285Sbostic * Try the _suffix key words first. 37865285Sbostic * 37965285Sbostic * XXX 38065285Sbostic * Older versions of man.conf didn't have the suffix 38165285Sbostic * key words, it was assumed that everything was a .0. 38265285Sbostic * We just test for .0 first, it's fast and probably 38365285Sbostic * going to hit. 38465285Sbostic */ 38565287Sbostic (void)snprintf(buf, sizeof(buf), "*/%s.0", page); 38665287Sbostic if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) 38765285Sbostic goto easy; 38865285Sbostic 38965283Sbostic sufp = getlist("_suffix"); 39065283Sbostic if (sufp != NULL) 39165283Sbostic sufp = sufp->list.qe_next; 39265283Sbostic for (found = 0; 39365283Sbostic sufp != NULL; sufp = sufp->list.qe_next) { 39465283Sbostic (void)snprintf(buf, 39565287Sbostic sizeof(buf), "*/%s%s", page, sufp->s); 39665287Sbostic if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { 39765283Sbostic found = 1; 39865283Sbostic break; 39965283Sbostic } 40065283Sbostic } 40165283Sbostic if (found) { 40265285Sbostic easy: anyfound = 1; 40365283Sbostic if (!f_all) 40465283Sbostic break; 40542402Sbostic continue; 40663515Sbostic } 40765283Sbostic 40865283Sbostic /* Try the _build key words next. */ 40965283Sbostic sufp = getlist("_build"); 41065283Sbostic if (sufp != NULL) 41165283Sbostic sufp = sufp->list.qe_next; 41265283Sbostic for (found = 0; 41365283Sbostic sufp != NULL; sufp = sufp->list.qe_next) { 41465283Sbostic for (p = sufp->s; 41565283Sbostic *p != '\0' && !isspace(*p); ++p); 41665283Sbostic if (*p == '\0') 41765283Sbostic continue; 41865283Sbostic *p = '\0'; 41965283Sbostic (void)snprintf(buf, 42065287Sbostic sizeof(buf), "*/%s%s", page, sufp->s); 42165287Sbostic if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { 422*65289Sbostic if (!f_where) 42365283Sbostic build_page(p + 1, 424*65289Sbostic &pg->gl_pathv[cnt]); 42565283Sbostic *p = ' '; 42665283Sbostic found = 1; 42765283Sbostic break; 42865283Sbostic } 42965283Sbostic *p = ' '; 43065283Sbostic } 43165283Sbostic if (found) { 43265283Sbostic anyfound = 1; 43365283Sbostic if (!f_all) 43465283Sbostic break; 43542402Sbostic continue; 43663515Sbostic } 43765283Sbostic 43865283Sbostic /* It's not a man page, forget about it. */ 43965287Sbostic pg->gl_pathv[cnt] = ""; 44042402Sbostic } 44142402Sbostic 44265283Sbostic if (anyfound && !f_all) 44365283Sbostic break; 44431703Sbostic } 44565283Sbostic 44665283Sbostic /* If not found, enter onto the missing list. */ 44765283Sbostic if (!anyfound) { 44865283Sbostic if ((missp = getlist("_missing")) == NULL) 44965283Sbostic missp = addlist("_missing"); 45065283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 45165283Sbostic (tp->s = strdup(page)) == NULL) { 45265283Sbostic cleanup(); 45365283Sbostic err(1, NULL); 45465283Sbostic } 45565283Sbostic queue_enter_tail(&missp->list, tp, ENTRY *, list); 45665283Sbostic } 45765283Sbostic return (anyfound); 45831703Sbostic } 45931703Sbostic 46065283Sbostic /* 46165283Sbostic * build_page -- 46265283Sbostic * Build a man page for display. 46365283Sbostic */ 46465283Sbostic static void 465*65289Sbostic build_page(fmt, pathp) 466*65289Sbostic char *fmt, **pathp; 46765283Sbostic { 46865283Sbostic static int warned; 46965283Sbostic ENTRY *intmpp, *tp; 47065283Sbostic int fd; 47165283Sbostic char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[sizeof(_PATH_TMP)]; 47265283Sbostic 47365283Sbostic /* Let the user know this may take awhile. */ 47465283Sbostic if (!warned) { 47565283Sbostic warned = 1; 47665283Sbostic warnx("Formatting manual page..."); 47765283Sbostic } 47865283Sbostic 479*65289Sbostic /* Add a remove-when-done list. */ 48065283Sbostic if ((intmpp = getlist("_intmp")) == NULL) 48165283Sbostic intmpp = addlist("_intmp"); 48265283Sbostic 48365283Sbostic /* Move to the printf(3) format string. */ 48465283Sbostic for (; *fmt && isspace(*fmt); ++fmt); 48565283Sbostic 48665283Sbostic /* 487*65289Sbostic * Get a temporary file and build a version of the file 488*65289Sbostic * to display. Replace the old file name with the new one. 48965283Sbostic */ 49065283Sbostic (void)strcpy(tpath, _PATH_TMP); 49165283Sbostic if ((fd = mkstemp(tpath)) == -1) { 49265283Sbostic cleanup(); 49365283Sbostic err(1, "%s", tpath); 49465283Sbostic } 49565283Sbostic (void)snprintf(buf, sizeof(buf), "%s > %s", fmt, tpath); 496*65289Sbostic (void)snprintf(cmd, sizeof(cmd), buf, *pathp); 49765283Sbostic (void)system(cmd); 49865283Sbostic (void)close(fd); 499*65289Sbostic if ((*pathp = strdup(tpath)) == NULL) { 50065283Sbostic cleanup(); 50165283Sbostic err(1, NULL); 50265283Sbostic } 503*65289Sbostic 504*65289Sbostic /* Link the built file into the remove-when-done list. */ 505*65289Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL) { 506*65289Sbostic cleanup(); 507*65289Sbostic err(1, NULL); 508*65289Sbostic } 509*65289Sbostic tp->s = *pathp; 51065283Sbostic queue_enter_tail(&intmpp->list, tp, ENTRY *, list); 51165283Sbostic } 51265283Sbostic 51331778Sbostic /* 51444938Sbostic * how -- 51544938Sbostic * display how information 51644938Sbostic */ 51765283Sbostic static void 51844938Sbostic how(fname) 51944938Sbostic char *fname; 52044938Sbostic { 52144938Sbostic register FILE *fp; 52244938Sbostic 52344938Sbostic register int lcnt, print; 52444938Sbostic register char *p; 52544938Sbostic char buf[BUFSIZ]; 52644938Sbostic 52744938Sbostic if (!(fp = fopen(fname, "r"))) { 52865283Sbostic cleanup(); 52965283Sbostic err(1, "%s", fname); 53044938Sbostic } 53144938Sbostic #define S1 "SYNOPSIS" 53244938Sbostic #define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS" 53344938Sbostic #define D1 "DESCRIPTION" 53444938Sbostic #define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" 53544938Sbostic for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) { 53644938Sbostic if (!strncmp(buf, S1, sizeof(S1) - 1) || 53744938Sbostic !strncmp(buf, S2, sizeof(S2) - 1)) { 53844938Sbostic print = 1; 53944938Sbostic continue; 54044938Sbostic } else if (!strncmp(buf, D1, sizeof(D1) - 1) || 54144938Sbostic !strncmp(buf, D2, sizeof(D2) - 1)) 54244938Sbostic return; 54344938Sbostic if (!print) 54444938Sbostic continue; 54544938Sbostic if (*buf == '\n') 54644938Sbostic ++lcnt; 54744938Sbostic else { 54844938Sbostic for(; lcnt; --lcnt) 54944938Sbostic (void)putchar('\n'); 55044938Sbostic for (p = buf; isspace(*p); ++p); 55144938Sbostic (void)fputs(p, stdout); 55244938Sbostic } 55344938Sbostic } 55444938Sbostic (void)fclose(fp); 55544938Sbostic } 55665283Sbostic 55744938Sbostic /* 55833809Sbostic * cat -- 55933809Sbostic * cat out the file 56031778Sbostic */ 56165283Sbostic static void 56233809Sbostic cat(fname) 56333809Sbostic char *fname; 56431703Sbostic { 56533809Sbostic register int fd, n; 56633809Sbostic char buf[BUFSIZ]; 56731703Sbostic 56844938Sbostic if ((fd = open(fname, O_RDONLY, 0)) < 0) { 56965283Sbostic cleanup(); 57065283Sbostic err(1, "%s", fname); 57131703Sbostic } 57233809Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 57365283Sbostic if (write(STDOUT_FILENO, buf, n) != n) { 57465283Sbostic cleanup(); 57565283Sbostic err(1, "write"); 57633809Sbostic } 57733809Sbostic if (n == -1) { 57865283Sbostic cleanup(); 57965283Sbostic err(1, "read"); 58033809Sbostic } 58133809Sbostic (void)close(fd); 58231703Sbostic } 58331703Sbostic 58431778Sbostic /* 58540390Sbostic * check_pager -- 58640390Sbostic * check the user supplied page information 58740390Sbostic */ 58865283Sbostic static char * 58940390Sbostic check_pager(name) 59040390Sbostic char *name; 59140390Sbostic { 59240390Sbostic register char *p; 59342402Sbostic char *save; 59440390Sbostic 59540390Sbostic /* 59640390Sbostic * if the user uses "more", we make it "more -s"; watch out for 59740390Sbostic * PAGER = "mypager /usr/ucb/more" 59840390Sbostic */ 59940390Sbostic for (p = name; *p && !isspace(*p); ++p); 60040390Sbostic for (; p > name && *p != '/'; --p); 60140390Sbostic if (p != name) 60240390Sbostic ++p; 60340390Sbostic 60440390Sbostic /* make sure it's "more", not "morex" */ 60540390Sbostic if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 60640390Sbostic save = name; 60740390Sbostic /* allocate space to add the "-s" */ 60840390Sbostic if (!(name = 60940390Sbostic malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 61065283Sbostic err(1, NULL); 61140390Sbostic (void)sprintf(name, "%s %s", save, "-s"); 61240390Sbostic } 61340390Sbostic return(name); 61440390Sbostic } 61540390Sbostic 61640390Sbostic /* 61734057Sbostic * jump -- 61834057Sbostic * strip out flag argument and jump 61934057Sbostic */ 62065283Sbostic static void 62134057Sbostic jump(argv, flag, name) 62265283Sbostic char **argv, *flag, *name; 62334057Sbostic { 62465283Sbostic char **arg; 62534057Sbostic 62634057Sbostic argv[0] = name; 62734057Sbostic for (arg = argv + 1; *arg; ++arg) 62834057Sbostic if (!strcmp(*arg, flag)) 62934057Sbostic break; 63034057Sbostic for (; *arg; ++arg) 63134057Sbostic arg[0] = arg[1]; 63234057Sbostic execvp(name, argv); 63342402Sbostic (void)fprintf(stderr, "%s: Command not found.\n", name); 63434057Sbostic exit(1); 63534057Sbostic } 63634057Sbostic 63765283Sbostic /* 63865283Sbostic * onsig -- 63965283Sbostic * If signaled, delete the temporary files. 64065283Sbostic */ 64165283Sbostic static void 64265283Sbostic onsig(signo) 64365283Sbostic int signo; 64465283Sbostic { 64565283Sbostic cleanup(); 64665283Sbostic 64765283Sbostic (void)signal(SIGINT, SIG_DFL); 64865283Sbostic (void)kill(getpid(), SIGINT); 64965283Sbostic } 65065283Sbostic 65134057Sbostic /* 65265283Sbostic * cleanup -- 65365283Sbostic * Clean up temporary files, show any error messages. 65465283Sbostic */ 65565283Sbostic static void 65665283Sbostic cleanup() 65765283Sbostic { 65865283Sbostic ENTRY *intmpp, *missp; 65965283Sbostic int sverrno; 66065283Sbostic 66165283Sbostic sverrno = errno; 66265283Sbostic 66365283Sbostic missp = getlist("_missing"); 66465283Sbostic if (missp != NULL) 66565283Sbostic missp = missp->list.qe_next; 66665283Sbostic if (missp != NULL) 66765283Sbostic for (; missp != NULL; missp = missp->list.qe_next) 66865283Sbostic warnx("no entry for %s in the manual.", missp->s); 66965283Sbostic 67065283Sbostic intmpp = getlist("_intmp"); 67165283Sbostic if (intmpp != NULL) 67265283Sbostic intmpp = intmpp->list.qe_next; 67365283Sbostic for (; intmpp != NULL; intmpp = intmpp->list.qe_next) 67465283Sbostic (void)unlink(intmpp->s); 67565283Sbostic 67665283Sbostic errno = sverrno; 67765283Sbostic } 67865283Sbostic 67965283Sbostic /* 68034057Sbostic * usage -- 68140390Sbostic * print usage message and die 68234057Sbostic */ 68365283Sbostic static void 68434057Sbostic usage() 68534057Sbostic { 68640390Sbostic (void)fprintf(stderr, 68765284Sbostic "usage: man [-ac] [-C file] [-M path] [-m path] [section] title ...\n"); 68834057Sbostic exit(1); 68934057Sbostic } 690