Mimic OSX behaviour:

On OS X it is possible to specify the manpage filename
with a full or relative path like this:

   man ./foo.5

or

   man /cd/foo/bar.1.gz

This is really helpful to view the manpage quickly while editing it.

patch presented on current-users@ and tech-userlevel@:
http://mail-index.netbsd.org/current-users/2009/10/06/msg010767.html
http://mail-index.netbsd.org/tech-userlevel/2009/10/06/msg002675.html

No objections
This commit is contained in:
cegger 2009-10-07 08:30:31 +00:00
parent 8b451badf9
commit 656e85b2f1
2 changed files with 107 additions and 26 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: man.1,v 1.20 2006/04/13 21:10:44 wiz Exp $
.\" $NetBSD: man.1,v 1.21 2009/10/07 08:30:31 cegger Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -29,7 +29,7 @@
.\"
.\" @(#)man.1 8.2 (Berkeley) 1/2/94
.\"
.Dd April 10, 2006
.Dd October 6, 2009
.Dt MAN 1
.Os
.Sh NAME
@ -168,6 +168,17 @@ 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.
.Pp
If
.Ar name
is given with a full or relative path then
.Nm
interprets it as a file specification, so that you can do
.Nm
.Cm ./foo.5
or even
.Nm
.Cm /cd/foo/bar.1.gz .
.Sh ENVIRONMENT
.Bl -tag -width MANPATHX
.It Ev MACHINE

View File

@ -1,4 +1,4 @@
/* $NetBSD: man.c,v 1.38 2009/10/06 06:43:15 cegger Exp $ */
/* $NetBSD: man.c,v 1.39 2009/10/07 08:30:31 cegger Exp $ */
/*
* Copyright (c) 1987, 1993, 1994, 1995
@ -40,7 +40,7 @@ __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994, 1995\
#if 0
static char sccsid[] = "@(#)man.c 8.17 (Berkeley) 1/31/95";
#else
__RCSID("$NetBSD: man.c,v 1.38 2009/10/06 06:43:15 cegger Exp $");
__RCSID("$NetBSD: man.c,v 1.39 2009/10/07 08:30:31 cegger Exp $");
#endif
#endif /* not lint */
@ -472,6 +472,39 @@ main(int argc, char **argv)
exit(cleanup());
}
static int
manual_find_buildkeyword(char *escpage, const char *fmt,
struct manstate *mp, glob_t *pg, size_t cnt)
{
ENTRY *suffix;
int found;
char *p, buf[MAXPATHLEN];
found = 0;
/* Try the _build key words next. */
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), fmt, 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 = ' ';
}
return found;
}
/*
* manual --
* Search the manuals for the pages.
@ -510,6 +543,63 @@ manual(char *page, struct manstate *mp, glob_t *pg)
*eptr = '\0';
/*
* If 'page' is given with a full or relative path
* then interpret it as a file specification.
*/
if ((page[0] == '/') || (page[0] == '.')) {
/* check if file actually exists */
(void)strlcpy(buf, escpage, sizeof(buf));
error = glob(buf, GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT, NULL, pg);
if (error != 0) {
if (error == GLOB_NOMATCH) {
goto notfound;
} else {
errx(EXIT_FAILURE, "glob failed");
}
}
if (pg->gl_matchc == 0)
goto notfound;
/* clip suffix for the suffix check below */
p = strrchr(escpage, '.');
if (p && p[0] == '.' && isdigit((unsigned char)p[1]))
p[0] = '\0';
found = 0;
for (cnt = pg->gl_pathc - pg->gl_matchc;
cnt < pg->gl_pathc; ++cnt)
{
found = manual_find_buildkeyword(escpage, "%s%s",
mp, pg, cnt);
if (found) {
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] = "";
}
notfound:
if (!anyfound) {
if (addentry(mp->missinglist, page, 0) < 0) {
warn("malloc");
(void)cleanup();
exit(EXIT_FAILURE);
}
}
free(escpage);
return anyfound;
}
/* For each man directory in mymanpath ... */
TAILQ_FOREACH(mdir, &mp->mymanpath->entrylist, q) {
@ -576,28 +666,8 @@ manual(char *page, struct manstate *mp, glob_t *pg)
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 = ' ';
}
found = manual_find_buildkeyword(escpage, "*/%s%s",
mp, pg, cnt);
if (found) {
next: anyfound = 1;
if (!mp->all) {