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*65290Sbostic static char sccsid[] = "@(#)man.c 8.10 (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 3865289Sbostic 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; 5565289Sbostic 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; 11365289Sbostic 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 269*65290Sbostic /* 6: If nothing found, we're done. */ 27065283Sbostic if (!found) { 27165283Sbostic cleanup(); 27265283Sbostic exit (1); 27342402Sbostic } 27442402Sbostic 275*65290Sbostic /* 7: If it's simple, display it fast. */ 27665283Sbostic if (f_cat) { 27765283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 27865287Sbostic if (**ap == '\0') 27965283Sbostic continue; 28065283Sbostic cat(*ap); 28165283Sbostic } 28265283Sbostic cleanup(); 28365283Sbostic exit (0); 28465283Sbostic } 28565283Sbostic if (f_how) { 28665283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 28765287Sbostic if (**ap == '\0') 28865283Sbostic continue; 28965283Sbostic how(*ap); 29065283Sbostic } 29165283Sbostic cleanup(); 29265283Sbostic exit (0); 29365283Sbostic } 29465283Sbostic if (f_where) { 29565283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 29665287Sbostic if (**ap == '\0') 29765283Sbostic continue; 29865283Sbostic (void)printf("%s\n", *ap); 29965283Sbostic } 30065283Sbostic cleanup(); 30165283Sbostic exit (0); 30265283Sbostic } 30365283Sbostic 30465283Sbostic /* 305*65290Sbostic * 8: We display things in a single command; build a list of things 30665283Sbostic * to display. 30765283Sbostic */ 30865283Sbostic for (ap = pg.gl_pathv, len = strlen(pager) + 1; *ap != NULL; ++ap) { 30965283Sbostic if (**ap == '\0') 31065283Sbostic continue; 31165283Sbostic len += strlen(*ap) + 1; 31265283Sbostic } 31365283Sbostic if ((cmd = malloc(len)) == NULL) { 31465283Sbostic cleanup(); 31565283Sbostic err(1, NULL); 31665283Sbostic } 31765283Sbostic p = cmd; 31865283Sbostic len = strlen(pager); 31965283Sbostic memmove(p, pager, len); 32065283Sbostic p += len; 32165283Sbostic *p++ = ' '; 32265283Sbostic for (ap = pg.gl_pathv; *ap != NULL; ++ap) { 32365283Sbostic if (**ap == '\0') 32465283Sbostic continue; 32565283Sbostic len = strlen(*ap); 32665283Sbostic memmove(p, *ap, len); 32765283Sbostic p += len; 32865283Sbostic *p++ = ' '; 32965283Sbostic } 33065283Sbostic *p = '\0'; 33165283Sbostic 33265283Sbostic /* Use system(3) in case someone's pager is "pager arg1 arg2". */ 33365283Sbostic (void)system(cmd); 33465283Sbostic 33565283Sbostic cleanup(); 33633354Sbostic exit(0); 33733354Sbostic } 33831703Sbostic 33940390Sbostic /* 34031778Sbostic * manual -- 34165283Sbostic * Search the manuals for the pages. 34231778Sbostic */ 34365283Sbostic static int 34465283Sbostic manual(page, list, pg) 34565283Sbostic char *page; 34665283Sbostic ENTRY *list; 34765283Sbostic glob_t *pg; 34831703Sbostic { 34965283Sbostic ENTRY *listp, *missp, *sufp, *tp; 35065283Sbostic int anyfound, cnt, found; 35165283Sbostic char *p, buf[128]; 35231703Sbostic 35365283Sbostic anyfound = 0; 35465283Sbostic buf[0] = '*'; 35565283Sbostic 35665283Sbostic /* For each element in the list... */ 35765283Sbostic if (list != NULL) 35865283Sbostic list = list->list.qe_next; 35965283Sbostic for (listp = list; listp != NULL; listp = listp->list.qe_next) { 36065283Sbostic (void)snprintf(buf, sizeof(buf), "%s/%s.*", listp->s, page); 36165283Sbostic if (glob(buf, 36265286Sbostic GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT | GLOB_QUOTE, 36365286Sbostic NULL, pg)) { 36465283Sbostic cleanup(); 36565283Sbostic err(1, "globbing"); 36665283Sbostic } 36765283Sbostic if (pg->gl_matchc == 0) 36865283Sbostic continue; 36965283Sbostic 37065283Sbostic /* Find out if it's really a man page. */ 37165287Sbostic for (cnt = pg->gl_pathc - pg->gl_matchc; 37265287Sbostic cnt < pg->gl_pathc; ++cnt) { 37365283Sbostic 37465285Sbostic /* 37565285Sbostic * Try the _suffix key words first. 37665285Sbostic * 37765285Sbostic * XXX 37865285Sbostic * Older versions of man.conf didn't have the suffix 37965285Sbostic * key words, it was assumed that everything was a .0. 38065285Sbostic * We just test for .0 first, it's fast and probably 38165285Sbostic * going to hit. 38265285Sbostic */ 38365287Sbostic (void)snprintf(buf, sizeof(buf), "*/%s.0", page); 38465287Sbostic if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) 38565285Sbostic goto easy; 38665285Sbostic 38765283Sbostic sufp = getlist("_suffix"); 38865283Sbostic if (sufp != NULL) 38965283Sbostic sufp = sufp->list.qe_next; 39065283Sbostic for (found = 0; 39165283Sbostic sufp != NULL; sufp = sufp->list.qe_next) { 39265283Sbostic (void)snprintf(buf, 39365287Sbostic sizeof(buf), "*/%s%s", page, sufp->s); 39465287Sbostic if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { 39565283Sbostic found = 1; 39665283Sbostic break; 39765283Sbostic } 39865283Sbostic } 39965283Sbostic if (found) { 40065285Sbostic easy: anyfound = 1; 40165283Sbostic if (!f_all) 40265283Sbostic break; 40342402Sbostic continue; 40463515Sbostic } 40565283Sbostic 40665283Sbostic /* Try the _build key words next. */ 40765283Sbostic sufp = getlist("_build"); 40865283Sbostic if (sufp != NULL) 40965283Sbostic sufp = sufp->list.qe_next; 41065283Sbostic for (found = 0; 41165283Sbostic sufp != NULL; sufp = sufp->list.qe_next) { 41265283Sbostic for (p = sufp->s; 41365283Sbostic *p != '\0' && !isspace(*p); ++p); 41465283Sbostic if (*p == '\0') 41565283Sbostic continue; 41665283Sbostic *p = '\0'; 41765283Sbostic (void)snprintf(buf, 41865287Sbostic sizeof(buf), "*/%s%s", page, sufp->s); 41965287Sbostic if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { 42065289Sbostic if (!f_where) 42165283Sbostic build_page(p + 1, 42265289Sbostic &pg->gl_pathv[cnt]); 42365283Sbostic *p = ' '; 42465283Sbostic found = 1; 42565283Sbostic break; 42665283Sbostic } 42765283Sbostic *p = ' '; 42865283Sbostic } 42965283Sbostic if (found) { 43065283Sbostic anyfound = 1; 43165283Sbostic if (!f_all) 43265283Sbostic break; 43342402Sbostic continue; 43463515Sbostic } 43565283Sbostic 43665283Sbostic /* It's not a man page, forget about it. */ 43765287Sbostic pg->gl_pathv[cnt] = ""; 43842402Sbostic } 43942402Sbostic 44065283Sbostic if (anyfound && !f_all) 44165283Sbostic break; 44231703Sbostic } 44365283Sbostic 44465283Sbostic /* If not found, enter onto the missing list. */ 44565283Sbostic if (!anyfound) { 44665283Sbostic if ((missp = getlist("_missing")) == NULL) 44765283Sbostic missp = addlist("_missing"); 44865283Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL || 44965283Sbostic (tp->s = strdup(page)) == NULL) { 45065283Sbostic cleanup(); 45165283Sbostic err(1, NULL); 45265283Sbostic } 45365283Sbostic queue_enter_tail(&missp->list, tp, ENTRY *, list); 45465283Sbostic } 45565283Sbostic return (anyfound); 45631703Sbostic } 45731703Sbostic 45865283Sbostic /* 45965283Sbostic * build_page -- 46065283Sbostic * Build a man page for display. 46165283Sbostic */ 46265283Sbostic static void 46365289Sbostic build_page(fmt, pathp) 46465289Sbostic char *fmt, **pathp; 46565283Sbostic { 46665283Sbostic static int warned; 46765283Sbostic ENTRY *intmpp, *tp; 46865283Sbostic int fd; 46965283Sbostic char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[sizeof(_PATH_TMP)]; 47065283Sbostic 47165283Sbostic /* Let the user know this may take awhile. */ 47265283Sbostic if (!warned) { 47365283Sbostic warned = 1; 47465283Sbostic warnx("Formatting manual page..."); 47565283Sbostic } 47665283Sbostic 47765289Sbostic /* Add a remove-when-done list. */ 47865283Sbostic if ((intmpp = getlist("_intmp")) == NULL) 47965283Sbostic intmpp = addlist("_intmp"); 48065283Sbostic 48165283Sbostic /* Move to the printf(3) format string. */ 48265283Sbostic for (; *fmt && isspace(*fmt); ++fmt); 48365283Sbostic 48465283Sbostic /* 48565289Sbostic * Get a temporary file and build a version of the file 48665289Sbostic * to display. Replace the old file name with the new one. 48765283Sbostic */ 48865283Sbostic (void)strcpy(tpath, _PATH_TMP); 48965283Sbostic if ((fd = mkstemp(tpath)) == -1) { 49065283Sbostic cleanup(); 49165283Sbostic err(1, "%s", tpath); 49265283Sbostic } 49365283Sbostic (void)snprintf(buf, sizeof(buf), "%s > %s", fmt, tpath); 49465289Sbostic (void)snprintf(cmd, sizeof(cmd), buf, *pathp); 49565283Sbostic (void)system(cmd); 49665283Sbostic (void)close(fd); 49765289Sbostic if ((*pathp = strdup(tpath)) == NULL) { 49865283Sbostic cleanup(); 49965283Sbostic err(1, NULL); 50065283Sbostic } 50165289Sbostic 50265289Sbostic /* Link the built file into the remove-when-done list. */ 50365289Sbostic if ((tp = malloc(sizeof(ENTRY))) == NULL) { 50465289Sbostic cleanup(); 50565289Sbostic err(1, NULL); 50665289Sbostic } 50765289Sbostic tp->s = *pathp; 50865283Sbostic queue_enter_tail(&intmpp->list, tp, ENTRY *, list); 50965283Sbostic } 51065283Sbostic 51131778Sbostic /* 51244938Sbostic * how -- 51344938Sbostic * display how information 51444938Sbostic */ 51565283Sbostic static void 51644938Sbostic how(fname) 51744938Sbostic char *fname; 51844938Sbostic { 51944938Sbostic register FILE *fp; 52044938Sbostic 52144938Sbostic register int lcnt, print; 52244938Sbostic register char *p; 52344938Sbostic char buf[BUFSIZ]; 52444938Sbostic 52544938Sbostic if (!(fp = fopen(fname, "r"))) { 52665283Sbostic cleanup(); 52765283Sbostic err(1, "%s", fname); 52844938Sbostic } 52944938Sbostic #define S1 "SYNOPSIS" 53044938Sbostic #define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS" 53144938Sbostic #define D1 "DESCRIPTION" 53244938Sbostic #define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" 53344938Sbostic for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) { 53444938Sbostic if (!strncmp(buf, S1, sizeof(S1) - 1) || 53544938Sbostic !strncmp(buf, S2, sizeof(S2) - 1)) { 53644938Sbostic print = 1; 53744938Sbostic continue; 53844938Sbostic } else if (!strncmp(buf, D1, sizeof(D1) - 1) || 53944938Sbostic !strncmp(buf, D2, sizeof(D2) - 1)) 54044938Sbostic return; 54144938Sbostic if (!print) 54244938Sbostic continue; 54344938Sbostic if (*buf == '\n') 54444938Sbostic ++lcnt; 54544938Sbostic else { 54644938Sbostic for(; lcnt; --lcnt) 54744938Sbostic (void)putchar('\n'); 54844938Sbostic for (p = buf; isspace(*p); ++p); 54944938Sbostic (void)fputs(p, stdout); 55044938Sbostic } 55144938Sbostic } 55244938Sbostic (void)fclose(fp); 55344938Sbostic } 55465283Sbostic 55544938Sbostic /* 55633809Sbostic * cat -- 55733809Sbostic * cat out the file 55831778Sbostic */ 55965283Sbostic static void 56033809Sbostic cat(fname) 56133809Sbostic char *fname; 56231703Sbostic { 56333809Sbostic register int fd, n; 56433809Sbostic char buf[BUFSIZ]; 56531703Sbostic 56644938Sbostic if ((fd = open(fname, O_RDONLY, 0)) < 0) { 56765283Sbostic cleanup(); 56865283Sbostic err(1, "%s", fname); 56931703Sbostic } 57033809Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 57165283Sbostic if (write(STDOUT_FILENO, buf, n) != n) { 57265283Sbostic cleanup(); 57365283Sbostic err(1, "write"); 57433809Sbostic } 57533809Sbostic if (n == -1) { 57665283Sbostic cleanup(); 57765283Sbostic err(1, "read"); 57833809Sbostic } 57933809Sbostic (void)close(fd); 58031703Sbostic } 58131703Sbostic 58231778Sbostic /* 58340390Sbostic * check_pager -- 58440390Sbostic * check the user supplied page information 58540390Sbostic */ 58665283Sbostic static char * 58740390Sbostic check_pager(name) 58840390Sbostic char *name; 58940390Sbostic { 59040390Sbostic register char *p; 59142402Sbostic char *save; 59240390Sbostic 59340390Sbostic /* 59440390Sbostic * if the user uses "more", we make it "more -s"; watch out for 59540390Sbostic * PAGER = "mypager /usr/ucb/more" 59640390Sbostic */ 59740390Sbostic for (p = name; *p && !isspace(*p); ++p); 59840390Sbostic for (; p > name && *p != '/'; --p); 59940390Sbostic if (p != name) 60040390Sbostic ++p; 60140390Sbostic 60240390Sbostic /* make sure it's "more", not "morex" */ 60340390Sbostic if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 60440390Sbostic save = name; 60540390Sbostic /* allocate space to add the "-s" */ 60640390Sbostic if (!(name = 60740390Sbostic malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 60865283Sbostic err(1, NULL); 60940390Sbostic (void)sprintf(name, "%s %s", save, "-s"); 61040390Sbostic } 61140390Sbostic return(name); 61240390Sbostic } 61340390Sbostic 61440390Sbostic /* 61534057Sbostic * jump -- 61634057Sbostic * strip out flag argument and jump 61734057Sbostic */ 61865283Sbostic static void 61934057Sbostic jump(argv, flag, name) 62065283Sbostic char **argv, *flag, *name; 62134057Sbostic { 62265283Sbostic char **arg; 62334057Sbostic 62434057Sbostic argv[0] = name; 62534057Sbostic for (arg = argv + 1; *arg; ++arg) 62634057Sbostic if (!strcmp(*arg, flag)) 62734057Sbostic break; 62834057Sbostic for (; *arg; ++arg) 62934057Sbostic arg[0] = arg[1]; 63034057Sbostic execvp(name, argv); 63142402Sbostic (void)fprintf(stderr, "%s: Command not found.\n", name); 63234057Sbostic exit(1); 63334057Sbostic } 63434057Sbostic 63565283Sbostic /* 63665283Sbostic * onsig -- 63765283Sbostic * If signaled, delete the temporary files. 63865283Sbostic */ 63965283Sbostic static void 64065283Sbostic onsig(signo) 64165283Sbostic int signo; 64265283Sbostic { 64365283Sbostic cleanup(); 64465283Sbostic 64565283Sbostic (void)signal(SIGINT, SIG_DFL); 64665283Sbostic (void)kill(getpid(), SIGINT); 64765283Sbostic } 64865283Sbostic 64934057Sbostic /* 65065283Sbostic * cleanup -- 65165283Sbostic * Clean up temporary files, show any error messages. 65265283Sbostic */ 65365283Sbostic static void 65465283Sbostic cleanup() 65565283Sbostic { 65665283Sbostic ENTRY *intmpp, *missp; 65765283Sbostic int sverrno; 65865283Sbostic 65965283Sbostic sverrno = errno; 66065283Sbostic 66165283Sbostic missp = getlist("_missing"); 66265283Sbostic if (missp != NULL) 66365283Sbostic missp = missp->list.qe_next; 66465283Sbostic if (missp != NULL) 66565283Sbostic for (; missp != NULL; missp = missp->list.qe_next) 66665283Sbostic warnx("no entry for %s in the manual.", missp->s); 66765283Sbostic 66865283Sbostic intmpp = getlist("_intmp"); 66965283Sbostic if (intmpp != NULL) 67065283Sbostic intmpp = intmpp->list.qe_next; 67165283Sbostic for (; intmpp != NULL; intmpp = intmpp->list.qe_next) 67265283Sbostic (void)unlink(intmpp->s); 67365283Sbostic 67465283Sbostic errno = sverrno; 67565283Sbostic } 67665283Sbostic 67765283Sbostic /* 67834057Sbostic * usage -- 67940390Sbostic * print usage message and die 68034057Sbostic */ 68165283Sbostic static void 68234057Sbostic usage() 68334057Sbostic { 68440390Sbostic (void)fprintf(stderr, 68565284Sbostic "usage: man [-ac] [-C file] [-M path] [-m path] [section] title ...\n"); 68634057Sbostic exit(1); 68734057Sbostic } 688