diff --git a/commands/Makefile b/commands/Makefile index 4d6a71215..61b67c101 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -16,7 +16,7 @@ SUBDIR= aal add_route adduser advent arp ash at autil awk \ hostaddr id ifconfig ifdef indent install \ intr ipcrm ipcs irdpd isoread join kill last leave \ less lex life loadkeys loadramdisk logger login look lp \ - lpd ls lspci M m4 mail make MAKEDEV \ + lpd ls lspci M m4 mail make MAKEDEV man \ mdb mdocml mesg mined mkdep mkdir mkdist mkfifo mkfs mknod \ mkproto modem mount mt netconf newroot nice nm nohup \ nonamed od packit packman passwd paste patch pax \ diff --git a/commands/man/Makefile b/commands/man/Makefile new file mode 100644 index 000000000..1e038d865 --- /dev/null +++ b/commands/man/Makefile @@ -0,0 +1,11 @@ +# $NetBSD: Makefile,v 1.10 2007/10/05 07:38:52 lukem Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= man +SRCS= man.c manconf.c +MAN= man.1 man.conf.5 + +DPADD+= ${LIBUTIL} +LDADD+= -lutil + +.include diff --git a/commands/man/man.1 b/commands/man/man.1 new file mode 100644 index 000000000..96b0ce763 --- /dev/null +++ b/commands/man/man.1 @@ -0,0 +1,233 @@ +.\" $NetBSD: man.1,v 1.20 2006/04/13 21:10:44 wiz Exp $ +.\" +.\" Copyright (c) 1989, 1990, 1993 +.\" 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. +.\" +.\" @(#)man.1 8.2 (Berkeley) 1/2/94 +.\" +.Dd April 10, 2006 +.Dt MAN 1 +.Os +.Sh NAME +.Nm man +.Nd display the on-line manual pages +.Pq aka Dq Em man pages +.Sh SYNOPSIS +.Nm +.Oo Fl acw Ns \&| Ns Fl h Oc +.Op Fl C Ar file +.Op Fl M Ar path +.Op Fl m Ar path +.Op Fl S Ar srch +.Oo +.Op Fl s +.Ar section +.Oc +.Ar name Ar ... +.Nm +.Op Fl k +.Op Fl C Ar file +.Op Fl M Ar path +.Op Fl m Ar path +.Ar keyword Ar ... +.Sh DESCRIPTION +The +.Nm +utility displays the manual pages named on the command line. +Its options are as follows: +.Bl -tag -width indent +.It Fl a +Display all of the man pages for a specified +.Ar section +and +.Ar name +combination. +(Normally, only the first man page found is displayed.) +.It Fl C +Use the specified +.Ar file +instead of the default configuration file. +This permits users to configure their own man environment. +See +.Xr man.conf 5 +for a description of the contents of this file. +.It Fl c +Copy the man page to the standard output instead of using +.Xr more 1 +to paginate it. +This is done by default if the standard output is not a terminal device. +.It Fl h +Display only the +.Dq Tn SYNOPSIS +lines of the requested man pages. +For commands, this is typically the command line usage information. +For library functions, this usually contains the required include +files and function prototypes. +.It Fl k +Display the header lines for any man pages matching +.Ar keyword Ns Pq s , +in the same manner as +.Xr apropos 1 . +.It Fl M +Override the list of standard directories which +.Nm +searches for man pages. +The supplied +.Ar path +must be a colon +.Pq Dq \&: +separated list of directories. +This search path may also be set using the environment variable +.Ev MANPATH . +The subdirectories to be searched, and their search order, +is specified by the +.Dq _subdir +line in the +.Nm +configuration file. +.It Fl m +Augment the list of standard directories which +.Nm +searches for man pages. +The supplied +.Ar path +must be a colon +.Pq Dq \&: +separated list of directories. +These directories will be searched before the standard directories or +the directories specified using the +.Fl M +option or the +.Ev MANPATH +environment variable. +The subdirectories to be searched, and their search order, +is specified by the +.Dq _subdir +line in the +.Nm +configuration file. +.It Fl s +Restrict the directories that +.Nm +will search to the specified section. +The +.Nm +configuration file (see +.Xr man.conf 5 ) +specifies the possible +.Ar section +values that are currently available. +.It Fl S +Display only man pages that have the specified string in the directory +part of their filenames. +This allows the man page search process criteria to be +narrowed without having to change the MANPATH or +.Dq _default +variables. +.It Fl w +List the pathnames of the man pages which +.Nm +would display for the specified +.Ar section +and +.Ar name +combination. +.El +.Pp +If the +.Ql Fl s +option is not specified, +there is more than one argument, +the +.Ql Fl k +option is not used, and the first argument is a valid section, then that +argument will be used as if specified by the +.Ql Fl s +option. +.Sh ENVIRONMENT +.Bl -tag -width MANPATHX +.It Ev MACHINE +As some man pages are intended only for specific architectures, +.Nm +searches any subdirectories, +with the same name as the current architecture, +in every directory which it searches. +Machine specific areas are checked before general areas. +The current machine type may be overridden by setting the environment +variable +.Ev MACHINE +to the name of a specific architecture. +.It Ev MANPATH +The standard search path used by +.Nm +may be overridden by specifying a path in the +.Ev MANPATH +environment +variable. +The format of the path is a colon +.Pq Dq \&: +separated list of directories. +The subdirectories to be searched as well as their search order +is specified by the +.Dq _subdir +line in the +.Nm +configuration file. +.It Ev PAGER +The pagination command used for writing the output. +If the +.Ev PAGER +environment variable is null or not set, the standard pagination program +.Xr more 1 +will be used. +.El +.Sh FILES +.Bl -hang -width /etc/man.conf -compact +.It Pa /etc/man.conf +default man configuration file. +.It Pa /usr/{share,X11R6,pkg,local}/man/whatis.db +standard whatis/apropos database search path, +set in +.Pa /etc/man.conf . +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr whatis 1 , +.Xr whereis 1 , +.Xr man.conf 5 , +.Xr mdoc 7 , +.Xr mdoc.samples 7 +.Sh STANDARDS +.Nm +conforms to +.St -xcu5 . +.\"and is expected to conform to +.\".St -p1003.2-?? . +.Sh BUGS +The on-line man pages are, by necessity, forgiving toward stupid +display devices, causing a few man pages to be not as nicely formatted +as their typeset counterparts. diff --git a/commands/man/man.c b/commands/man/man.c new file mode 100644 index 000000000..d539c8d6d --- /dev/null +++ b/commands/man/man.c @@ -0,0 +1,906 @@ +/* $NetBSD: man.c,v 1.37 2008/07/21 14:19:24 lukem 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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 */ + + /* 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; /* : tag for m.sectionname */ + + /* other misc stuff */ + const char *pager; /* pager to use */ + size_t pagerlen; /* length of the above */ +}; + +/* + * prototypes + */ +int main(int, char **); +static void build_page(char *, char **, struct manstate *); +static void cat(char *); +static const char *check_pager(const char *); +static int cleanup(void); +static void how(char *); +static void jump(char **, char *, char *); +static int manual(char *, struct manstate *, glob_t *); +static void onsig(int); +static void usage(void); + +/* + * main function + */ +int +main(int argc, char **argv) +{ + static struct manstate m = { 0 }; /* init to zero */ + int ch, abs_section, found; + const char *machine; + ENTRY *esubd, *epath; + char *p, **ap, *cmd, buf[MAXPATHLEN * 2]; + size_t len; + glob_t pg; + + /* + * parse command line... + */ + while ((ch = getopt(argc, argv, "-aC:cfhkM:m:P:s: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 */ + m.manpath = strdup(optarg); + 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 (!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 ((machine = getenv("MACHINE")) == NULL) { + struct utsname utsname; + + if (uname(&utsname) == -1) { + perror("uname"); + exit(1); + } + machine = utsname.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(1, "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(1, "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) { + snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", + p, (p[len-1] == '/') ? "" : "/", + esubd->s, machine); + if (addentry(m.mymanpath, buf, 0) < 0) + errx(1, "malloc failed"); + } + } + + } else { + + TAILQ_FOREACH(epath, &m.defaultpath->entrylist, q) { + /* handle trailing "/" magic here ... */ + if (abs_section && + epath->s[epath->len - 1] != '/') { + + (void)snprintf(buf, sizeof(buf), + "%s{/%s,}", epath->s, machine); + if (addentry(m.mymanpath, buf, 0) < 0) + errx(1, "malloc failed"); + continue; + } + + TAILQ_FOREACH(esubd, &m.subdirs->entrylist, q) { + snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", + epath->s, + (epath->s[epath->len-1] == '/') ? "" + : "/", + esubd->s, machine); + if (addentry(m.mymanpath, buf, 0) < 0) + errx(1, "malloc failed"); + } + } + + } + + /* + * [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) { + snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", + p, (p[len-1] == '/') ? "" : "/", + esubd->s, machine); + /* add at front */ + if (addentry(m.mymanpath, buf, 1) < 0) + errx(1, "malloc failed"); + } + } + + } + + /* + * 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 (1); + } + + /* + * 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(1); + } + + /* 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()); +} + +/* + * 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(1); + } + + p = page; + eptr = escpage; + + while (*p) { + if (strchr(escglob, *p) != NULL) { + *eptr++ = '\\'; + *eptr++ = *p++; + } else + *eptr++ = *p++; + } + + *eptr = '\0'; + + /* 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(1); + } + } + 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] = ""; /* zap! */ + continue; + } + } + + /* + * Try the _suffix key words first. + * + * XXX + * Older versions of man.conf didn't have the suffix + * key words, 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 key words next. */ + found = 0; + TAILQ_FOREACH(suffix, &mp->buildlist->entrylist, q) { + for (p = suffix->s; + *p != '\0' && !isspace((unsigned char)*p); + ++p) + continue; + if (*p == '\0') + continue; + *p = '\0'; + (void)snprintf(buf, + sizeof(buf), "*/%s%s", escpage, + suffix->s); + if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { + if (!mp->where) + build_page(p + 1, + &pg->gl_pathv[cnt], mp); + *p = ' '; + found = 1; + break; + } + *p = ' '; + } + if (found) { +next: anyfound = 1; + if (!mp->all) { + /* Delete any other matches. */ + while (++cnt< pg->gl_pathc) + pg->gl_pathv[cnt] = ""; + break; + } + continue; + } + + /* It's not a man page, forget about it. */ + pg->gl_pathv[cnt] = ""; + } + + 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(1); + } + } + + free(escpage); + return (anyfound); +} + +/* + * build_page -- + * Build a man page for display. + */ +static void +build_page(char *fmt, char **pathp, struct manstate *mp) +{ + static int warned; + int olddir, fd, n, 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 pass 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 && tmpdir[tmpdirlen-1] == '/') ? "" : "/", TMPFILE); + if ((fd = mkstemp(tpath)) == -1) { + warn("%s", tpath); + (void)cleanup(); + exit(1); + } + (void)snprintf(buf, sizeof(buf), "%s > %s", fmt, tpath); + (void)snprintf(cmd, sizeof(cmd), buf, p); + (void)system(cmd); + (void)close(fd); + if ((*pathp = strdup(tpath)) == NULL) { + warn("malloc"); + (void)cleanup(); + exit(1); + } + + /* Link the built file into the remove-when-done list. */ + if (addentry(mp->intmp, *pathp, 0) < 0) { + warn("malloc"); + (void)cleanup(); + exit(1); + } + + /* restore old directory so relative manpaths still work */ + if (olddir != -1) { + fchdir(olddir); + close(olddir); + } +} + +/* + * how -- + * display how information + */ +static void +how(char *fname) +{ + FILE *fp; + + int lcnt, print; + char *p, buf[256]; + + if (!(fp = fopen(fname, "r"))) { + warn("%s", fname); + (void)cleanup(); + exit (1); + } +#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(char *fname) +{ + int fd, n; + char buf[2048]; + + if ((fd = open(fname, O_RDONLY, 0)) < 0) { + warn("%s", fname); + (void)cleanup(); + exit(1); + } + while ((n = read(fd, buf, sizeof(buf))) > 0) + if (write(STDOUT_FILENO, buf, n) != n) { + warn("write"); + (void)cleanup(); + exit (1); + } + if (n == -1) { + warn("read"); + (void)cleanup(); + exit(1); + } + (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; + if(!(newname = malloc(strlen(p) + 20))) { + errx(1, "malloc failed"); + } + (void)sprintf(newname, "%s %s", p, "-s"); + name = newname; + } + + return (name); +} + +/* + * jump -- + * strip out flag argument and jump + */ +static void +jump(char **argv, char *flag, char *name) +{ + char **arg; + + argv[0] = name; + for (arg = argv + 1; *arg; ++arg) + if (!strcmp(*arg, flag)) + break; + for (; *arg; ++arg) + arg[0] = arg[1]; + execvp(name, argv); + (void)fprintf(stderr, "%s: Command not found.\n", name); + exit(1); +} + +/* + * onsig -- + * If signaled, delete the temporary files. + */ +static void +onsig(int signo) +{ + + (void)cleanup(); + +#if 0 + (void)raise_default_signal(signo); +#endif + + /* NOTREACHED */ + exit (1); +} + +/* + * cleanup -- + * Clean up temporary files, show any error messages. + */ +static int +cleanup() +{ + TAG *intmpp, *missp; + ENTRY *ep; + int rval; + + rval = 0; + /* + * 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 = 1; + } + + TAILQ_FOREACH(ep, &intmpp->entrylist, q) + (void)unlink(ep->s); + + return (rval); +} + +/* + * usage -- + * print usage message and die + */ +static void +usage() +{ + (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 -k [-C cfg] [-M path] [-m path] keyword ...\n", + getprogname()); + exit(1); +} diff --git a/commands/man/man.conf.5 b/commands/man/man.conf.5 new file mode 100644 index 000000000..9442e5d51 --- /dev/null +++ b/commands/man/man.conf.5 @@ -0,0 +1,271 @@ +.\" $NetBSD: man.conf.5,v 1.20 2007/02/10 19:27:39 reed Exp $ +.\" +.\" Copyright (c) 1989, 1991, 1993 +.\" 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. +.\" +.\" @(#)man.conf.5 8.5 (Berkeley) 1/2/94 +.\" +.Dd April 10, 2006 +.Dt MAN.CONF 5 +.Os +.Sh NAME +.Nm man.conf +.Nd configuration file for manual pages +.Sh DESCRIPTION +The +.Nm +file contains the default configuration used by +.Xr man 1 , +.Xr apropos 1 , +.Xr whatis 1 , +.Xr catman 8 , +and +.Xr makewhatis 8 +to find manual pages and information about manual pages (e.g. the +whatis database). +.Pp +Manual pages are located by searching an ordered set of directories +called the +.Dq man path +for a file that matches the name of the requested page. +Each directory in the search path usually has a set of subdirectories +in it (though this is not required). +When subdirectories are used, there are normally two subdirectories +for each section of the manual. +One subdirectory contains formatted copies of that section's manual +pages that can be directly displayed to a terminal, while the other +section subdirectory contains unformatted copies of the pages (see +.Xr nroff 1 +and +.Xr mdoc 7 ) . +Formatted manual pages are normally named with a trailing +.Dq \.0 +suffix. +.Pp +The +.Nm +file contains comment and configuration lines. +Comment lines start with the +.Dq # +character. +Blank lines are also treated as comment lines. +Configuration lines consist of a configuration keyword followed by a +configuration string. +There are two types of configuration keywords: control keywords and +section keywords. +Control keywords must start with the +.Dq _ +character. +The following control keywords are currently defined: +.Bl -tag -width "_version" +.It _build +identifies the set of suffixes used for manual pages that must be +formatted for display and the command that should be used to format +them. +Manual file names, regardless of their format, are expected to end in a +.Dq \.* +pattern, i.e. a +.Dq \&\. +followed by some suffix. +The first field of a _build line contains a man page suffix specification. +The suffix specification may contain the normal shell globbing characters +(NOT including curly braces +.Pq Dq {} ) . +The rest of the _build line is a shell command line whose standard +output is a formatted manual page that can be directly displayed to +the user. +Any occurrences of the string +.Dq %s +in the shell command line will +be replaced by the name of the file which is being formatted. +.It _crunch +used by +.Xr catman 8 +to determine how to crunch formatted pages +which originally were compressed man pages: The first field lists a suffix +which indicates what kind of compression were used to compress the man page. +The rest of the line must be a shell command line, used to compress the +formatted pages. +.It _default +contains the system-wide default man path used to search for man pages. +.It _subdir +contains the list (in search order) of section subdirectories which will +be searched in any man path directory named with a trailing slash +.Pq Dq / +character. +This list is also used, even if there is no trailing slash character, +when a path is specified to the +.Xr man 1 +utility by the user, by the +.Ev MANPATH +environment variable, or by the +.Fl M +and +.Fl m +options. +.It _suffix +identifies the set of suffixes used for formatted man pages +(the +.Dq \.0 +suffix is normally used here). +Formatted man pages can be directly displayed to the user. +Each suffix may contain the normal shell globbing characters (NOT +including curly braces +.Pq Dq {} ) . +.It _version +contains the version of the configuration file. +.It _whatdb +defines the full pathname (not just a directory path) for a database to +be used +by the +.Xr apropos 1 +and +.Xr whatis 1 +commands. +The pathname may contain the normal shell globbing characters, +including curly braces +.Pq Dq {} ; +to escape a shell globbing character, +precede it with a backslash +.Pq Dq \e . +.El +.Pp +Section configuration lines in +.Nm +consist of a section keyword naming the section and a configuration +string that defines the directory or subdirectory path that the section's +manual pages are located in. +The path may contain the normal shell globbing characters, +including curly braces +.Pq Dq {} ; +to escape a shell globbing character, +precede it with a backslash +.Pq Dq \e . +Section keywords must not start with the +.Dq _ +character. +.Pp +A section path may contain either a list of absolute directories or +a list of or relative directories (but not both). +Relative directory paths are treated as a list of subdirectories that +are appended to the current man path directory being searched. +Section configuration lines with absolute directory paths (starting with +.Dq / ) +completely replace the current man search path directory with their +content. +.Pp +Section configuration lines with absolute directory paths ending +with a trailing slash character are expected to contain subdirectories +of manual pages, (see the keyword +.Dq _subdir +above). +The +.Dq _subdir +subdirectory list is not applied to absolute section directories +if there is no trailing slash. +.Pp +In addition to the above rules, the +.Xr man 1 +command also always checks in each directory that it searches for +a subdirectory with the same name as the current machine type. +If the machine-specific directory is found, it is also searched. +This allows the manual to contain machine-specific man pages. +Note that the machine subdirectory does not need to be specified +in the +.Nm +file. +.Pp +Multiple specifications for all types of +.Nm +configuration lines are +cumulative and the entries are used in the order listed in the file; +multiple entries may be listed per line, as well. +.Sh FILES +.Bl -tag -width /etc/man.conf -compact +.It Pa /etc/man.conf +Standard manual configuration file. +.El +.Sh EXAMPLES +Given the following +.Nm +file: +.Bd -literal -offset indent +_version BSD.2 +_subdir cat[123] +_suffix .0 +_build .[1-9] nroff -man %s +_build .tbl tbl %s | nroff -man +_default /usr/share/man/ +sect3 /usr/share/man/{old/,}cat3 +.Ed +.Pp +By default, the command +.Dq Li man mktemp +will search for +.Dq mktemp.\*[Lt]any_digit\*[Gt] +and +.Dq mktemp.tbl +in the directories +.Dq Pa /usr/share/man/cat1 , +.Dq Pa /usr/share/man/cat2 , +and +.Dq Pa /usr/share/man/cat3 . +If on a machine of type +.Dq vax , +the subdirectory +.Dq vax +in each +directory would be searched as well, before the directory was +searched. +.Pp +If +.Dq mktemp.tbl +was found first, the command +.Dq Li tbl \*[Lt]manual page\*[Gt] | nroff -man +would be run to build a man page for display to the user. +.Pp +The command +.Dq Li man sect3 mktemp +would search the directories +.Dq Pa /usr/share/man/old/cat3 +and +.Dq Pa /usr/share/man/cat3 , +in that order, for +the mktemp manual page. +If a subdirectory with the same name as the current machine type +existed in any of them, it would be searched as well, before each +of them were searched. +.Sh SEE ALSO +.Xr apropos 1 , +.Xr machine 1 , +.Xr man 1 , +.Xr whatis 1 , +.Xr whereis 1 , +.Xr fnmatch 3 , +.Xr glob 3 , +.Xr catman 8 , +.Xr makewhatis 8 diff --git a/commands/man/manconf.c b/commands/man/manconf.c new file mode 100644 index 000000000..63c5a94eb --- /dev/null +++ b/commands/man/manconf.c @@ -0,0 +1,250 @@ +/* $NetBSD: manconf.c,v 1.6 2008/03/08 15:48:27 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993, 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. + */ + +/* + * manconf.c: provides interface for reading man.conf files + * + * note that this code is shared across all programs that read man.conf. + * (currently: apropos, catman, makewhatis, man, and whatis...) + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "manconf.h" +#include "pathnames.h" + +TAILQ_HEAD(_head, _tag); +static struct _head head; /* 'head' -- top level data structure */ + +/* + * xstrdup: like strdup, but also returns length of string in lenp + */ +static char * +xstrdup(const char *str, size_t *lenp) +{ + size_t len; + char *copy; + + len = strlen(str) + 1; + copy = malloc(len); + if (!copy) + return NULL; + (void)memcpy(copy, str, len); + if (lenp) + *lenp = len - 1; /* subtract out the null */ + return copy; +} + +/* + * config -- + * + * Read the configuration file and build a doubly linked + * list off of "head" that looks like: + * + * tag1 <-> entry <-> entry <-> entry + * | + * tag2 <-> entry <-> entry <-> entry + * + * note: will err/errx out on error (fopen or malloc failure) + */ +void +config(const char *fname) +{ + TAG *tp; + FILE *cfp; + size_t len; + int lcnt; + char *p, *t, type; + + if (fname == NULL) + fname = _PATH_MANCONF; + if ((cfp = fopen(fname, "r")) == NULL) + err(EXIT_FAILURE, "%s", fname); + TAILQ_INIT(&head); + for (lcnt = 1; (p = fgetln(cfp, &len)) != NULL; ++lcnt) { + if (len == 1) /* Skip empty lines. */ + continue; + if (p[len - 1] != '\n') { /* Skip corrupted lines. */ + warnx("%s: line %d corrupted", fname, lcnt); + continue; + } + p[len - 1] = '\0'; /* Terminate the line. */ + + /* Skip leading space. */ + for (/*EMPTY*/; *p != '\0' && isspace((unsigned char)*p); ++p) + continue; + /* Skip empty/comment lines. */ + if (*p == '\0' || *p == '#') + continue; + /* Find first token. */ + for (t = p; *t && !isspace((unsigned char)*t); ++t) + continue; + if (*t == '\0') /* Need more than one token.*/ + continue; + *t = '\0'; + + tp = gettag(p, 1); + if (!tp) + errx(EXIT_FAILURE, "gettag: malloc failed"); + + /* + * Attach new records. Check to see if it is a + * section record or not. + */ + + if (*p == '_') { /* not a section record */ + /* + * Special cases: _build and _crunch take the + * rest of the line as a single entry. + */ + if (!strcmp(p, "_build") || !strcmp(p, "_crunch")) { + /* + * The reason we're not just using + * strtok(3) for all of the parsing is + * so we don't get caught if a line + * has only a single token on it. + */ + while (*++t && isspace((unsigned char)*t)); + if (addentry(tp, t, 0) == -1) + errx(EXIT_FAILURE, + "addentry: malloc failed"); + } else { + for (++t; (p = strtok(t, " \t\n")) != NULL; + t = NULL) { + if (addentry(tp, p, 0) == -1) + errx(EXIT_FAILURE, + "addentry: malloc failed"); + } + } + + } else { /* section record */ + + /* + * section entries can either be all absolute + * paths or all relative paths, but not both. + */ + type = (TAILQ_FIRST(&tp->entrylist) != NULL) ? + *(TAILQ_FIRST(&tp->entrylist)->s) : 0; + + for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) { + + /* ensure an assigned type */ + if (type == 0) + type = *p; + + /* check for illegal mix */ + if (*p != type) { + warnx("section %s: %s: invalid entry, does not match previous types", + tp->s, p); + warnx("man.conf cannot mix absolute and relative paths in an entry"); + continue; + } + if (addentry(tp, p, 0) == -1) + errx(EXIT_FAILURE, + "addentry: malloc failed"); + } + } + } + (void)fclose(cfp); +} + +/* + * gettag -- + * if (!create) return tag for given name if it exists, or NULL otherwise + * + * if (create) return tag for given name if it exists, try and create + * a new tag if it does not exist. return NULL if unable to create new + * tag. + */ +TAG * +gettag(const char *name, int create) +{ + TAG *tp; + + TAILQ_FOREACH(tp, &head, q) + if (!strcmp(name, tp->s)) + return tp; + if (!create) + return NULL; + + /* try and add it in */ + tp = malloc(sizeof(*tp)); + if (tp) + tp->s = xstrdup(name, &tp->len); + if (!tp || !tp->s) { + if (tp) + free(tp); + return NULL; + } + TAILQ_INIT(&tp->entrylist); + TAILQ_INSERT_TAIL(&head, tp, q); + return tp; +} + +/* + * addentry -- + * add an entry to a list. + * returns -1 if malloc failed, otherwise 0. + */ +int +addentry(TAG *tp, const char *newent, int ishead) +{ + ENTRY *ep; + + ep = malloc(sizeof(*ep)); + if (ep) + ep->s = xstrdup(newent, &ep->len); + if (!ep || !ep->s) { + if (ep) + free(ep); + return -1; + } + if (ishead) + TAILQ_INSERT_HEAD(&tp->entrylist, ep, q); + else + TAILQ_INSERT_TAIL(&tp->entrylist, ep, q); + + return 0; +} diff --git a/commands/man/manconf.h b/commands/man/manconf.h new file mode 100644 index 000000000..ab8772887 --- /dev/null +++ b/commands/man/manconf.h @@ -0,0 +1,60 @@ +/* $NetBSD: manconf.h,v 1.3 2006/04/10 14:39:06 chuck Exp $ */ + +/*- + * Copyright (c) 1993 + * 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. + * + * @(#)config.h 8.4 (Berkeley) 12/18/93 + */ + +/* + * manconf.h: common data structures and APIs shared across all programs + * that access man.conf (currently: apropos, catman, makewhatis, man, and + * whatis). + */ + +/* TAG: top-level structure (one per section/reserved word) */ +typedef struct _tag { + TAILQ_ENTRY(_tag) q; /* Queue of tags */ + + TAILQ_HEAD(tqh, _entry) entrylist; /* Queue of entries */ + char *s; /* Associated string */ + size_t len; /* Length of 's' */ +} TAG; + +/* ENTRY: each TAG has one or more ENTRY strings linked off of it */ +typedef struct _entry { + TAILQ_ENTRY(_entry) q; /* Queue of entries */ + + char *s; /* Associated string */ + size_t len; /* Length of 's' */ +} ENTRY; + +int addentry(TAG *, const char *, int); +void config(const char *); +TAG *gettag(const char *, int); diff --git a/commands/man/pathnames.h b/commands/man/pathnames.h new file mode 100644 index 000000000..6de096bf6 --- /dev/null +++ b/commands/man/pathnames.h @@ -0,0 +1,39 @@ +/* $NetBSD: pathnames.h,v 1.5 2003/08/07 11:15:11 agc Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * 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. + * + * @(#)pathnames.h 8.3 (Berkeley) 1/2/94 + */ + +#include + +#define _PATH_MANCONF "/etc/man.conf" +#define _PATH_PAGER "/usr/bin/more -s" +#define _PATH_WHATIS "whatis.db" +#define TMPFILE "man.XXXXXX"