diff options
Diffstat (limited to 'usr.bin/man/man.c')
-rw-r--r-- | usr.bin/man/man.c | 1077 |
1 files changed, 0 insertions, 1077 deletions
diff --git a/usr.bin/man/man.c b/usr.bin/man/man.c deleted file mode 100644 index cba36bc..0000000 --- a/usr.bin/man/man.c +++ /dev/null @@ -1,1077 +0,0 @@ -/* $NetBSD: man.c,v 1.67 2018/06/15 20:16:35 mrg Exp $ */ - -/* - * Copyright (c) 1987, 1993, 1994, 1995 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> - -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994, 1995\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)man.c 8.17 (Berkeley) 1/31/95"; -#else -__RCSID("$NetBSD: man.c,v 1.67 2018/06/15 20:16:35 mrg Exp $"); -#endif -#endif /* not lint */ - -#include <sys/param.h> -#include <sys/queue.h> -#include <sys/stat.h> -#include <sys/utsname.h> - -#include <ctype.h> -#include <err.h> -#include <fcntl.h> -#include <fnmatch.h> -#include <glob.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <util.h> -#include <locale.h> - -#include "manconf.h" -#include "pathnames.h" - -#ifndef MAN_DEBUG -#define MAN_DEBUG 0 /* debug path output */ -#endif - -/* - * manstate: structure collecting the current global state so we can - * easily identify it and pass it to helper functions in one arg. - */ -struct manstate { - /* command line flags */ - int all; /* -a: show all matches rather than first */ - int cat; /* -c: do not use a pager */ - char *conffile; /* -C: use alternate config file */ - int how; /* -h: show SYNOPSIS only */ - char *manpath; /* -M: alternate MANPATH */ - char *addpath; /* -m: add these dirs to front of manpath */ - char *pathsearch; /* -S: path of man must contain this string */ - char *sectionname; /* -s: limit search to a given man section */ - int where; /* -w: just show paths of all matching files */ - int getpath; /* -p: print the path of directories containing man pages */ - - /* important tags from the config file */ - TAG *defaultpath; /* _default: default MANPATH */ - TAG *subdirs; /* _subdir: default subdir search list */ - TAG *suffixlist; /* _suffix: for files that can be cat()'d */ - TAG *buildlist; /* _build: for files that must be built */ - - /* tags for internal use */ - TAG *intmp; /* _intmp: tmp files we must cleanup */ - TAG *missinglist; /* _missing: pages we couldn't find */ - TAG *mymanpath; /* _new_path: final version of MANPATH */ - TAG *section; /* <sec>: tag for m.sectionname */ - - /* other misc stuff */ - const char *pager; /* pager to use */ - size_t pagerlen; /* length of the above */ - const char *machine; /* machine */ - const char *machclass; /* machine class */ -}; - -/* - * prototypes - */ -static void build_page(const char *, char **, struct manstate *); -static void cat(const char *); -static const char *check_pager(const char *); -static int cleanup(void); -static void how(const char *); -static void jump(char **, const char *, const char *) __dead; -static int manual(char *, struct manstate *, glob_t *); -static void onsig(int) __dead; -static void usage(void) __dead; -static void addpath(struct manstate *, const char *, size_t, const char *); -static const char *getclass(const char *); -static void printmanpath(struct manstate *); - -/* - * main function - */ -int -main(int argc, char **argv) -{ - static struct manstate m; - struct utsname utsname; - int ch, abs_section, found; - ENTRY *esubd, *epath; - char *p, **ap, *cmd; - size_t len; - glob_t pg; - - setprogname(argv[0]); - setlocale(LC_ALL, ""); - /* - * parse command line... - */ - while ((ch = getopt(argc, argv, "-aC:cfhkM:m:P:ps:S:w")) != -1) - switch (ch) { - case 'a': - m.all = 1; - break; - case 'C': - m.conffile = optarg; - break; - case 'c': - case '-': /* XXX: '-' is a deprecated version of '-c' */ - m.cat = 1; - break; - case 'h': - m.how = 1; - break; - case 'm': - m.addpath = optarg; - break; - case 'M': - case 'P': /* -P for backward compatibility */ - if ((m.manpath = strdup(optarg)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - break; - case 'p': - m.getpath = 1; - break; - /* - * The -f and -k options are backward compatible, - * undocumented ways of calling whatis(1) and apropos(1). - */ - case 'f': - jump(argv, "-f", "whatis"); - /* NOTREACHED */ - case 'k': - jump(argv, "-k", "apropos"); - /* NOTREACHED */ - case 's': - if (m.sectionname != NULL) - usage(); - m.sectionname = optarg; - break; - case 'S': - m.pathsearch = optarg; - break; - case 'w': - m.all = m.where = 1; - break; - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - - if (!m.getpath && !argc) - usage(); - - /* - * read the configuration file and collect any other information - * we will need (machine type, pager, section [if specified - * without '-s'], and MANPATH through the environment). - */ - config(m.conffile); /* exits on error ... */ - - if ((m.machine = getenv("MACHINE")) == NULL) { - if (uname(&utsname) == -1) - err(EXIT_FAILURE, "uname"); - m.machine = utsname.machine; - } - - m.machclass = getclass(m.machine); - - if (!m.cat && !m.how && !m.where) { /* if we need a pager ... */ - if (!isatty(STDOUT_FILENO)) { - m.cat = 1; - } else { - if ((m.pager = getenv("PAGER")) != NULL && - m.pager[0] != '\0') - m.pager = check_pager(m.pager); - else - m.pager = _PATH_PAGER; - m.pagerlen = strlen(m.pager); - } - } - - /* do we need to set m.section to a non-null value? */ - if (m.sectionname) { - - m.section = gettag(m.sectionname, 0); /* -s must be a section */ - if (m.section == NULL) - errx(EXIT_FAILURE, "unknown section: %s", m.sectionname); - - } else if (argc > 1) { - - m.section = gettag(*argv, 0); /* might be a section? */ - if (m.section) { - argv++; - argc--; - } - - } - - if (m.manpath == NULL) - m.manpath = getenv("MANPATH"); /* note: -M overrides getenv */ - - - /* - * get default values from config file, plus create the tags we - * use for keeping internal state. make sure all our mallocs - * go through. - */ - /* from cfg file */ - m.defaultpath = gettag("_default", 1); - m.subdirs = gettag("_subdir", 1); - m.suffixlist = gettag("_suffix", 1); - m.buildlist = gettag("_build", 1); - /* internal use */ - m.mymanpath = gettag("_new_path", 1); - m.missinglist = gettag("_missing", 1); - m.intmp = gettag("_intmp", 1); - if (!m.defaultpath || !m.subdirs || !m.suffixlist || !m.buildlist || - !m.mymanpath || !m.missinglist || !m.intmp) - errx(EXIT_FAILURE, "malloc failed"); - - /* - * are we using a section whose elements are all absolute paths? - * (we only need to look at the first entry on the section list, - * as config() will ensure that any additional entries will match - * the first one.) - */ - abs_section = (m.section != NULL && - !TAILQ_EMPTY(&m.section->entrylist) && - *(TAILQ_FIRST(&m.section->entrylist)->s) == '/'); - - /* - * now that we have all the data we need, we must determine the - * manpath we are going to use to find the requested entries using - * the following steps... - * - * [1] if the user specified a section and that section's elements - * from the config file are all absolute paths, then we override - * defaultpath and -M/MANPATH with the section's absolute paths. - */ - if (abs_section) { - m.manpath = NULL; /* ignore -M/MANPATH */ - m.defaultpath = m.section; /* overwrite _default path */ - m.section = NULL; /* promoted to defaultpath */ - } - - /* - * [2] section can now only be non-null if the user asked for - * a section and that section's elements did not have - * absolute paths. in this case we use the section's - * elements to override _subdir from the config file. - * - * after this step, we are done processing "m.section"... - */ - if (m.section) - m.subdirs = m.section; - - /* - * [3] we need to setup the path we want to use (m.mymanpath). - * if the user gave us a path (m.manpath) use it, otherwise - * go with the default. in either case we need to append - * the subdir and machine spec to each element of the path. - * - * for absolute section paths that come from the config file, - * we only append the subdir spec if the path ends in - * a '/' --- elements that do not end in '/' are assumed to - * not have subdirectories. this is mainly for backward compat, - * but it allows non-subdir configs like: - * sect3 /usr/share/man/{old/,}cat3 - * doc /usr/{pkg,share}/doc/{sendmail/op,sendmail/intro} - * - * note that we try and be careful to not put double slashes - * in the path (e.g. we want /usr/share/man/man1, not - * /usr/share/man//man1) because "more" will put the filename - * we generate in its prompt and the double slashes look ugly. - */ - if (m.manpath) { - - /* note: strtok is going to destroy m.manpath */ - for (p = strtok(m.manpath, ":") ; p ; p = strtok(NULL, ":")) { - len = strlen(p); - if (len < 1) - continue; - TAILQ_FOREACH(esubd, &m.subdirs->entrylist, q) - addpath(&m, p, len, esubd->s); - } - - } else { - - TAILQ_FOREACH(epath, &m.defaultpath->entrylist, q) { - /* handle trailing "/" magic here ... */ - if (abs_section && epath->s[epath->len - 1] != '/') { - addpath(&m, "", 1, epath->s); - continue; - } - - TAILQ_FOREACH(esubd, &m.subdirs->entrylist, q) - addpath(&m, epath->s, epath->len, esubd->s); - } - - } - - /* - * [4] finally, prepend the "-m" m.addpath to mymanpath if it - * was specified. subdirs and machine are always applied to - * m.addpath. - */ - if (m.addpath) { - - /* note: strtok is going to destroy m.addpath */ - for (p = strtok(m.addpath, ":") ; p ; p = strtok(NULL, ":")) { - len = strlen(p); - if (len < 1) - continue; - TAILQ_FOREACH(esubd, &m.subdirs->entrylist, q) - addpath(&m, p, len, esubd->s); - } - - } - - if (m.getpath) - printmanpath(&m); - - /* - * now m.mymanpath is complete! - */ -#if MAN_DEBUG - printf("mymanpath:\n"); - TAILQ_FOREACH(epath, &m.mymanpath->entrylist, q) { - printf("\t%s\n", epath->s); - } -#endif - - /* - * start searching for matching files and format them if necessary. - * setup an interrupt handler so that we can ensure that temporary - * files go away. - */ - (void)signal(SIGINT, onsig); - (void)signal(SIGHUP, onsig); - (void)signal(SIGPIPE, onsig); - - memset(&pg, 0, sizeof(pg)); - for (found = 0; *argv; ++argv) - if (manual(*argv, &m, &pg)) { - found = 1; - } - - /* if nothing found, we're done. */ - if (!found) { - (void)cleanup(); - exit(EXIT_FAILURE); - } - - /* - * handle the simple display cases first (m.cat, m.how, m.where) - */ - if (m.cat) { - for (ap = pg.gl_pathv; *ap != NULL; ++ap) { - if (**ap == '\0') - continue; - cat(*ap); - } - exit(cleanup()); - } - if (m.how) { - for (ap = pg.gl_pathv; *ap != NULL; ++ap) { - if (**ap == '\0') - continue; - how(*ap); - } - exit(cleanup()); - } - if (m.where) { - for (ap = pg.gl_pathv; *ap != NULL; ++ap) { - if (**ap == '\0') - continue; - (void)printf("%s\n", *ap); - } - exit(cleanup()); - } - - /* - * normal case - we display things in a single command, so - * build a list of things to display. first compute total - * length of buffer we will need so we can malloc it. - */ - for (ap = pg.gl_pathv, len = m.pagerlen + 1; *ap != NULL; ++ap) { - if (**ap == '\0') - continue; - len += strlen(*ap) + 1; - } - if ((cmd = malloc(len)) == NULL) { - warn("malloc"); - (void)cleanup(); - exit(EXIT_FAILURE); - } - - /* now build the command string... */ - p = cmd; - len = m.pagerlen; - memcpy(p, m.pager, len); - p += len; - *p++ = ' '; - for (ap = pg.gl_pathv; *ap != NULL; ++ap) { - if (**ap == '\0') - continue; - len = strlen(*ap); - memcpy(p, *ap, len); - p += len; - *p++ = ' '; - } - *--p = '\0'; - - /* Use system(3) in case someone's pager is "pager arg1 arg2". */ - (void)system(cmd); - - exit(cleanup()); -} - -static int -manual_find_literalfile(struct manstate *mp, char **pv) -{ - ENTRY *suffix; - int found; - char buf[MAXPATHLEN]; - const char *p; - int suflen; - - found = 0; - - /* - * Expand both '*' and suffix to force an actual - * match via fnmatch(3). Since the only match in pg - * is the literal file, the match is genuine. - */ - - TAILQ_FOREACH(suffix, &mp->buildlist->entrylist, q) { - for (p = suffix->s, suflen = 0; - *p != '\0' && !isspace((unsigned char)*p); - ++p) - ++suflen; - if (*p == '\0') - continue; - - (void)snprintf(buf, sizeof(buf), "*%.*s", suflen, suffix->s); - - if (!fnmatch(buf, *pv, 0)) { - if (!mp->where) - build_page(p + 1, pv, mp); - found = 1; - break; - } - } - - return found; -} - -static int -manual_find_buildkeyword(const char *prefix, const char *escpage, - struct manstate *mp, char **pv) -{ - ENTRY *suffix; - int found; - char buf[MAXPATHLEN]; - const char *p; - int suflen; - - found = 0; - /* Try the _build keywords next. */ - TAILQ_FOREACH(suffix, &mp->buildlist->entrylist, q) { - for (p = suffix->s, suflen = 0; - *p != '\0' && !isspace((unsigned char)*p); - ++p) - ++suflen; - if (*p == '\0') - continue; - - (void)snprintf(buf, sizeof(buf), "%s%s%.*s", - prefix, escpage, suflen, suffix->s); - if (!fnmatch(buf, *pv, 0)) { - if (!mp->where) - build_page(p + 1, pv, mp); - found = 1; - break; - } - } - - return found; -} - -/* - * manual -- - * Search the manuals for the pages. - */ -static int -manual(char *page, struct manstate *mp, glob_t *pg) -{ - ENTRY *suffix, *mdir; - int anyfound, error, found; - size_t cnt; - char *p, buf[MAXPATHLEN], *escpage, *eptr; - static const char escglob[] = "\\~?*{}[]"; - - anyfound = 0; - - /* - * Fixup page which may contain glob(3) special characters, e.g. - * the famous "No man page for [" FAQ. - */ - if ((escpage = malloc((2 * strlen(page)) + 1)) == NULL) { - warn("malloc"); - (void)cleanup(); - exit(EXIT_FAILURE); - } - - p = page; - eptr = escpage; - - while (*p) { - if (strchr(escglob, *p) != NULL) { - *eptr++ = '\\'; - *eptr++ = *p++; - } else - *eptr++ = *p++; - } - - *eptr = '\0'; - - /* - * If 'page' is given with an absolute path, - * or a relative path explicitly beginning with "./" - * or "../", then interpret it as a file specification. - */ - if ((page[0] == '/') - || (page[0] == '.' && page[1] == '/') - || (page[0] == '.' && page[1] == '.' && page[2] == '/') - ) { - /* check if file actually exists */ - (void)strlcpy(buf, escpage, sizeof(buf)); - error = glob(buf, GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT, NULL, pg); - if (error != 0) { - if (error == GLOB_NOMATCH) { - goto notfound; - } else { - errx(EXIT_FAILURE, "glob failed"); - } - } - - if (pg->gl_matchc == 0) - goto notfound; - - /* literal file only yields one match */ - cnt = pg->gl_pathc - pg->gl_matchc; - - if (manual_find_literalfile(mp, &pg->gl_pathv[cnt])) { - anyfound = 1; - } else { - /* It's not a man page, forget about it. */ - *pg->gl_pathv[cnt] = '\0'; - } - - notfound: - if (!anyfound) { - if (addentry(mp->missinglist, page, 0) < 0) { - warn("malloc"); - (void)cleanup(); - exit(EXIT_FAILURE); - } - } - free(escpage); - return anyfound; - } - - /* For each man directory in mymanpath ... */ - TAILQ_FOREACH(mdir, &mp->mymanpath->entrylist, q) { - - /* - * use glob(3) to look in the filesystem for matching files. - * match any suffix here, as we will check that later. - */ - (void)snprintf(buf, sizeof(buf), "%s/%s.*", mdir->s, escpage); - if ((error = glob(buf, - GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT, NULL, pg)) != 0) { - if (error == GLOB_NOMATCH) - continue; - else { - warn("globbing"); - (void)cleanup(); - exit(EXIT_FAILURE); - } - } - if (pg->gl_matchc == 0) - continue; - - /* - * start going through the matches glob(3) just found and - * use m.pathsearch (if present) to filter out pages we - * don't want. then verify the suffix is valid, and build - * the page if we have a _build suffix. - */ - for (cnt = pg->gl_pathc - pg->gl_matchc; - cnt < pg->gl_pathc; ++cnt) { - - /* filter on directory path name */ - if (mp->pathsearch) { - p = strstr(pg->gl_pathv[cnt], mp->pathsearch); - if (!p || strchr(p, '/') == NULL) { - *pg->gl_pathv[cnt] = '\0'; /* zap! */ - continue; - } - } - - /* - * Try the _suffix keywords first. - * - * XXX - * Older versions of man.conf didn't have the _suffix - * keywords, it was assumed that everything was a .0. - * We just test for .0 first, it's fast and probably - * going to hit. - */ - (void)snprintf(buf, sizeof(buf), "*/%s.0", escpage); - if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) - goto next; - - found = 0; - TAILQ_FOREACH(suffix, &mp->suffixlist->entrylist, q) { - (void)snprintf(buf, - sizeof(buf), "*/%s%s", escpage, - suffix->s); - if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { - found = 1; - break; - } - } - if (found) - goto next; - - /* Try the _build keywords next. */ - found = manual_find_buildkeyword("*/", escpage, - mp, &pg->gl_pathv[cnt]); - if (found) { -next: anyfound = 1; - if (!mp->all) { - /* Delete any other matches. */ - while (++cnt< pg->gl_pathc) - *pg->gl_pathv[cnt] = '\0'; - break; - } - continue; - } - - /* It's not a man page, forget about it. */ - *pg->gl_pathv[cnt] = '\0'; - } - - if (anyfound && !mp->all) - break; - } - - /* If not found, enter onto the missing list. */ - if (!anyfound) { - if (addentry(mp->missinglist, page, 0) < 0) { - warn("malloc"); - (void)cleanup(); - exit(EXIT_FAILURE); - } - } - - free(escpage); - return anyfound; -} - -/* - * A do-nothing counterpart to fmtcheck(3) that only supplies the - * __format_arg marker. Actual fmtcheck(3) call is done once in - * config(). - */ -__always_inline __format_arg(2) -static inline const char * -fmtcheck_ok(const char *userfmt, const char *template) -{ - return userfmt; -} - -/* - * build_page -- - * Build a man page for display. - */ -static void -build_page(const char *fmt, char **pathp, struct manstate *mp) -{ - static int warned; - int olddir, fd, n; - size_t tmpdirlen; - char *p, *b; - char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[MAXPATHLEN]; - const char *tmpdir; - - /* Let the user know this may take awhile. */ - if (!warned) { - warned = 1; - warnx("Formatting manual page..."); - } - - /* - * Historically man chdir'd to the root of the man tree. - * This was used in man pages that contained relative ".so" - * directives (including other man pages for command aliases etc.) - * It even went one step farther, by examining the first line - * of the man page and parsing the .so filename so it would - * make hard(?) links to the cat'ted man pages for space savings. - * (We don't do that here, but we could). - */ - - /* copy and find the end */ - for (b = buf, p = *pathp; (*b++ = *p++) != '\0';) - continue; - - /* - * skip the last two path components, page name and man[n] ... - * (e.g. buf will be "/usr/share/man" and p will be "man1/man.1") - * we also save a pointer to our current directory so that we - * can fchdir() back to it. this allows relative MANDIR paths - * to work with multiple man pages... e.g. consider: - * cd /usr/share && man -M ./man cat ls - * when no "cat1" subdir files are present. - */ - olddir = -1; - for (--b, --p, n = 2; b != buf; b--, p--) - if (*b == '/') - if (--n == 0) { - *b = '\0'; - olddir = open(".", O_RDONLY); - (void) chdir(buf); - p++; - break; - } - - - /* advance fmt past the suffix spec to the printf format string */ - for (; *fmt && isspace((unsigned char)*fmt); ++fmt) - continue; - - /* - * Get a temporary file and build a version of the file - * to display. Replace the old file name with the new one. - */ - if ((tmpdir = getenv("TMPDIR")) == NULL) - tmpdir = _PATH_TMP; - tmpdirlen = strlen(tmpdir); - (void)snprintf(tpath, sizeof (tpath), "%s%s%s", tmpdir, - (tmpdirlen > 0 && tmpdir[tmpdirlen-1] == '/') ? "" : "/", TMPFILE); - if ((fd = mkstemp(tpath)) == -1) { - warn("%s", tpath); - (void)cleanup(); - exit(EXIT_FAILURE); - } - (void)snprintf(buf, sizeof(buf), "%s > %s", fmt, tpath); - (void)snprintf(cmd, sizeof(cmd), fmtcheck_ok(buf, "%s"), p); - (void)system(cmd); - (void)close(fd); - if ((*pathp = strdup(tpath)) == NULL) { - warn("malloc"); - (void)cleanup(); - exit(EXIT_FAILURE); - } - - /* Link the built file into the remove-when-done list. */ - if (addentry(mp->intmp, *pathp, 0) < 0) { - warn("malloc"); - (void)cleanup(); - exit(EXIT_FAILURE); - } - - /* restore old directory so relative manpaths still work */ - if (olddir != -1) { - fchdir(olddir); - close(olddir); - } -} - -/* - * how -- - * display how information - */ -static void -how(const char *fname) -{ - FILE *fp; - - int lcnt, print; - char buf[256]; - const char *p; - - if (!(fp = fopen(fname, "r"))) { - warn("%s", fname); - (void)cleanup(); - exit(EXIT_FAILURE); - } -#define S1 "SYNOPSIS" -#define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS" -#define D1 "DESCRIPTION" -#define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" - for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) { - if (!strncmp(buf, S1, sizeof(S1) - 1) || - !strncmp(buf, S2, sizeof(S2) - 1)) { - print = 1; - continue; - } else if (!strncmp(buf, D1, sizeof(D1) - 1) || - !strncmp(buf, D2, sizeof(D2) - 1)) { - if (fp) - (void)fclose(fp); - return; - } - if (!print) - continue; - if (*buf == '\n') - ++lcnt; - else { - for(; lcnt; --lcnt) - (void)putchar('\n'); - for (p = buf; isspace((unsigned char)*p); ++p) - continue; - (void)fputs(p, stdout); - } - } - (void)fclose(fp); -} - -/* - * cat -- - * cat out the file - */ -static void -cat(const char *fname) -{ - int fd; - ssize_t n; - char buf[2048]; - - if ((fd = open(fname, O_RDONLY, 0)) < 0) { - warn("%s", fname); - (void)cleanup(); - exit(EXIT_FAILURE); - } - while ((n = read(fd, buf, sizeof(buf))) > 0) - if (write(STDOUT_FILENO, buf, (size_t)n) != n) { - warn("write"); - (void)cleanup(); - exit(EXIT_FAILURE); - } - if (n == -1) { - warn("read"); - (void)cleanup(); - exit(EXIT_FAILURE); - } - (void)close(fd); -} - -/* - * check_pager -- - * check the user supplied page information - */ -static const char * -check_pager(const char *name) -{ - const char *p; - - /* - * if the user uses "more", we make it "more -s"; watch out for - * PAGER = "mypager /usr/ucb/more" - */ - for (p = name; *p && !isspace((unsigned char)*p); ++p) - continue; - for (; p > name && *p != '/'; --p); - if (p != name) - ++p; - - /* make sure it's "more", not "morex" */ - if (!strncmp(p, "more", 4) && (!p[4] || isspace((unsigned char)p[4]))){ - char *newname; - (void)asprintf(&newname, "%s %s", p, "-s"); - name = newname; - } - - return name; -} - -/* - * jump -- - * strip out flag argument and jump - */ -static void -jump(char **argv, const char *flag, const char *name) -{ - char **arg; - - argv[0] = __UNCONST(name); - for (arg = argv + 1; *arg; ++arg) - if (!strcmp(*arg, flag)) - break; - for (; *arg; ++arg) - arg[0] = arg[1]; - execvp(name, argv); - err(EXIT_FAILURE, "Cannot execute `%s'", name); -} - -/* - * onsig -- - * If signaled, delete the temporary files. - */ -static void -onsig(int signo) -{ - - (void)cleanup(); - - (void)raise_default_signal(signo); - - /* NOTREACHED */ - exit(EXIT_FAILURE); -} - -/* - * cleanup -- - * Clean up temporary files, show any error messages. - */ -static int -cleanup(void) -{ - TAG *intmpp, *missp; - ENTRY *ep; - int rval; - - rval = EXIT_SUCCESS; - /* - * note that _missing and _intmp were created by main(), so - * gettag() cannot return NULL here. - */ - missp = gettag("_missing", 0); /* missing man pages */ - intmpp = gettag("_intmp", 0); /* tmp files we need to unlink */ - - TAILQ_FOREACH(ep, &missp->entrylist, q) { - warnx("no entry for %s in the manual.", ep->s); - rval = EXIT_FAILURE; - } - - TAILQ_FOREACH(ep, &intmpp->entrylist, q) - (void)unlink(ep->s); - - return rval; -} - -static const char * -getclass(const char *machine) -{ - char buf[BUFSIZ]; - TAG *t; - snprintf(buf, sizeof(buf), "_%s", machine); - t = gettag(buf, 0); - return t != NULL && !TAILQ_EMPTY(&t->entrylist) ? - TAILQ_FIRST(&t->entrylist)->s : NULL; -} - -static void -addpath(struct manstate *m, const char *dir, size_t len, const char *sub) -{ - char buf[2 * MAXPATHLEN + 1]; - (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,%s%s%s}", - dir, (dir[len - 1] == '/') ? "" : "/", sub, m->machine, - m->machclass ? "/" : "", m->machclass ? m->machclass : "", - m->machclass ? "," : ""); - if (addentry(m->mymanpath, buf, 0) < 0) - errx(EXIT_FAILURE, "malloc failed"); -} - -/* - * usage -- - * print usage message and die - */ -static void -usage(void) -{ - (void)fprintf(stderr, "Usage: %s [-acw|-h] [-C cfg] [-M path] " - "[-m path] [-S srch] [[-s] sect] name ...\n", getprogname()); - (void)fprintf(stderr, "Usage: %s [-C file] -f command ...\n", getprogname()); - (void)fprintf(stderr, - "Usage: %s [-C file] -k keyword ...\n", - getprogname()); - (void)fprintf(stderr, "Usage: %s -p\n", getprogname()); - exit(EXIT_FAILURE); -} - -/* - * printmanpath -- - * Prints a list of directories containing man pages. - */ -static void -printmanpath(struct manstate *m) -{ - ENTRY *epath; - char **ap; - glob_t pg; - struct stat sb; - TAG *path = m->mymanpath; - - /* the tail queue is empty if no _default tag is defined in * man.conf */ - if (TAILQ_EMPTY(&path->entrylist)) - errx(EXIT_FAILURE, "Empty manpath"); - - TAILQ_FOREACH(epath, &path->entrylist, q) { - if (glob(epath->s, GLOB_BRACE | GLOB_NOSORT, NULL, &pg) != 0) - err(EXIT_FAILURE, "glob failed"); - - if (pg.gl_matchc == 0) { - globfree(&pg); - continue; - } - - for (ap = pg.gl_pathv; *ap != NULL; ++ap) { - /* Skip cat page directories */ - if (strstr(*ap, "/cat") != NULL) - continue; - /* Skip non-directories. */ - if (stat(*ap, &sb) == 0 && S_ISDIR(sb.st_mode)) - printf("%s\n", *ap); - } - globfree(&pg); - } -} |