modified man(1):

- avoid double slashes when displaying man pages (got tired
   of '/usr/share/man//cat1/man.0').
 - got rid of __P() while working on it.
 - incorporate some of my old notes explaining how manpath works into the
   comments of the code itself.
 - renamed some of the vars so that the code is consistent throughout
   (and hopefully clearer and easier to understand)
 - fixed relative man paths for multiple man pages (man did a chdir()
   on the first man page it had to format --- this broke any remaining
   relative path man pages left to process).   save old directory and
   fchdir() back to it after formatting.
 - improved doc on "man -h" which does more than just whatis(1) [e.g.
   "man -h fopen" prints the required include files and the prototypes
   rather than just the one-liner you get with whatis(1)]
 - manconf.c now fills in the "len" length field in the TAG/ENTRY
   structures (man now uses len).

revise man.conf file reading stuff to return error on failure in
addentry/gettag (fka getlist) rather than just err()ing out.   this
allows man(1) to call cleanup and delete its tmp files rather than
just leave them floating.  revise other apps using this code
(makewhatis, apropos, catman, whatis) to expect this.  also remove
__P on updated files.
This commit is contained in:
chuck 2006-04-10 14:39:06 +00:00
parent f7a378cb65
commit d09fe2c467
7 changed files with 535 additions and 399 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: makewhatis.c,v 1.38 2005/11/18 17:12:09 christos Exp $ */ /* $NetBSD: makewhatis.c,v 1.39 2006/04/10 14:39:06 chuck Exp $ */
/*- /*-
* Copyright (c) 1999 The NetBSD Foundation, Inc. * Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -44,7 +44,7 @@
#if !defined(lint) #if !defined(lint)
__COPYRIGHT("@(#) Copyright (c) 1999 The NetBSD Foundation, Inc.\n\ __COPYRIGHT("@(#) Copyright (c) 1999 The NetBSD Foundation, Inc.\n\
All rights reserved.\n"); All rights reserved.\n");
__RCSID("$NetBSD: makewhatis.c,v 1.38 2005/11/18 17:12:09 christos Exp $"); __RCSID("$NetBSD: makewhatis.c,v 1.39 2006/04/10 14:39:06 chuck Exp $");
#endif /* not lint */ #endif /* not lint */
#include <sys/types.h> #include <sys/types.h>
@ -180,14 +180,14 @@ main(int argc, char *const *argv)
* if man.conf not available. * if man.conf not available.
*/ */
config(conffile); config(conffile);
if ((tp = getlist("_whatdb", 0)) == NULL) { if ((tp = gettag("_whatdb", 0)) == NULL) {
manpath = default_manpath; manpath = default_manpath;
goto mkwhatis; goto mkwhatis;
} }
/* Build individual databases */ /* Build individual databases */
paths[1] = NULL; paths[1] = NULL;
TAILQ_FOREACH(ep, &tp->list, q) { TAILQ_FOREACH(ep, &tp->entrylist, q) {
if ((rv = glob(ep->s, if ((rv = glob(ep->s,
GLOB_BRACE | GLOB_NOSORT | GLOB_ERR | GLOB_NOCHECK, GLOB_BRACE | GLOB_NOSORT | GLOB_ERR | GLOB_NOCHECK,
NULL, &pg)) != 0) NULL, &pg)) != 0)

View File

@ -1,4 +1,4 @@
/* $NetBSD: apropos.c,v 1.26 2005/09/17 19:18:31 elad Exp $ */ /* $NetBSD: apropos.c,v 1.27 2006/04/10 14:39:06 chuck Exp $ */
/* /*
* Copyright (c) 1987, 1993, 1994 * Copyright (c) 1987, 1993, 1994
@ -40,7 +40,7 @@ __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\n\
#if 0 #if 0
static char sccsid[] = "@(#)apropos.c 8.8 (Berkeley) 5/4/95"; static char sccsid[] = "@(#)apropos.c 8.8 (Berkeley) 5/4/95";
#else #else
__RCSID("$NetBSD: apropos.c,v 1.26 2005/09/17 19:18:31 elad Exp $"); __RCSID("$NetBSD: apropos.c,v 1.27 2006/04/10 14:39:06 chuck Exp $");
#endif #endif
#endif /* not lint */ #endif /* not lint */
@ -114,8 +114,10 @@ main(int argc, char *argv[])
apropos(argv, p_path, 1); apropos(argv, p_path, 1);
else { else {
config(conffile); config(conffile);
tp = getlist("_whatdb", 1); tp = gettag("_whatdb", 1);
TAILQ_FOREACH(ep, &tp->list, q) { if (!tp)
errx(EXIT_FAILURE, "malloc");
TAILQ_FOREACH(ep, &tp->entrylist, q) {
if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL, if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL,
&pg)) != 0) { &pg)) != 0) {
if (rv == GLOB_NOMATCH) if (rv == GLOB_NOMATCH)
@ -154,7 +156,8 @@ apropos(char **argv, char *path, int buildpath)
*end++ = '\0'; *end++ = '\0';
if (buildpath) { if (buildpath) {
(void)snprintf(hold, sizeof(hold), "%s/%s", name, _PATH_WHATIS); (void)snprintf(hold, sizeof(hold), "%s/%s", name,
_PATH_WHATIS);
name = hold; name = hold;
} }

View File

@ -1,4 +1,4 @@
/* $NetBSD: man.c,v 1.32 2006/04/08 23:27:03 christos Exp $ */ /* $NetBSD: man.c,v 1.33 2006/04/10 14:39:06 chuck Exp $ */
/* /*
* Copyright (c) 1987, 1993, 1994, 1995 * Copyright (c) 1987, 1993, 1994, 1995
@ -40,7 +40,7 @@ __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994, 1995\n\
#if 0 #if 0
static char sccsid[] = "@(#)man.c 8.17 (Berkeley) 1/31/95"; static char sccsid[] = "@(#)man.c 8.17 (Berkeley) 1/31/95";
#else #else
__RCSID("$NetBSD: man.c,v 1.32 2006/04/08 23:27:03 christos Exp $"); __RCSID("$NetBSD: man.c,v 1.33 2006/04/10 14:39:06 chuck Exp $");
#endif #endif
#endif /* not lint */ #endif /* not lint */
@ -63,60 +63,95 @@ __RCSID("$NetBSD: man.c,v 1.32 2006/04/08 23:27:03 christos Exp $");
#include "manconf.h" #include "manconf.h"
#include "pathnames.h" #include "pathnames.h"
int f_all, f_where; #ifndef MAN_DEBUG
#define MAN_DEBUG 0 /* debug path output */
int main __P((int, char **));
static void build_page __P((char *, char **));
static void cat __P((char *));
static const char *check_pager __P((const char *));
static int cleanup __P((void));
static void how __P((char *));
static void jump __P((char **, char *, char *));
static int manual __P((char *, TAG *, glob_t *, const char *));
static void onsig __P((int));
static void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
TAG *defp, *section, *newpathp, *subp;
ENTRY *e_defp, *e_subp;
glob_t pg;
size_t len;
int ch, f_cat, f_how, found, abs_section;
char **ap, *cmd, *p, *p_add, *p_path;
const char *machine, *pager, *conffile, *pathsearch, *sectionname;
char buf[MAXPATHLEN * 2];
#ifdef __GNUC__
pager = NULL; /* XXX gcc -Wuninitialized */
#endif #endif
f_cat = f_how = 0; /*
sectionname = pathsearch = conffile = p_add = p_path = NULL; * 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; /* <sec>: 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) while ((ch = getopt(argc, argv, "-aC:cfhkM:m:P:s:S:w")) != -1)
switch (ch) { switch (ch) {
case 'a': case 'a':
f_all = 1; m.all = 1;
break; break;
case 'C': case 'C':
conffile = optarg; m.conffile = optarg;
break; break;
case 'c': case 'c':
case '-': /* Deprecated. */ case '-': /* XXX: '-' is a deprecated version of '-c' */
f_cat = 1; m.cat = 1;
break; break;
case 'h': case 'h':
f_how = 1; m.how = 1;
break; break;
case 'm': case 'm':
p_add = optarg; m.addpath = optarg;
break; break;
case 'M': case 'M':
case 'P': /* Backward compatibility. */ case 'P': /* -P for backward compatibility */
p_path = strdup(optarg); m.manpath = strdup(optarg);
break; break;
/* /*
* The -f and -k options are backward compatible, * The -f and -k options are backward compatible,
@ -129,15 +164,15 @@ main(argc, argv)
jump(argv, "-k", "apropos"); jump(argv, "-k", "apropos");
/* NOTREACHED */ /* NOTREACHED */
case 's': case 's':
if (sectionname != NULL) if (m.sectionname != NULL)
usage(); usage();
sectionname = optarg; m.sectionname = optarg;
break; break;
case 'S': case 'S':
pathsearch = optarg; m.pathsearch = optarg;
break; break;
case 'w': case 'w':
f_all = f_where = 1; m.all = m.where = 1;
break; break;
case '?': case '?':
default: default:
@ -149,22 +184,13 @@ main(argc, argv)
if (!argc) if (!argc)
usage(); usage();
if (!f_cat && !f_how && !f_where) { /*
if (!isatty(STDOUT_FILENO)) { * read the configuration file and collect any other information
f_cat = 1; * we will need (machine type, pager, section [if specified
} else { * without '-s'], and MANPATH through the environment).
if ((pager = getenv("PAGER")) != NULL && */
pager[0] != '\0') config(m.conffile); /* exits on error ... */
pager = check_pager(pager);
else
pager = _PATH_PAGER;
}
}
/* Read the configuration file. */
config(conffile);
/* Get the machine type. */
if ((machine = getenv("MACHINE")) == NULL) { if ((machine = getenv("MACHINE")) == NULL) {
struct utsname utsname; struct utsname utsname;
@ -175,122 +201,194 @@ main(argc, argv)
machine = utsname.machine; machine = utsname.machine;
} }
/* create an empty _default list if the config file didn't have one */ if (!m.cat && !m.how && !m.where) { /* if we need a pager ... */
defp = getlist("_default", 1); 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);
}
}
/* if -M wasn't specified, check for MANPATH */ /* do we need to set m.section to a non-null value? */
if (p_path == NULL) if (m.sectionname) {
p_path = getenv("MANPATH");
/* m.section = gettag(m.sectionname, 0); /* -s must be a section */
* get section. abs_section will be non-zero iff the user if (m.section == NULL)
* specified a section and it had absolute (rather than errx(1, "unknown section: %s", m.sectionname);
* relative) paths in the man.conf file.
*/ } else if (argc > 1) {
if ((argc > 1 || sectionname != NULL) &&
(section = getlist(sectionname ? sectionname : *argv, 0)) != NULL) { m.section = gettag(*argv, 0); /* might be a section? */
if (sectionname == NULL) { if (m.section) {
argv++; argv++;
argc--; argc--;
} }
abs_section = (! TAILQ_EMPTY(&section->list) &&
*(TAILQ_FIRST(&section->list)->s) == '/');
} else {
section = NULL;
abs_section = 0;
} }
/* get subdir list */ if (m.manpath == NULL)
subp = getlist("_subdir", 1); m.manpath = getenv("MANPATH"); /* note: -M overrides getenv */
/* /*
* now that we have all the inputs we must generate a search path. * 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");
/* /*
* 1: If user specified a section and it has absolute paths * are we using a section whose elements are all absolute paths?
* in the config file, then that overrides _default, MANPATH and * (we only need to look at the first entry on the section list,
* path passed via -M. * 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) { if (abs_section) {
p_path = NULL; /* zap -M/MANPATH */ m.manpath = NULL; /* ignore -M/MANPATH */
defp = section; /* zap _default */ m.defaultpath = m.section; /* overwrite _default path */
section = NULL; /* promoted to defp */ m.section = NULL; /* promoted to defaultpath */
} }
/* /*
* 2: Section can be non-null only if a section was specified * [2] section can now only be non-null if the user asked for
* and the config file has relative paths - the section list * a section and that section's elements did not have
* overrides _subdir in this case. * absolute paths. in this case we use the section's
*/ * elements to override _subdir from the config file.
if (section)
subp = section;
/*
* 3: now we either have text string path (p_path) or a tag
* based path (defp). we need to append subp and machine
* to each element in the path.
* *
* for backward compat, we do not append subp if abs_section * after this step, we are done processing "m.section"...
* and the path does not end in "/".
*/ */
newpathp = getlist("_new_path", 1); if (m.section)
if (p_path) { m.subdirs = m.section;
/* use p_path */
for (; (p = strtok(p_path, ":")) != NULL; p_path = NULL) { /*
TAILQ_FOREACH(e_subp, &subp->list, q) { * [3] we need to setup the path we want to use (m.mymanpath).
snprintf(buf, sizeof(buf), "%s/%s{/%s,}", * if the user gave us a path (m.manpath) use it, otherwise
p, e_subp->s, machine); * go with the default. in either case we need to append
addentry(newpathp, buf, 0); * 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 {
/* use defp rather than p_path */
TAILQ_FOREACH(e_defp, &defp->list, q) {
} else {
TAILQ_FOREACH(epath, &m.defaultpath->entrylist, q) {
/* handle trailing "/" magic here ... */ /* handle trailing "/" magic here ... */
if (abs_section && if (abs_section &&
e_defp->s[strlen(e_defp->s) - 1] != '/') { epath->s[epath->len - 1] != '/') {
(void)snprintf(buf, sizeof(buf), (void)snprintf(buf, sizeof(buf),
"%s{/%s,}", e_defp->s, machine); "%s{/%s,}", epath->s, machine);
addentry(newpathp, buf, 0); if (addentry(m.mymanpath, buf, 0) < 0)
errx(1, "malloc failed");
continue; continue;
} }
TAILQ_FOREACH(e_subp, &subp->list, q) { TAILQ_FOREACH(esubd, &m.subdirs->entrylist, q) {
snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
e_defp->s, (abs_section) ? "" : "/", epath->s,
e_subp->s, machine); (epath->s[epath->len-1] == '/') ? ""
addentry(newpathp, buf, 0); : "/",
esubd->s, machine);
if (addentry(m.mymanpath, buf, 0) < 0)
errx(1, "malloc failed");
} }
} }
} /* using defp ... */
/* now replace the current path with the new one */ }
defp = newpathp;
/* /*
* 4: prepend the "-m" path, if specified. we always add * [4] finally, prepend the "-m" m.addpath to mymanpath if it
* subp and machine to this part of the path. * was specified. subdirs and machine are always applied to
* m.addpath.
*/ */
if (m.addpath) {
if (p_add) { /* note: strtok is going to destroy m.addpath */
for (p = strtok(p_add, ":") ; p ; p = strtok(NULL, ":")) { for (p = strtok(m.addpath, ":") ; p ; p = strtok(NULL, ":")) {
TAILQ_FOREACH(e_subp, &subp->list, q) { len = strlen(p);
snprintf(buf, sizeof(buf), "%s/%s{/%s,}", if (len < 1)
p, e_subp->s, machine); continue;
addentry(newpathp, buf, 1); 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);
}
} }
/* /*
* 5: Search for the files. Set up an interrupt handler, so the * start searching for matching files and format them if necessary.
* temporary files go away. * setup an interrupt handler so that we can ensure that temporary
* files go away.
*/ */
(void)signal(SIGINT, onsig); (void)signal(SIGINT, onsig);
(void)signal(SIGHUP, onsig); (void)signal(SIGHUP, onsig);
@ -298,17 +396,20 @@ main(argc, argv)
memset(&pg, 0, sizeof(pg)); memset(&pg, 0, sizeof(pg));
for (found = 0; *argv; ++argv) for (found = 0; *argv; ++argv)
if (manual(*argv, defp, &pg, pathsearch)) if (manual(*argv, &m, &pg)) {
found = 1; found = 1;
}
/* 6: If nothing found, we're done. */ /* if nothing found, we're done. */
if (!found) { if (!found) {
(void)cleanup(); (void)cleanup();
exit (1); exit (1);
} }
/* 7: If it's simple, display it fast. */ /*
if (f_cat) { * handle the simple display cases first (m.cat, m.how, m.where)
*/
if (m.cat) {
for (ap = pg.gl_pathv; *ap != NULL; ++ap) { for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
if (**ap == '\0') if (**ap == '\0')
continue; continue;
@ -316,7 +417,7 @@ main(argc, argv)
} }
exit (cleanup()); exit (cleanup());
} }
if (f_how) { if (m.how) {
for (ap = pg.gl_pathv; *ap != NULL; ++ap) { for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
if (**ap == '\0') if (**ap == '\0')
continue; continue;
@ -324,7 +425,7 @@ main(argc, argv)
} }
exit(cleanup()); exit(cleanup());
} }
if (f_where) { if (m.where) {
for (ap = pg.gl_pathv; *ap != NULL; ++ap) { for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
if (**ap == '\0') if (**ap == '\0')
continue; continue;
@ -334,10 +435,11 @@ main(argc, argv)
} }
/* /*
* 8: We display things in a single command; build a list of things * normal case - we display things in a single command, so
* to display. * 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 = strlen(pager) + 1; *ap != NULL; ++ap) { for (ap = pg.gl_pathv, len = m.pagerlen + 1; *ap != NULL; ++ap) {
if (**ap == '\0') if (**ap == '\0')
continue; continue;
len += strlen(*ap) + 1; len += strlen(*ap) + 1;
@ -347,16 +449,18 @@ main(argc, argv)
(void)cleanup(); (void)cleanup();
exit(1); exit(1);
} }
/* now build the command string... */
p = cmd; p = cmd;
len = strlen(pager); len = m.pagerlen;
memmove(p, pager, len); memcpy(p, m.pager, len);
p += len; p += len;
*p++ = ' '; *p++ = ' ';
for (ap = pg.gl_pathv; *ap != NULL; ++ap) { for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
if (**ap == '\0') if (**ap == '\0')
continue; continue;
len = strlen(*ap); len = strlen(*ap);
memmove(p, *ap, len); memcpy(p, *ap, len);
p += len; p += len;
*p++ = ' '; *p++ = ' ';
} }
@ -373,21 +477,15 @@ main(argc, argv)
* Search the manuals for the pages. * Search the manuals for the pages.
*/ */
static int static int
manual(page, tag, pg, pathsearch) manual(char *page, struct manstate *mp, glob_t *pg)
char *page;
TAG *tag;
glob_t *pg;
const char *pathsearch;
{ {
ENTRY *ep, *e_sufp, *e_tag; ENTRY *suffix, *mdir;
TAG *missp, *sufp;
int anyfound, error, found; int anyfound, error, found;
size_t cnt; size_t cnt;
char *p, buf[MAXPATHLEN], *escpage, *eptr; char *p, buf[MAXPATHLEN], *escpage, *eptr;
static const char escglob[] = "\\~?*{}[]"; static const char escglob[] = "\\~?*{}[]";
anyfound = 0; anyfound = 0;
buf[0] = '*';
/* /*
* Fixup page which may contain glob(3) special characters, e.g. * Fixup page which may contain glob(3) special characters, e.g.
@ -412,9 +510,14 @@ manual(page, tag, pg, pathsearch)
*eptr = '\0'; *eptr = '\0';
/* For each element in the list... */ /* For each man directory in mymanpath ... */
TAILQ_FOREACH(e_tag, &tag->list, q) { TAILQ_FOREACH(mdir, &mp->mymanpath->entrylist, q) {
(void)snprintf(buf, sizeof(buf), "%s/%s.*", e_tag->s, escpage);
/*
* 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, if ((error = glob(buf,
GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT, NULL, pg)) != 0) { GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT, NULL, pg)) != 0) {
if (error == GLOB_NOMATCH) if (error == GLOB_NOMATCH)
@ -428,14 +531,20 @@ manual(page, tag, pg, pathsearch)
if (pg->gl_matchc == 0) if (pg->gl_matchc == 0)
continue; continue;
/* Find out if it's really a man page. */ /*
* 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; for (cnt = pg->gl_pathc - pg->gl_matchc;
cnt < pg->gl_pathc; ++cnt) { cnt < pg->gl_pathc; ++cnt) {
if (pathsearch) { /* filter on directory path name */
p = strstr(pg->gl_pathv[cnt], pathsearch); if (mp->pathsearch) {
p = strstr(pg->gl_pathv[cnt], mp->pathsearch);
if (!p || strchr(p, '/') == NULL) { if (!p || strchr(p, '/') == NULL) {
pg->gl_pathv[cnt] = ""; pg->gl_pathv[cnt] = ""; /* zap! */
continue; continue;
} }
} }
@ -453,12 +562,11 @@ manual(page, tag, pg, pathsearch)
if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) if (!fnmatch(buf, pg->gl_pathv[cnt], 0))
goto next; goto next;
sufp = getlist("_suffix", 1);
found = 0; found = 0;
TAILQ_FOREACH(e_sufp, &sufp->list, q) { TAILQ_FOREACH(suffix, &mp->suffixlist->entrylist, q) {
(void)snprintf(buf, (void)snprintf(buf,
sizeof(buf), "*/%s%s", escpage, sizeof(buf), "*/%s%s", escpage,
e_sufp->s); suffix->s);
if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) {
found = 1; found = 1;
break; break;
@ -468,10 +576,9 @@ manual(page, tag, pg, pathsearch)
goto next; goto next;
/* Try the _build key words next. */ /* Try the _build key words next. */
sufp = getlist("_build", 1);
found = 0; found = 0;
TAILQ_FOREACH(e_sufp, &sufp->list, q) { TAILQ_FOREACH(suffix, &mp->buildlist->entrylist, q) {
for (p = e_sufp->s; for (p = suffix->s;
*p != '\0' && !isspace((unsigned char)*p); *p != '\0' && !isspace((unsigned char)*p);
++p) ++p)
continue; continue;
@ -480,11 +587,11 @@ manual(page, tag, pg, pathsearch)
*p = '\0'; *p = '\0';
(void)snprintf(buf, (void)snprintf(buf,
sizeof(buf), "*/%s%s", escpage, sizeof(buf), "*/%s%s", escpage,
e_sufp->s); suffix->s);
if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) { if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) {
if (!f_where) if (!mp->where)
build_page(p + 1, build_page(p + 1,
&pg->gl_pathv[cnt]); &pg->gl_pathv[cnt], mp);
*p = ' '; *p = ' ';
found = 1; found = 1;
break; break;
@ -493,7 +600,7 @@ manual(page, tag, pg, pathsearch)
} }
if (found) { if (found) {
next: anyfound = 1; next: anyfound = 1;
if (!f_all) { if (!mp->all) {
/* Delete any other matches. */ /* Delete any other matches. */
while (++cnt< pg->gl_pathc) while (++cnt< pg->gl_pathc)
pg->gl_pathv[cnt] = ""; pg->gl_pathv[cnt] = "";
@ -506,20 +613,17 @@ next: anyfound = 1;
pg->gl_pathv[cnt] = ""; pg->gl_pathv[cnt] = "";
} }
if (anyfound && !f_all) if (anyfound && !mp->all)
break; break;
} }
/* If not found, enter onto the missing list. */ /* If not found, enter onto the missing list. */
if (!anyfound) { if (!anyfound) {
missp = getlist("_missing", 1); if (addentry(mp->missinglist, page, 0) < 0) {
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(page)) == NULL) {
warn("malloc"); warn("malloc");
(void)cleanup(); (void)cleanup();
exit(1); exit(1);
} }
TAILQ_INSERT_TAIL(&missp->list, ep, q);
} }
free(escpage); free(escpage);
@ -531,13 +635,10 @@ next: anyfound = 1;
* Build a man page for display. * Build a man page for display.
*/ */
static void static void
build_page(fmt, pathp) build_page(char *fmt, char **pathp, struct manstate *mp)
char *fmt, **pathp;
{ {
static int warned; static int warned;
ENTRY *ep; int olddir, fd, n, tmpdirlen;
TAG *intmpp;
int fd, n;
char *p, *b; char *p, *b;
char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[MAXPATHLEN]; char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[MAXPATHLEN];
const char *tmpdir; const char *tmpdir;
@ -562,21 +663,28 @@ build_page(fmt, pathp)
for (b = buf, p = *pathp; (*b++ = *p++) != '\0';) for (b = buf, p = *pathp; (*b++ = *p++) != '\0';)
continue; continue;
/* skip the last two path components, page name and man[n] */ /*
* 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--) for (--b, --p, n = 2; b != buf; b--, p--)
if (*b == '/') if (*b == '/')
if (--n == 0) { if (--n == 0) {
*b = '\0'; *b = '\0';
olddir = open(".", O_RDONLY);
(void) chdir(buf); (void) chdir(buf);
p++; p++;
break; break;
} }
/* Add a remove-when-done list. */ /* advance fmt pass the suffix spec to the printf format string */
intmpp = getlist("_intmp", 1);
/* Move to the printf(3) format string. */
for (; *fmt && isspace((unsigned char)*fmt); ++fmt) for (; *fmt && isspace((unsigned char)*fmt); ++fmt)
continue; continue;
@ -586,7 +694,9 @@ build_page(fmt, pathp)
*/ */
if ((tmpdir = getenv("TMPDIR")) == NULL) if ((tmpdir = getenv("TMPDIR")) == NULL)
tmpdir = _PATH_TMP; tmpdir = _PATH_TMP;
(void)snprintf(tpath, sizeof (tpath), "%s/%s", tmpdir, TMPFILE); tmpdirlen = strlen(tmpdir);
(void)snprintf(tpath, sizeof (tpath), "%s%s%s", tmpdir,
(tmpdirlen && tmpdir[tmpdirlen-1] == '/') ? "" : "/", TMPFILE);
if ((fd = mkstemp(tpath)) == -1) { if ((fd = mkstemp(tpath)) == -1) {
warn("%s", tpath); warn("%s", tpath);
(void)cleanup(); (void)cleanup();
@ -603,13 +713,17 @@ build_page(fmt, pathp)
} }
/* Link the built file into the remove-when-done list. */ /* Link the built file into the remove-when-done list. */
if ((ep = malloc(sizeof(ENTRY))) == NULL) { if (addentry(mp->intmp, *pathp, 0) < 0) {
warn("malloc"); warn("malloc");
(void)cleanup(); (void)cleanup();
exit(1); exit(1);
} }
ep->s = *pathp;
TAILQ_INSERT_TAIL(&intmpp->list, ep, q); /* restore old directory so relative manpaths still work */
if (olddir != -1) {
fchdir(olddir);
close(olddir);
}
} }
/* /*
@ -617,8 +731,7 @@ build_page(fmt, pathp)
* display how information * display how information
*/ */
static void static void
how(fname) how(char *fname)
char *fname;
{ {
FILE *fp; FILE *fp;
@ -662,8 +775,7 @@ how(fname)
* cat out the file * cat out the file
*/ */
static void static void
cat(fname) cat(char *fname)
char *fname;
{ {
int fd, n; int fd, n;
char buf[2048]; char buf[2048];
@ -692,8 +804,7 @@ cat(fname)
* check the user supplied page information * check the user supplied page information
*/ */
static const char * static const char *
check_pager(name) check_pager(const char *name)
const char *name;
{ {
const char *p; const char *p;
@ -722,8 +833,7 @@ check_pager(name)
* strip out flag argument and jump * strip out flag argument and jump
*/ */
static void static void
jump(argv, flag, name) jump(char **argv, char *flag, char *name)
char **argv, *flag, *name;
{ {
char **arg; char **arg;
@ -743,8 +853,7 @@ jump(argv, flag, name)
* If signaled, delete the temporary files. * If signaled, delete the temporary files.
*/ */
static void static void
onsig(signo) onsig(int signo)
int signo;
{ {
sigset_t set; sigset_t set;
@ -775,23 +884,21 @@ cleanup()
int rval; int rval;
rval = 0; rval = 0;
/* /*
* get missing list, but don't create missing _missing, * note that _missing and _intmp were created by main(), so
* as we don't want to try & allocate memory in getlist() * gettag() cannot return NULL here.
*/ */
if ((missp = getlist("_missing", 0)) != NULL) missp = gettag("_missing", 0); /* missing man pages */
TAILQ_FOREACH(ep, &missp->list, q) { intmpp = gettag("_intmp", 0); /* tmp files we need to unlink */
warnx("no entry for %s in the manual.", ep->s);
rval = 1; 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);
/*
* get tempfile list, but don't create missing _intmp,
* as we don't want to try & allocate memory in getlist()
*/
if ((intmpp = getlist("_intmp", 0)) != NULL)
TAILQ_FOREACH(ep, &intmpp->list, q)
(void)unlink(ep->s);
return (rval); return (rval);
} }
@ -802,8 +909,10 @@ cleanup()
static void static void
usage() usage()
{ {
(void)fprintf(stderr, "usage: %s [-acw|-h] [-C cfg] [-M path] "
(void)fprintf(stderr, "usage: %s [-achw] [-C file] [-M path] [-m path]" "[-m path] [-S srch] [[-s] sect] name ...\n", getprogname());
"[-S srch] [[-s] section] title ...\n", getprogname()); (void)fprintf(stderr,
"usage: %s -k [-C cfg] [-M path] [-m path] keyword ...\n",
getprogname());
exit(1); exit(1);
} }

View File

@ -1,4 +1,4 @@
/* $NetBSD: manconf.c,v 1.4 2003/10/27 00:12:43 lukem Exp $ */ /* $NetBSD: manconf.c,v 1.5 2006/04/10 14:39:06 chuck Exp $ */
/* /*
* Copyright (c) 1989, 1993, 1995 * Copyright (c) 1989, 1993, 1995
@ -29,6 +29,13 @@
* SUCH DAMAGE. * 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 #if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h" #include "nbtool_config.h"
#endif #endif
@ -38,7 +45,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)config.c 8.8 (Berkeley) 1/31/95"; static char sccsid[] = "@(#)config.c 8.8 (Berkeley) 1/31/95";
#else #else
__RCSID("$NetBSD: manconf.c,v 1.4 2003/10/27 00:12:43 lukem Exp $"); __RCSID("$NetBSD: manconf.c,v 1.5 2006/04/10 14:39:06 chuck Exp $");
#endif #endif
#endif /* not lint */ #endif /* not lint */
@ -55,21 +62,42 @@ __RCSID("$NetBSD: manconf.c,v 1.4 2003/10/27 00:12:43 lukem Exp $");
#include "manconf.h" #include "manconf.h"
#include "pathnames.h" #include "pathnames.h"
struct _head head; 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);
memcpy(copy, str, len);
if (lenp)
*lenp = len - 1; /* subtract out the null */
return(copy);
}
/* /*
* config -- * config --
* *
* Read the configuration file and build a doubly linked * Read the configuration file and build a doubly linked
* list that looks like: * list off of "head" that looks like:
* *
* tag1 <-> record <-> record <-> record * tag1 <-> entry <-> entry <-> entry
* | * |
* tag2 <-> record <-> record <-> record * tag2 <-> entry <-> entry <-> entry
*
* note: will err/errx out on error (fopen or malloc failure)
*/ */
void void
config(fname) config(const char *fname)
const char *fname;
{ {
TAG *tp; TAG *tp;
FILE *cfp; FILE *cfp;
@ -102,7 +130,9 @@ config(fname)
continue; continue;
*t = '\0'; *t = '\0';
tp = getlist(p, 1); tp = gettag(p, 1);
if (!tp)
errx(1, "gettag: malloc failed");
/* /*
* Attach new records. Check to see if it is a * Attach new records. Check to see if it is a
@ -122,11 +152,15 @@ config(fname)
* has only a single token on it. * has only a single token on it.
*/ */
while (*++t && isspace((unsigned char)*t)); while (*++t && isspace((unsigned char)*t));
addentry(tp, t, 0); if (addentry(tp, t, 0) < 0)
errx(1, "addentry: malloc failed");
} else { } else {
for(++t; (p = strtok(t, " \t\n")) != NULL; for(++t; (p = strtok(t, " \t\n")) != NULL;
t = NULL) t = NULL) {
addentry(tp, p, 0); if (addentry(tp, p, 0) < 0)
errx(1,
"addentry: malloc failed");
}
} }
} else { /* section record */ } else { /* section record */
@ -135,8 +169,8 @@ config(fname)
* section entries can either be all absolute * section entries can either be all absolute
* paths or all relative paths, but not both. * paths or all relative paths, but not both.
*/ */
type = (TAILQ_FIRST(&tp->list) != NULL) ? type = (TAILQ_FIRST(&tp->entrylist) != NULL) ?
*(TAILQ_FIRST(&tp->list)->s) : 0; *(TAILQ_FIRST(&tp->entrylist)->s) : 0;
for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) { for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) {
@ -151,7 +185,8 @@ config(fname)
warnx("man.conf cannot mix absolute and relative paths in an entry"); warnx("man.conf cannot mix absolute and relative paths in an entry");
continue; continue;
} }
addentry(tp, p, 0); if (addentry(tp, p, 0) < 0)
errx(1, "addentry: malloc failed");
} }
} }
} }
@ -160,66 +195,61 @@ config(fname)
} }
/* /*
* getlist -- * gettag --
* Return the linked list of entries for a tag if it exists. * if (!create) return tag for given name if it exists, or NULL otherwise
* If it doesn't exist and create is non zero, create new tag *
* and return that, otherwise return NULL. * 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 * TAG *
getlist(name, create) gettag(const char *name, int create)
const char *name;
int create;
{ {
TAG *tp; TAG *tp;
TAILQ_FOREACH(tp, &head, q) TAILQ_FOREACH(tp, &head, q)
if (!strcmp(name, tp->s)) if (!strcmp(name, tp->s))
return (tp); return (tp);
if (create) { if (!create)
if ((tp = malloc(sizeof(TAG))) == NULL || return(NULL);
(tp->s = strdup(name)) == NULL)
err(1, "malloc"); /* try and add it in */
TAILQ_INIT(&tp->list); tp = malloc(sizeof(*tp));
TAILQ_INSERT_TAIL(&head, tp, q); if (tp)
return (tp); tp->s = xstrdup(name, &tp->len);
} else if (!tp || !tp->s) {
return (NULL); if (tp)
free(tp);
return(NULL);
}
TAILQ_INIT(&tp->entrylist);
TAILQ_INSERT_TAIL(&head, tp, q);
return (tp);
} }
/* /*
* addentry -- * addentry --
* add an entry to a list. * add an entry to a list.
* returns -1 if malloc failed, otherwise 0.
*/ */
void int
addentry(tp, newent, head) addentry(TAG *tp, const char *newent, int head)
TAG *tp;
const char *newent;
int head;
{ {
ENTRY *ep; ENTRY *ep;
if ((ep = malloc(sizeof(*ep))) == NULL || ep = malloc(sizeof(*ep));
(ep->s = strdup(newent)) == NULL) if (ep)
err(1, "malloc"); ep->s = xstrdup(newent, &ep->len);
if (head) if (!ep || !ep->s) {
TAILQ_INSERT_HEAD(&tp->list, ep, q); if (ep)
else free(ep);
TAILQ_INSERT_TAIL(&tp->list, ep, q); return(-1);
}
#ifdef MANDEBUG
void
debug(l)
const char *l;
{
TAG *tp;
ENTRY *ep;
(void)printf("%s ===============\n", l);
TAILQ_FOREACH(tp, &head, q) {
printf("%s\n", tp->s);
TAILQ_FOREACH(ep, &tp->list, q)
printf("\t%s\n", ep->s);
} }
if (head)
TAILQ_INSERT_HEAD(&tp->entrylist, ep, q);
else
TAILQ_INSERT_TAIL(&tp->entrylist, ep, q);
return(0);
} }
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: manconf.h,v 1.2 2003/08/07 11:15:11 agc Exp $ */ /* $NetBSD: manconf.h,v 1.3 2006/04/10 14:39:06 chuck Exp $ */
/*- /*-
* Copyright (c) 1993 * Copyright (c) 1993
@ -32,28 +32,29 @@
* @(#)config.h 8.4 (Berkeley) 12/18/93 * @(#)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 { typedef struct _tag {
TAILQ_ENTRY(_tag) q; /* Queue of tags. */ TAILQ_ENTRY(_tag) q; /* Queue of tags */
TAILQ_HEAD(tqh, _entry) list; /* Queue of entries. */ TAILQ_HEAD(tqh, _entry) entrylist; /* Queue of entries */
char *s; /* Associated string. */ char *s; /* Associated string */
size_t len; /* Length of 's'. */ size_t len; /* Length of 's' */
} TAG; } TAG;
typedef struct _entry {
TAILQ_ENTRY(_entry) q; /* Queue of entries. */
char *s; /* Associated string. */ /* ENTRY: each TAG has one or more ENTRY strings linked off of it */
size_t len; /* Length of 's'. */ typedef struct _entry {
TAILQ_ENTRY(_entry) q; /* Queue of entries */
char *s; /* Associated string */
size_t len; /* Length of 's' */
} ENTRY; } ENTRY;
TAILQ_HEAD(_head, _tag); int addentry(TAG *, const char *, int);
extern struct _head head; void config(const char *);
TAG *gettag(const char *, int);
void addentry __P((TAG *, const char *, int));
void config __P((const char *));
#ifdef MANDEBUG
void debug __P((const char *));
#endif
TAG *getlist __P((const char *, int));
void removelist __P((const char *));
TAG *renamelist __P((const char *, const char *));

View File

@ -1,4 +1,4 @@
/* $NetBSD: whatis.c,v 1.20 2005/08/25 16:29:15 rpaulo Exp $ */ /* $NetBSD: whatis.c,v 1.21 2006/04/10 14:39:06 chuck Exp $ */
/* /*
* Copyright (c) 1987, 1993 * Copyright (c) 1987, 1993
@ -40,7 +40,7 @@ __COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
#if 0 #if 0
static char sccsid[] = "@(#)whatis.c 8.5 (Berkeley) 1/2/94"; static char sccsid[] = "@(#)whatis.c 8.5 (Berkeley) 1/2/94";
#else #else
__RCSID("$NetBSD: whatis.c,v 1.20 2005/08/25 16:29:15 rpaulo Exp $"); __RCSID("$NetBSD: whatis.c,v 1.21 2006/04/10 14:39:06 chuck Exp $");
#endif #endif
#endif /* not lint */ #endif /* not lint */
@ -62,16 +62,14 @@ __RCSID("$NetBSD: whatis.c,v 1.20 2005/08/25 16:29:15 rpaulo Exp $");
static int *found, foundman; static int *found, foundman;
int main __P((int, char **)); int main(int, char **);
void dashtrunc __P((char *, char *)); void dashtrunc(char *, char *);
int match __P((char *, char *)); int match(char *, char *);
void usage __P((void)); void usage(void);
void whatis __P((char **, char *, int)); void whatis(char **, char *, int);
int int
main(argc, argv) main(int argc, char **argv)
int argc;
char *argv[];
{ {
ENTRY *ep; ENTRY *ep;
TAG *tp; TAG *tp;
@ -117,8 +115,11 @@ main(argc, argv)
whatis(argv, p_path, 1); whatis(argv, p_path, 1);
else { else {
config(conffile); config(conffile);
tp = getlist("_whatdb", 0); tp = gettag("_whatdb", 0);
TAILQ_FOREACH(ep, &tp->list, q) { if (!tp)
errx(EXIT_FAILURE,
"no database dirs (_whatdb) in config file");
TAILQ_FOREACH(ep, &tp->entrylist, q) {
if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL, if ((rv = glob(ep->s, GLOB_BRACE | GLOB_NOSORT, NULL,
&pg)) != 0) { &pg)) != 0) {
if (rv == GLOB_NOMATCH) if (rv == GLOB_NOMATCH)
@ -147,9 +148,7 @@ main(argc, argv)
} }
void void
whatis(argv, path, buildpath) whatis(char **argv, char *path, int buildpath)
char **argv, *path;
int buildpath;
{ {
char *end, *name, **p; char *end, *name, **p;
char buf[MAXLINELEN + 1], wbuf[MAXLINELEN + 1]; char buf[MAXLINELEN + 1], wbuf[MAXLINELEN + 1];
@ -192,8 +191,7 @@ whatis(argv, path, buildpath)
* match a full word * match a full word
*/ */
int int
match(bp, str) match(char *bp, char *str)
char *bp, *str;
{ {
int len; int len;
char *start; char *start;
@ -220,8 +218,7 @@ match(bp, str)
* truncate a string at " - " * truncate a string at " - "
*/ */
void void
dashtrunc(from, to) dashtrunc(char *from, char *to)
char *from, *to;
{ {
int ch; int ch;
@ -236,7 +233,7 @@ dashtrunc(from, to)
* print usage message and die * print usage message and die
*/ */
void void
usage() usage(void)
{ {
(void)fprintf(stderr, (void)fprintf(stderr,
"usage: whatis [-C file] [-M path] [-m path] command ...\n"); "usage: whatis [-C file] [-M path] [-m path] command ...\n");

View File

@ -1,4 +1,4 @@
/* $NetBSD: catman.c,v 1.25 2006/03/26 18:11:22 christos Exp $ */ /* $NetBSD: catman.c,v 1.26 2006/04/10 14:39:06 chuck Exp $ */
/* /*
* Copyright (c) 1998 The NetBSD Foundation, Inc. * Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -67,24 +67,21 @@ int dowhatis = 0;
TAG *defp; /* pointer to _default list */ TAG *defp; /* pointer to _default list */
int main __P((int, char * const *)); int main(int, char * const *);
static void setdefentries __P((char *, char *, const char *)); static void setdefentries(char *, char *, const char *);
static void uniquepath __P((void)); static void uniquepath(void);
static void catman __P((void)); static void catman(void);
static void scanmandir __P((const char *, const char *)); static void scanmandir(const char *, const char *);
static int splitentry __P((char *, char *, size_t, char *, size_t)); static int splitentry(char *, char *, size_t, char *, size_t);
static void setcatsuffix __P((char *, const char *, const char *)); static void setcatsuffix(char *, const char *, const char *);
static void makecat __P((const char *, const char *, const char *, static void makecat(const char *, const char *, const char *, const char *);
const char *)); static void makewhatis(void);
static void makewhatis __P((void)); static void dosystem(const char *);
static void dosystem __P((const char *)); static void usage(void);
static void usage __P((void));
int int
main(argc, argv) main(int argc, char * const *argv)
int argc;
char * const *argv;
{ {
char *m_path = NULL; char *m_path = NULL;
char *m_add = NULL; char *m_add = NULL;
@ -140,10 +137,7 @@ main(argc, argv)
} }
static void static void
setdefentries(m_path, m_add, sections) setdefentries(char *m_path, char *m_add, const char *sections)
char *m_path;
char *m_add;
const char *sections;
{ {
TAG *defnewp, *sectnewp, *subp; TAG *defnewp, *sectnewp, *subp;
ENTRY *e_defp, *e_subp; ENTRY *e_defp, *e_subp;
@ -164,21 +158,24 @@ setdefentries(m_path, m_add, sections)
} }
/* If there's no _default list, create an empty one. */ /* If there's no _default list, create an empty one. */
defp = getlist("_default", 1); defp = gettag("_default", 1);
subp = gettag("_subdir", 1);
subp = getlist("_subdir", 1); if (defp == NULL || subp == NULL)
err(1, "malloc");
/* /*
* 0: If one or more sections was specified, rewrite _subdir list. * 0: If one or more sections was specified, rewrite _subdir list.
*/ */
if (sections != NULL) { if (sections != NULL) {
sectnewp = getlist("_section_new", 1); if ((sectnewp = gettag("_section_new", 1)) == NULL)
err(1, "malloc");
for (p = sections; *p;) { for (p = sections; *p;) {
i = snprintf(buf, sizeof(buf), "man%c", *p++); i = snprintf(buf, sizeof(buf), "man%c", *p++);
for (; *p && !isdigit((unsigned char)*p) && i < sizeof(buf) - 1; i++) for (; *p && !isdigit((unsigned char)*p) && i < sizeof(buf) - 1; i++)
buf[i] = *p++; buf[i] = *p++;
buf[i] = '\0'; buf[i] = '\0';
addentry(sectnewp, buf, 0); if (addentry(sectnewp, buf, 0) < 0)
err(1, "malloc");
} }
subp = sectnewp; subp = sectnewp;
} }
@ -191,19 +188,20 @@ setdefentries(m_path, m_add, sections)
if (m_path == NULL) if (m_path == NULL)
m_path = getenv("MANPATH"); m_path = getenv("MANPATH");
if (m_path != NULL) { if (m_path != NULL) {
while ((e_defp = TAILQ_FIRST(&defp->list)) != NULL) { while ((e_defp = TAILQ_FIRST(&defp->entrylist)) != NULL) {
free(e_defp->s); free(e_defp->s);
TAILQ_REMOVE(&defp->list, e_defp, q); TAILQ_REMOVE(&defp->entrylist, e_defp, q);
} }
for (p = strtok(m_path, ":"); for (p = strtok(m_path, ":");
p != NULL; p = strtok(NULL, ":")) { p != NULL; p = strtok(NULL, ":")) {
slashp = p[strlen(p) - 1] == '/' ? "" : "/"; slashp = p[strlen(p) - 1] == '/' ? "" : "/";
TAILQ_FOREACH(e_subp, &subp->list, q) { TAILQ_FOREACH(e_subp, &subp->entrylist, q) {
if (!strncmp(e_subp->s, "cat", 3)) if (!strncmp(e_subp->s, "cat", 3))
continue; continue;
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
p, slashp, e_subp->s, machine); p, slashp, e_subp->s, machine);
addentry(defp, buf, 0); if (addentry(defp, buf, 0) < 0)
err(1, "malloc");
} }
} }
} }
@ -213,18 +211,21 @@ setdefentries(m_path, m_add, sections)
* the _default list to include the _subdir list and the machine. * the _default list to include the _subdir list and the machine.
*/ */
if (m_path == NULL) { if (m_path == NULL) {
defp = getlist("_default", 1); defp = gettag("_default", 1);
defnewp = getlist("_default_new1", 1); defnewp = gettag("_default_new1", 1);
if (defp == NULL || defnewp == NULL)
err(1, "malloc");
TAILQ_FOREACH(e_defp, &defp->list, q) { TAILQ_FOREACH(e_defp, &defp->entrylist, q) {
slashp = slashp =
e_defp->s[strlen(e_defp->s) - 1] == '/' ? "" : "/"; e_defp->s[strlen(e_defp->s) - 1] == '/' ? "" : "/";
TAILQ_FOREACH(e_subp, &subp->list, q) { TAILQ_FOREACH(e_subp, &subp->entrylist, q) {
if (!strncmp(e_subp->s, "cat", 3)) if (!strncmp(e_subp->s, "cat", 3))
continue; continue;
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
e_defp->s, slashp, e_subp->s, machine); e_defp->s, slashp, e_subp->s, machine);
addentry(defnewp, buf, 0); if (addentry(defnewp, buf, 0) < 0)
err(1, "malloc");
} }
} }
defp = defnewp; defp = defnewp;
@ -238,12 +239,13 @@ setdefentries(m_path, m_add, sections)
if (m_add != NULL) if (m_add != NULL)
for (p = strtok(m_add, ":"); p != NULL; p = strtok(NULL, ":")) { for (p = strtok(m_add, ":"); p != NULL; p = strtok(NULL, ":")) {
slashp = p[strlen(p) - 1] == '/' ? "" : "/"; slashp = p[strlen(p) - 1] == '/' ? "" : "/";
TAILQ_FOREACH(e_subp, &subp->list, q) { TAILQ_FOREACH(e_subp, &subp->entrylist, q) {
if (!strncmp(e_subp->s, "cat", 3)) if (!strncmp(e_subp->s, "cat", 3))
continue; continue;
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}", (void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
p, slashp, e_subp->s, machine); p, slashp, e_subp->s, machine);
addentry(defp, buf, 1); if (addentry(defp, buf, 1) < 0)
err(1, "malloc");
} }
} }
} }
@ -269,13 +271,14 @@ uniquepath(void)
char path[PATH_MAX], *p; char path[PATH_MAX], *p;
gflags = 0; gflags = 0;
TAILQ_FOREACH(e_defp, &defp->list, q) { TAILQ_FOREACH(e_defp, &defp->entrylist, q) {
glob(e_defp->s, GLOB_BRACE | GLOB_NOSORT | gflags, NULL, glob(e_defp->s, GLOB_BRACE | GLOB_NOSORT | gflags, NULL,
&manpaths); &manpaths);
gflags = GLOB_APPEND; gflags = GLOB_APPEND;
} }
defnewp = getlist("_default_new2", 1); if ((defnewp = gettag("_default_new2", 1)) == NULL)
err(1, "malloc");
for (i = 0; i < manpaths.gl_pathc; i++) { for (i = 0; i < manpaths.gl_pathc; i++) {
lnk = 0; lnk = 0;
@ -308,8 +311,10 @@ uniquepath(void)
} }
} }
if (!lnk) if (!lnk) {
addentry(defnewp, manpaths.gl_pathv[i], 0); if (addentry(defnewp, manpaths.gl_pathv[i], 0) < 0)
err(1, "malloc");
}
} }
globfree(&manpaths); globfree(&manpaths);
@ -324,7 +329,7 @@ catman(void)
const char *mandir; const char *mandir;
char catdir[PATH_MAX], *cp; char catdir[PATH_MAX], *cp;
TAILQ_FOREACH(e_path, &defp->list, q) { TAILQ_FOREACH(e_path, &defp->entrylist, q) {
mandir = e_path->s; mandir = e_path->s;
strlcpy(catdir, mandir, sizeof(catdir)); strlcpy(catdir, mandir, sizeof(catdir));
if (!(cp = strstr(catdir, "man/man"))) if (!(cp = strstr(catdir, "man/man")))
@ -335,9 +340,7 @@ catman(void)
} }
static void static void
scanmandir(catdir, mandir) scanmandir(const char *catdir, const char *mandir)
const char *catdir;
const char *mandir;
{ {
TAG *buildp, *crunchp; TAG *buildp, *crunchp;
ENTRY *e_build, *e_crunch; ENTRY *e_build, *e_crunch;
@ -385,8 +388,9 @@ scanmandir(catdir, mandir)
snprintf(catpage, sizeof(catpage), "%s/%s", catdir, dp->d_name); snprintf(catpage, sizeof(catpage), "%s/%s", catdir, dp->d_name);
e_build = NULL; e_build = NULL;
buildp = getlist("_build", 1); if ((buildp = gettag("_build", 1)) == NULL)
TAILQ_FOREACH(e_build, &buildp->list, q) { err(1, "malloc");
TAILQ_FOREACH(e_build, &buildp->entrylist, q) {
splitentry(e_build->s, buildsuff, sizeof(buildsuff), splitentry(e_build->s, buildsuff, sizeof(buildsuff),
buildcmd, sizeof(buildcmd)); buildcmd, sizeof(buildcmd));
snprintf(match, sizeof(match), "*%s", snprintf(match, sizeof(match), "*%s",
@ -399,8 +403,9 @@ scanmandir(catdir, mandir)
continue; continue;
e_crunch = NULL; e_crunch = NULL;
crunchp = getlist("_crunch", 1); if ((crunchp = gettag("_crunch", 1)) == NULL)
TAILQ_FOREACH(e_crunch, &crunchp->list, q) { err(1, "malloc");
TAILQ_FOREACH(e_crunch, &crunchp->entrylist, q) {
splitentry(e_crunch->s, crunchsuff, sizeof(crunchsuff), splitentry(e_crunch->s, crunchsuff, sizeof(crunchsuff),
crunchcmd, sizeof(crunchcmd)); crunchcmd, sizeof(crunchcmd));
snprintf(match, sizeof(match), "*%s", crunchsuff); snprintf(match, sizeof(match), "*%s", crunchsuff);
@ -518,12 +523,8 @@ scanmandir(catdir, mandir)
} }
static int static int
splitentry(s, first, firstlen, second, secondlen) splitentry(char *s, char *first, size_t firstlen, char *second,
char *s; size_t secondlen)
char *first;
size_t firstlen;
char *second;
size_t secondlen;
{ {
char *c; char *c;
@ -543,20 +544,18 @@ splitentry(s, first, firstlen, second, secondlen)
} }
static void static void
setcatsuffix(catpage, suffix, crunchsuff) setcatsuffix(char *catpage, const char *suffix, const char *crunchsuff)
char *catpage;
const char *suffix;
const char *crunchsuff;
{ {
TAG *tp; TAG *tp;
char *p; char *p;
for (p = catpage + strlen(catpage); p != catpage; p--) for (p = catpage + strlen(catpage); p != catpage; p--)
if (!fnmatch(suffix, p, 0)) { if (!fnmatch(suffix, p, 0)) {
tp = getlist("_suffix", 1); if ((tp = gettag("_suffix", 1)) == NULL)
if (! TAILQ_EMPTY(&tp->list)) { err(1, "malloc");
if (! TAILQ_EMPTY(&tp->entrylist)) {
sprintf(p, "%s%s", sprintf(p, "%s%s",
TAILQ_FIRST(&tp->list)->s, crunchsuff); TAILQ_FIRST(&tp->entrylist)->s, crunchsuff);
} else { } else {
sprintf(p, ".0%s", crunchsuff); sprintf(p, ".0%s", crunchsuff);
} }
@ -565,11 +564,8 @@ setcatsuffix(catpage, suffix, crunchsuff)
} }
static void static void
makecat(manpage, catpage, buildcmd, crunchcmd) makecat(const char *manpage, const char *catpage, const char *buildcmd,
const char *manpage; const char *crunchcmd)
const char *catpage;
const char *buildcmd;
const char *crunchcmd;
{ {
char crunchbuf[1024]; char crunchbuf[1024];
char sysbuf[2048]; char sysbuf[2048];
@ -596,8 +592,9 @@ makewhatis(void)
ENTRY *e_whatdb; ENTRY *e_whatdb;
char sysbuf[1024]; char sysbuf[1024];
whatdbp = getlist("_whatdb", 1); if ((whatdbp = gettag("_whatdb", 1)) == NULL)
TAILQ_FOREACH(e_whatdb, &whatdbp->list, q) { err(1, "malloc");
TAILQ_FOREACH(e_whatdb, &whatdbp->entrylist, q) {
snprintf(sysbuf, sizeof(sysbuf), "%s %s", snprintf(sysbuf, sizeof(sysbuf), "%s %s",
_PATH_WHATIS, dirname(e_whatdb->s)); _PATH_WHATIS, dirname(e_whatdb->s));
if (f_noprint == 0) if (f_noprint == 0)
@ -608,8 +605,7 @@ makewhatis(void)
} }
static void static void
dosystem(cmd) dosystem(const char *cmd)
const char *cmd;
{ {
int status; int status;