allow to specify relative paths for sections in man.conf - they are used

similarily to _subdir, but only when appropriate
fix -m handling, so that e.g. "man -m . 3 printf" works as it should
add new -S flag, to specify a string the result path has to contain
g/c some unused stuff

Written by Chuck Cranor, with only cosmetic changes & const poisoning by me.
This commit is contained in:
jdolecek 2000-05-27 21:33:26 +00:00
parent 8293b12111
commit c1f28b097c
5 changed files with 237 additions and 197 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: config.c,v 1.10 1999/04/04 16:57:36 dante Exp $ */
/* $NetBSD: config.c,v 1.11 2000/05/27 21:33:26 jdolecek Exp $ */
/*
* Copyright (c) 1989, 1993, 1995
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)config.c 8.8 (Berkeley) 1/31/95";
#else
__RCSID("$NetBSD: config.c,v 1.10 1999/04/04 16:57:36 dante Exp $");
__RCSID("$NetBSD: config.c,v 1.11 2000/05/27 21:33:26 jdolecek Exp $");
#endif
#endif /* not lint */
@ -69,14 +69,13 @@ struct _head head;
*/
void
config(fname)
char *fname;
const char *fname;
{
TAG *tp;
ENTRY *ep;
FILE *cfp;
size_t len;
int lcnt;
char *p, *t;
char *p, *t, type;
if (fname == NULL)
fname = _PATH_MANCONF;
@ -103,31 +102,59 @@ config(fname)
continue;
*t = '\0';
for (tp = head.tqh_first; /* Find any matching tag. */
tp != NULL && strcmp(p, tp->s); tp = tp->q.tqe_next);
tp = getlist(p);
if (tp == NULL) /* Create a new tag. */
tp = addlist(p);
/*
* Attach new records. The keywords _build and _crunch takes
* the rest of the line as a single entity, everything else is
* whitespace separated.
* 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.
* Attach new records. Check to see if it is a
* section record or not.
*/
if (!strcmp(p, "_build") || !strcmp(p, "_crunch")) {
while (*++t && isspace((unsigned char)*t));
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(t)) == NULL)
err(1, "malloc");
TAILQ_INSERT_TAIL(&tp->list, ep, q);
} else for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) {
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(p)) == NULL)
err(1, "malloc");
TAILQ_INSERT_TAIL(&tp->list, ep, q);
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));
addentry(tp, t, 0);
} else {
for(++t; (p = strtok(t, " \t\n")) != NULL;
t = NULL)
addentry(tp, p, 0);
}
} else { /* section record */
/*
* section entries can either be all absolute
* paths or all relative paths, but not both.
*/
type = (TAILQ_FIRST(&tp->list) != NULL) ?
*(TAILQ_FIRST(&tp->list)->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;
}
addentry(tp, p, 0);
}
}
}
@ -136,15 +163,16 @@ config(fname)
/*
* addlist --
* Add a tag to the list.
* Add a tag to the list. caller should check for duplicate
* before calling (we don't).
*/
TAG *
addlist(name)
char *name;
const char *name;
{
TAG *tp;
if ((tp = calloc(1, sizeof(TAG))) == NULL ||
if ((tp = malloc(sizeof(TAG))) == NULL ||
(tp->s = strdup(name)) == NULL)
err(1, "malloc");
TAILQ_INIT(&tp->list);
@ -158,7 +186,7 @@ addlist(name)
*/
TAG *
getlist(name)
char *name;
const char *name;
{
TAG *tp;
@ -168,41 +196,31 @@ getlist(name)
return (NULL);
}
/*
* addentry --
* add an entry to a list.
*/
void
removelist(name)
char *name;
{
addentry(tp, newent, head)
TAG *tp;
const char *newent;
int head;
{
ENTRY *ep;
tp = getlist(name);
while ((ep = tp->list.tqh_first) != NULL) {
free(ep->s);
TAILQ_REMOVE(&tp->list, ep, q);
}
free(tp->s);
TAILQ_REMOVE(&head, tp, q);
}
TAG *
renamelist(oldname, newname)
char *oldname;
char *newname;
{
TAG *tp;
if(!(tp = getlist(oldname)))
return (NULL);
free(tp->s);
if(!(tp->s = strdup(newname)))
if ((ep = malloc(sizeof(*ep))) == NULL ||
(ep->s = strdup(newent)) == NULL)
err(1, "malloc");
return (tp);
if (head)
TAILQ_INSERT_HEAD(&tp->list, ep, q);
else
TAILQ_INSERT_TAIL(&tp->list, ep, q);
}
#ifdef MANDEBUG
void
debug(l)
char *l;
const char *l;
{
TAG *tp;
ENTRY *ep;
@ -214,3 +232,4 @@ debug(l)
printf("\t%s\n", ep->s);
}
}
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: config.h,v 1.3 1999/04/04 16:57:36 dante Exp $ */
/* $NetBSD: config.h,v 1.4 2000/05/27 21:33:26 jdolecek Exp $ */
/*-
* Copyright (c) 1993
@ -53,9 +53,10 @@ typedef struct _entry {
TAILQ_HEAD(_head, _tag);
extern struct _head head;
TAG *addlist __P((char *));
void config __P((char *));
void debug __P((char *));
TAG *getlist __P((char *));
void removelist __P((char *));
TAG *renamelist __P((char *, char *));
TAG *addlist __P((const char *));
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 *));

View File

@ -1,4 +1,4 @@
.\" $NetBSD: man.1,v 1.9 1999/09/08 20:32:03 fredb Exp $
.\" $NetBSD: man.1,v 1.10 2000/05/27 21:33:26 jdolecek Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -46,6 +46,7 @@
.Op Fl C Ar file
.Op Fl M Ar path
.Op Fl m Ar path
.Op Fl S Ar srch
.Op Ar section
.Ar name Ar ...
.Nm ""
@ -126,6 +127,11 @@ The subdirectories to be searched, and their search order,
is specified by the ``_subdir'' line in the
.Nm
configuration file.
.It Fl S
Display only man pages that have the specified string in their
filenames. This allows the man page search process criteria to be
narrowed without having to change the MANPATH or ``_default''
variables.
.It Fl w
List the pathnames of the man pages which
.Nm

View File

@ -1,4 +1,4 @@
/* $NetBSD: man.c,v 1.22 2000/01/09 04:54:54 tsutsui Exp $ */
/* $NetBSD: man.c,v 1.23 2000/05/27 21:33:26 jdolecek Exp $ */
/*
* Copyright (c) 1987, 1993, 1994, 1995
@ -44,7 +44,7 @@ __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994, 1995\n\
#if 0
static char sccsid[] = "@(#)man.c 8.17 (Berkeley) 1/31/95";
#else
__RCSID("$NetBSD: man.c,v 1.22 2000/01/09 04:54:54 tsutsui Exp $");
__RCSID("$NetBSD: man.c,v 1.23 2000/05/27 21:33:26 jdolecek Exp $");
#endif
#endif /* not lint */
@ -72,11 +72,11 @@ int f_all, f_where;
int main __P((int, char **));
static void build_page __P((char *, char **));
static void cat __P((char *));
static char *check_pager __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 *));
static int manual __P((char *, TAG *, glob_t *, const char *));
static void onsig __P((int));
static void usage __P((void));
@ -85,13 +85,14 @@ main(argc, argv)
int argc;
char *argv[];
{
TAG *defp, *defnewp, *section, *sectnewp, *subp;
ENTRY *e_defp, *e_sectp, *e_subp, *ep;
TAG *defp, *section, *newpathp, *subp;
ENTRY *e_defp, *e_subp;
glob_t pg;
size_t len;
int ch, f_cat, f_how, found;
char **ap, *cmd, *machine, *p, *p_add, *p_path, *pager, *slashp;
char *conffile, buf[MAXPATHLEN * 2];
int ch, f_cat, f_how, found, abs_section;
char **ap, *cmd, *p, *p_add, *p_path;
const char *machine, *pager, *conffile, *pathsearch;
char buf[MAXPATHLEN * 2];
#ifdef __GNUC__
pager = NULL; /* XXX gcc -Wuninitialized */
@ -99,7 +100,8 @@ main(argc, argv)
f_cat = f_how = 0;
conffile = p_add = p_path = NULL;
while ((ch = getopt(argc, argv, "-aC:cfhkM:m:P:w")) != -1)
pathsearch = NULL;
while ((ch = getopt(argc, argv, "-aC:cfhkM:m:P:S:w")) != -1)
switch (ch) {
case 'a':
f_all = 1;
@ -119,7 +121,7 @@ main(argc, argv)
break;
case 'M':
case 'P': /* Backward compatibility. */
p_path = optarg;
p_path = strdup(optarg);
break;
/*
* The -f and -k options are backward compatible,
@ -131,6 +133,9 @@ main(argc, argv)
case 'k':
jump(argv, "-k", "apropos");
/* NOTREACHED */
case 'S':
pathsearch = optarg;
break;
case 'w':
f_all = f_where = 1;
break;
@ -141,7 +146,7 @@ main(argc, argv)
argc -= optind;
argv += optind;
if (!*argv)
if (!argc)
usage();
if (!f_cat && !f_how && !f_where) {
@ -155,6 +160,7 @@ main(argc, argv)
pager = _PATH_PAGER;
}
}
/* Read the configuration file. */
config(conffile);
@ -169,131 +175,127 @@ main(argc, argv)
machine = utsname.machine;
}
/* If there's no _default list, create an empty one. */
/* create an empty _default list if the config file didn't have one */
if ((defp = getlist("_default")) == NULL)
defp = addlist("_default");
/*
* 1: If the user specified a MANPATH variable, or set the -M
* option, we replace the _default list with the user's list,
* appending the entries in the _subdir list and the machine.
*/
/* if -M wasn't specified, check for MANPATH */
if (p_path == NULL)
p_path = getenv("MANPATH");
if (p_path != NULL) {
while ((e_defp = defp->list.tqh_first) != NULL) {
free(e_defp->s);
TAILQ_REMOVE(&defp->list, e_defp, q);
}
for (p = strtok(p_path, ":");
p != NULL; p = strtok(NULL, ":")) {
slashp = p[strlen(p) - 1] == '/' ? "" : "/";
e_subp = (subp = getlist("_subdir")) == NULL ?
NULL : subp->list.tqh_first;
for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
p, slashp, e_subp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, "malloc");
TAILQ_INSERT_TAIL(&defp->list, ep, q);
}
}
}
/*
* 2: If the user did not specify MANPATH, -M or a section, rewrite
* the _default list to include the _subdir list and the machine.
* get section. abs_section will be non-zero iff the user
* specified a section and it had absolute (rather than
* relative) paths in the man.conf file.
*/
if (argv[1] == NULL)
if (argc > 1 && (section = getlist(*argv)) != NULL) {
argv++;
argc--;
abs_section = (TAILQ_FIRST(&section->list) != NULL &&
*(TAILQ_FIRST(&section->list)->s) == '/');
} else {
section = NULL;
else if ((section = getlist(*argv)) != NULL)
++argv;
if (p_path == NULL && section == NULL) {
defnewp = addlist("_default_new");
e_defp =
defp->list.tqh_first == NULL ? NULL : defp->list.tqh_first;
for (; e_defp != NULL; e_defp = e_defp->q.tqe_next) {
slashp =
e_defp->s[strlen(e_defp->s) - 1] == '/' ? "" : "/";
e_subp = (subp = getlist("_subdir")) == NULL ?
NULL : subp->list.tqh_first;
for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
e_defp->s, slashp, e_subp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, "malloc");
TAILQ_INSERT_TAIL(&defnewp->list, ep, q);
}
}
defp = getlist("_default");
while ((e_defp = defp->list.tqh_first) != NULL) {
free(e_defp->s);
TAILQ_REMOVE(&defp->list, e_defp, q);
}
free(defp->s);
TAILQ_REMOVE(&head, defp, q);
defnewp = getlist("_default_new");
free(defnewp->s);
defnewp->s = "_default";
defp = defnewp;
abs_section = 0;
}
/*
* 3: If the user set the -m option, insert the user's list before
* whatever list we have, again appending the _subdir list and
* the machine.
*/
if (p_add != NULL)
for (p = strtok(p_add, ":"); p != NULL; p = strtok(NULL, ":")) {
slashp = p[strlen(p) - 1] == '/' ? "" : "/";
e_subp = (subp = getlist("_subdir")) == NULL ?
NULL : subp->list.tqh_first;
for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
p, slashp, e_subp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, "malloc");
TAILQ_INSERT_HEAD(&defp->list, ep, q);
}
}
/* get subdir list */
subp = getlist("_subdir");
if (!subp)
subp = addlist("_subdir");
/*
* 4: If no -m was specified, and a section was, rewrite the section's
* paths (if they have a trailing slash) to append the _subdir list
* and the machine. This then becomes the _default list.
* now that we have all the inputs we must generate a search path.
*/
if (p_add == NULL && section != NULL) {
sectnewp = addlist("_section_new");
for (e_sectp = section->list.tqh_first;
e_sectp != NULL; e_sectp = e_sectp->q.tqe_next) {
if (e_sectp->s[strlen(e_sectp->s) - 1] != '/') {
/*
* 1: If user specified a section and it has absolute paths
* in the config file, then that overrides _default, MANPATH and
* path passed via -M.
*/
if (abs_section) {
p_path = NULL; /* zap -M/MANPATH */
defp = section; /* zap _default */
section = NULL; /* promoted to defp */
}
/*
* 2: Section can be non-null only if a section was specified
* and the config file has relative paths - the section list
* overrides _subdir in this case.
*/
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
* and the path does not end in "/".
*/
newpathp = addlist("_new_path");
if (p_path) {
/* use p_path */
for (; (p = strtok(p_path, ":")) != NULL; p_path = NULL) {
for ( e_subp = TAILQ_FIRST(&subp->list) ;
e_subp != NULL ;
e_subp = TAILQ_NEXT(e_subp, q)) {
snprintf(buf, sizeof(buf), "%s/%s{/%s,}",
p, e_subp->s, machine);
addentry(newpathp, buf, 0);
}
}
} else {
/* use defp rather than p_path */
for (e_defp = TAILQ_FIRST(&defp->list) ;
e_defp != NULL ;
e_defp = TAILQ_NEXT(e_defp, q)) {
/* handle trailing "/" magic here ... */
if (abs_section &&
e_defp->s[strlen(e_defp->s) - 1] != '/') {
(void)snprintf(buf, sizeof(buf),
"%s{/%s,}", e_sectp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, "malloc");
TAILQ_INSERT_TAIL(&sectnewp->list, ep, q);
"%s{/%s,}", e_defp->s, machine);
addentry(newpathp, buf, 0);
continue;
}
e_subp = (subp = getlist("_subdir")) == NULL ?
NULL : subp->list.tqh_first;
for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
(void)snprintf(buf, sizeof(buf), "%s%s{/%s,}",
e_sectp->s, e_subp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, "malloc");
TAILQ_INSERT_TAIL(&sectnewp->list, ep, q);
for ( e_subp = TAILQ_FIRST(&subp->list) ;
e_subp != NULL ;
e_subp = TAILQ_NEXT(e_subp, q)) {
snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
e_defp->s, (abs_section) ? "" : "/",
e_subp->s, machine);
addentry(newpathp, buf, 0);
}
}
} /* using defp ... */
/* now replace the current path with the new one */
defp = newpathp;
/*
* 4: prepend the "-m" path, if specified. we always add
* subp and machine to this part of the path.
*/
if (p_add) {
for (p = strtok(p_add, ":") ; p ; p = strtok(NULL, ":")) {
for ( e_subp = TAILQ_FIRST(&subp->list) ;
e_subp != NULL ;
e_subp = TAILQ_NEXT(e_subp, q)) {
snprintf(buf, sizeof(buf), "%s/%s{/%s,}",
p, e_subp->s, machine);
addentry(newpathp, buf, 1);
}
}
sectnewp->s = section->s;
defp = sectnewp;
TAILQ_REMOVE(&head, section, q);
}
/*
* 5: Search for the files. Set up an interrupt handler, so the
* temporary files go away.
@ -304,7 +306,7 @@ main(argc, argv)
memset(&pg, 0, sizeof(pg));
for (found = 0; *argv; ++argv)
if (manual(*argv, defp, &pg))
if (manual(*argv, defp, &pg, pathsearch))
found = 1;
/* 6: If nothing found, we're done. */
@ -379,10 +381,11 @@ main(argc, argv)
* Search the manuals for the pages.
*/
static int
manual(page, tag, pg)
manual(page, tag, pg, pathsearch)
char *page;
TAG *tag;
glob_t *pg;
const char *pathsearch;
{
ENTRY *ep, *e_sufp, *e_tag;
TAG *missp, *sufp;
@ -413,6 +416,14 @@ manual(page, tag, pg)
for (cnt = pg->gl_pathc - pg->gl_matchc;
cnt < pg->gl_pathc; ++cnt) {
if (pathsearch) {
p = strstr(pg->gl_pathv[cnt], pathsearch);
if (!p || strchr(p, '/') == NULL) {
pg->gl_pathv[cnt] = "";
continue;
}
}
/*
* Try the _suffix key words first.
*
@ -662,11 +673,11 @@ cat(fname)
* check_pager --
* check the user supplied page information
*/
static char *
static const char *
check_pager(name)
char *name;
const char *name;
{
char *p, *save;
const char *p, *save;
/*
* if the user uses "more", we make it "more -s"; watch out for
@ -680,14 +691,12 @@ check_pager(name)
/* make sure it's "more", not "morex" */
if (!strncmp(p, "more", 4) && (!p[4] || isspace((unsigned char)p[4]))){
save = name;
/* allocate space to add the "-s" */
if (!(name =
malloc((u_int)(strlen(save) + sizeof("-s") + 1))))
err(1, "malloc");
(void)sprintf(name, "%s %s", save, "-s");
char *newname;
(void)asprintf(&newname, "%s %s", save, "-s");
name = newname;
}
return(name);
return (name);
}
/*
@ -772,7 +781,7 @@ usage()
{
extern char *__progname;
(void)fprintf(stderr,
"Usage: %s [-achw] [-C file] [-M path] [-m path] [section] title ...\n",
"Usage: %s [-achw] [-C file] [-M path] [-m path] [-S srch] [section] title ...\n",
__progname);
exit(1);
}

View File

@ -1,4 +1,4 @@
.\" $NetBSD: man.conf.5,v 1.7 1999/11/19 22:29:26 kristerw Exp $
.\" $NetBSD: man.conf.5,v 1.8 2000/05/27 21:33:26 jdolecek Exp $
.\"
.\" Copyright (c) 1989, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -66,10 +66,15 @@ precede it with a backslash (``\e'').
Lines in this format specify that manual pages for the section
may be found in the following directories.
.Pp
Directories named with a trailing slash character (``/'') are expected
to contain subdirectories of manual pages, (see the keyword ``_subdir''
below) instead of manual pages.
These subdirectories are searched instead of the directory.
Section lines may contain either absolute directory paths or relative
directory paths (but not both). Relative directory paths are treated
as a list of subdirectories to append to the current directory search
path. Section lines with absolute directory paths (starting with
``/'') completely replace the current directory search path with their
content. Absolute directory paths named with a trailing slash
character are expected to contain subdirectories of manual pages, (see
the keyword ``_subdir'' below) instead of man pages. These
subdirectories are searched instead of the directory.
.Pp
Before searching any directory for a manual page, the
.Xr man 1