Add catman.

It require "_crunch" section in /etc/man.conf to re-compress the compressed man pages.
It handle symbolic links, but at this time no hard links.
config files are stolen from man with few changes to support "_crunch" section.

catman.8 miss the "full moon" joke, I can't remember it, if you can pleas add it :-)
This commit is contained in:
dante 1999-04-04 10:56:38 +00:00
parent 0d59551634
commit bea7444699
7 changed files with 830 additions and 160 deletions

View File

@ -1,7 +1,8 @@
# $NetBSD: Makefile,v 1.4 1997/10/18 04:37:17 lukem Exp $ # $NetBSD: Makefile,v 1.5 1999/04/04 10:56:38 dante Exp $
BINDIR= /usr/sbin BINDIR= /usr/sbin
PROG= catman PROG= catman
SRCS= config.c catman.c
MAN= catman.8 MAN= catman.8
.include <bsd.prog.mk> .include <bsd.prog.mk>

View File

@ -1,2 +1 @@
Use man.conf
Handle hard-linked manpages. Handle hard-linked manpages.

View File

@ -27,7 +27,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $NetBSD: catman.8,v 1.8 1997/10/18 04:37:19 lukem Exp $ .\" $NetBSD: catman.8,v 1.9 1999/04/04 10:56:38 dante Exp $
.\" .\"
.Dd July 30, 1993 .Dd July 30, 1993
.Dt CATMAN 8 .Dt CATMAN 8
@ -38,6 +38,10 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl knpsw .Op Fl knpsw
.Op Fl m Ar directory
.Op Ar sections
.Nm ""
.Op Fl knpsw
.Op Fl M Ar directory .Op Fl M Ar directory
.Op Ar sections .Op Ar sections
.Sh DESCRIPTION .Sh DESCRIPTION
@ -58,8 +62,8 @@ The optional
argument is one word, and contains the section numbers of all the argument is one word, and contains the section numbers of all the
sections to be checked. For example, if sections to be checked. For example, if
.Ar sections .Ar sections
is ``138'', the is ``13f8'', the
manual pages in sections 1, 3, and 8 will be checked and regenerated. manual pages in sections 1, 3f, and 8 will be checked and regenerated.
If no If no
.Ar sections .Ar sections
argument is provided, argument is provided,
@ -86,6 +90,10 @@ is specified.
Only create the Only create the
.Pa whatis .Pa whatis
database. database.
.It Fl m Ar directory
Add
.Ar directory
to the set of directories to be updated.
.It Fl M Ar directory .It Fl M Ar directory
Update manual pages in Update manual pages in
.Ar directory. .Ar directory.
@ -95,6 +103,4 @@ Update manual pages in
.Xr man 1 , .Xr man 1 ,
.Xr whatis 1 .Xr whatis 1
.Sh BUGS .Sh BUGS
Currently knows nothing about Currently does not handle hard links.
.Pa /etc/man.conf
and machine specific man pages.

View File

@ -1,7 +1,11 @@
/* $NetBSD: catman.c,v 1.10 1999/04/04 10:56:38 dante Exp $ */
/* /*
* Copyright (c) 1993 Winning Strategies, Inc. * Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved. * All rights reserved.
* *
* Author: Baldassare Dante Profeta <dante@mclink.it>
*
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
@ -12,67 +16,82 @@
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software * 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement: * must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc. * This product includes software developed by the NetBSD
* 4. The name of the author may not be used to endorse or promote products * Foundation, Inc. and its contributors.
* derived from this software without specific prior written permission * 4. Neither the name of The NetBSD Foundation 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: catman.c,v 1.9 1997/10/24 01:31:35 mrg Exp $");
#endif /* not lint */
#include <sys/types.h> #include <sys/types.h>
#include <sys/queue.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <fnmatch.h>
#include <limits.h> #include <limits.h>
#include <libgen.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <paths.h> #include <glob.h>
#include "config.h"
#include "pathnames.h" #include "pathnames.h"
int f_nowhatis; #ifndef MACHINE
int f_noaction; #define MACHINE __ARCHITECTURE__
int f_noformat; #endif
int f_ignerr;
int f_noprint;
int dowhatis; int f_nowhatis = 0;
int f_noaction = 0;
int f_noformat = 0;
int f_ignerr = 0;
int f_noprint = 0;
int dowhatis = 0;
char *mp = _PATH_MAN; int main __P((int, char **));
char *sp = _MAN_SECTIONS; static void setdefentries __P((char *, char *, char *));
static void uniquepath __P((void));
static void catman __P((void));
static void scanmandir __P((const char *, const char *));
static int splitentry __P((char *, char *, char *));
static void setcatsuffix __P((char *, const char *, const char *));
static void makecat __P((const char *, const char *, const char *,
const char *));
static void makewhatis __P((void));
static void dosystem __P((const char *));
static void usage __P((void));
void catman __P((const char *, char *));
int main __P((int, char **));
void makewhatis __P((const char *));
void dosystem __P((const char *));
void usage __P((void));
int int
main(argc, argv) main(argc, argv)
int argc; int argc;
char **argv; char **argv;
{ {
char *m_path = NULL;
char *m_add = NULL;
int c; int c;
while ((c = getopt(argc, argv, "knpswM:")) != -1) { while ((c = getopt(argc, argv, "km:M:npsw")) != -1) {
switch (c) { switch (c) {
case 'k': case 'k':
f_ignerr = 1; f_ignerr = 1;
@ -89,8 +108,11 @@ main(argc, argv)
case 'w': case 'w':
f_noformat = 1; f_noformat = 1;
break; break;
case 'm':
m_add = optarg;
break;
case 'M': case 'M':
mp = optarg; m_path = optarg;
break; break;
case '?': case '?':
@ -107,143 +129,501 @@ main(argc, argv)
if (argc > 1) if (argc > 1)
usage(); usage();
if (argc == 1)
sp = *argv; config(_PATH_MANCONF);
setdefentries(m_path, m_add, (argc == 0)? NULL : argv[argc-1]);
uniquepath();
if (f_noformat == 0 || f_nowhatis == 0) if (f_noformat == 0 || f_nowhatis == 0)
catman(mp, sp); catman();
if (f_nowhatis == 0 && dowhatis) if (f_nowhatis == 0 && dowhatis)
makewhatis(mp); makewhatis();
exit(0); return(0);
} }
static void
void setdefentries(m_path, m_add, sections)
catman(path, section) char *m_path;
const char *path; char *m_add;
char *section; char *sections;
{ {
char mandir[PATH_MAX]; TAG *defp, *defnewp, *sectnewp, *subp;
char catdir[PATH_MAX]; ENTRY *e_defp, *e_sectp, *e_subp, *ep;
char manpage[PATH_MAX]; char *p, *slashp, *machine;
char catpage[PATH_MAX]; char section[10];
char sysbuf[1024]; char buf[MAXPATHLEN * 2];
struct stat manstat; int i;
struct stat catstat;
struct dirent *dp;
DIR *dirp;
char *s, *tmp;
int sectlen, error;
for (s = section; *s; s += sectlen) { /* Get the machine type. */
#ifdef notdef if ((machine = getenv("MACHINE")) == NULL)
tmp = s; machine = MACHINE;
sectlen = 0;
if (isdigit(*tmp)) { /* If there's no _default list, create an empty one. */
sectlen++; if ((defp = getlist("_default")) == NULL)
tmp++; defp = addlist("_default");
while (*tmp && isdigit(*tmp) == 0) {
sectlen++; /*
tmp++; * 0: If one or more sections was specified, rewrite _subdir list.
*/
if (sections != NULL) {
sectnewp = addlist("_section_new");
for(p=sections; *p;) {
section[0] = *p++;
for(i=1; *p && !isdigit(*p) && i<10; i++)
section[i] = *p++;
section[i] = '\0';
snprintf(buf, sizeof(buf), "man%s", section);
if(!(e_sectp = malloc(sizeof(ENTRY))))
err(1, "malloc");
if(!(e_sectp->s = strdup(buf)))
err(1, "malloc");
TAILQ_INSERT_TAIL(&sectnewp->list, e_sectp, q);
}
removelist("_subdir");
renamelist("_section_new", "_subdir");
}
/*
* 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_path == NULL)
m_path = getenv("MANPATH");
if (m_path != NULL) {
while ((e_defp = defp->list.tqh_first) != NULL) {
free(e_defp->s);
TAILQ_REMOVE(&defp->list, e_defp, q);
}
for (p = strtok(m_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) {
if(!strncmp(e_subp->s, "cat", 3))
continue;
(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);
} }
} }
#else }
sectlen = 1;
#endif
if (sectlen == 0)
errx(1, "malformed section string");
snprintf(mandir, sizeof mandir, "%s/%s%.*s", path, /*
_PATH_MANPAGES, sectlen, s); * 2: If the user did not specify MANPATH, -M or a section, rewrite
snprintf(catdir, sizeof catdir, "%s/%s%.*s", path, * the _default list to include the _subdir list and the machine.
_PATH_CATPAGES, sectlen, s); */
if (m_path == NULL) {
defp = getlist("_default");
defnewp = addlist("_default_new");
e_defp =
defp->list.tqh_first == NULL ? NULL : defp->list.tqh_first;
for (; e_defp; 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; e_subp = e_subp->q.tqe_next) {
if(!strncmp(e_subp->s, "cat", 3))
continue;
(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);
}
}
removelist("_default");
renamelist("_default_new", "_default");
}
if ((dirp = opendir(mandir)) == 0) { /*
warn("can't open %s", mandir); * 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 (m_add != NULL)
for (p = strtok(m_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) {
if(!strncmp(e_subp->s, "cat", 3))
continue;
(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);
}
}
}
/*
* Remove entries (directory) which are symbolic links to other entries.
* Some examples are showed below:
* 1) if /usr/X11 -> /usr/X11R6 then remove all /usr/X11/man entries.
* 2) if /usr/local/man -> /usr/share/man then remove all /usr/local/man
* entries
*/
static void
uniquepath(void)
{
TAG *defp, *defnewp;
ENTRY *e_defp;
glob_t manpaths;
struct stat st1;
struct stat st2;
struct stat st3;
int i,j,len,lnk;
char path[PATH_MAX], *p;
defp = getlist("_default");
e_defp = defp->list.tqh_first;
glob(e_defp->s, GLOB_BRACE | GLOB_NOSORT, NULL, &manpaths);
for(e_defp = e_defp->q.tqe_next; e_defp; e_defp = e_defp->q.tqe_next) {
glob(e_defp->s, GLOB_BRACE | GLOB_NOSORT | GLOB_APPEND, NULL,
&manpaths);
}
defnewp = addlist("_default_new");
for(i=0; i<manpaths.gl_pathc; i++) {
lnk = 0;
lstat(manpaths.gl_pathv[i], &st1);
for(j=0; j<manpaths.gl_pathc; j++) {
if(i!=j) {
lstat(manpaths.gl_pathv[j], &st2);
if(st1.st_ino == st2.st_ino) {
strcpy(path, manpaths.gl_pathv[i]);
for(p = path; *(p+1) != '\0';) {
p = dirname(p);
lstat(p, &st3);
if(S_ISLNK(st3.st_mode)) {
lnk = 1;
break;
}
}
} else {
len = readlink(manpaths.gl_pathv[i],
path, PATH_MAX);
if(len == -1)
continue;
if(!strcmp(path, manpaths.gl_pathv[j]))
lnk = 1;
}
if(lnk)
break;
}
}
if(!lnk) {
if(!(e_defp = malloc(sizeof(ENTRY))))
err(1, "malloc");
if(!(e_defp->s = strdup(manpaths.gl_pathv[i])))
err(1, "malloc");
TAILQ_INSERT_TAIL(&defnewp->list, e_defp, q);
}
}
globfree(&manpaths);
removelist("_default");
renamelist("_default_new", "_default");
}
static void
catman(void)
{
TAG *pathp;
ENTRY *e_path;
char *mandir;
char catdir[PATH_MAX], *cp;
pathp = getlist("_default");
for(e_path = pathp->list.tqh_first; e_path;
e_path = e_path->q.tqe_next) {
mandir = e_path->s;
strcpy(catdir,mandir);
if(!(cp = strstr(catdir, "man/man")))
continue;
cp+=4; *cp++ = 'c'; *cp++ = 'a'; *cp = 't';
scanmandir(catdir, mandir);
}
}
static void
scanmandir(catdir, mandir)
const char *catdir;
const char *mandir;
{
TAG *buildp, *crunchp;
ENTRY *e_build, *e_crunch;
char manpage[PATH_MAX];
char catpage[PATH_MAX];
char linkname[PATH_MAX];
char buffer[PATH_MAX], *bp;
char tmp[PATH_MAX];
char buildsuff[256], buildcmd[256];
char crunchsuff[256], crunchcmd[256];
char match[256];
struct stat manstat;
struct stat catstat;
struct stat lnkstat;
struct dirent *dp;
DIR *dirp;
int len, error;
if ((dirp = opendir(mandir)) == 0) {
warn("can't open %s", mandir);
return;
}
if (stat(catdir, &catstat) < 0) {
if (errno != ENOENT) {
warn("can't stat %s", catdir);
closedir(dirp);
return;
}
if (f_noprint == 0)
printf("mkdir %s\n", catdir);
if (f_noaction == 0 && mkdir(catdir,0755) < 0) {
warn("can't create %s", catdir);
closedir(dirp);
return;
}
}
while ((dp = readdir(dirp)) != NULL) {
if (strcmp(dp->d_name, ".") == 0 ||
strcmp(dp->d_name, "..") == 0)
continue;
snprintf(manpage, sizeof(manpage), "%s/%s", mandir, dp->d_name);
snprintf(catpage, sizeof(catpage), "%s/%s", catdir, dp->d_name);
buildp = getlist("_build");
for(e_build = buildp->list.tqh_first; e_build;
e_build = e_build->q.tqe_next) {
splitentry(e_build->s, buildsuff, buildcmd);
snprintf(match, sizeof(match), "*%s", buildsuff);
if(!fnmatch(match, manpage, 0))
break;
}
if(e_build == NULL) {
continue;
} else {
crunchp = getlist("_crunch");
for(e_crunch = crunchp->list.tqh_first; e_crunch;
e_crunch = e_crunch->q.tqe_next) {
splitentry(e_crunch->s, crunchsuff, crunchcmd);
snprintf(match, sizeof(match), "*%s",
crunchsuff);
if(!fnmatch(match, manpage, 0))
break;
}
}
if (lstat(manpage, &manstat) <0) {
warn("can't stat %s", manpage);
continue;
} else {
if(S_ISLNK(manstat.st_mode)) {
strcpy(buffer, catpage);
strcpy(linkname, basename(buffer));
len = readlink(manpage, buffer, PATH_MAX);
if(len == -1) {
warn("can't stat read symbolic link %s",
manpage);
continue;
}
buffer[len] = '\0';
bp = basename(buffer);
strcpy(tmp, manpage);
snprintf(manpage, sizeof(manpage), "%s/%s",
dirname(tmp), bp);
strcpy(tmp, catpage);
snprintf(catpage, sizeof(catpage), "%s/%s",
dirname(tmp), buffer);
}
else
*linkname='\0';
}
if(!e_crunch) {
*crunchsuff = *crunchcmd = '\0';
}
setcatsuffix(catpage, buildsuff, crunchsuff);
if(*linkname != '\0')
setcatsuffix(linkname, buildsuff, crunchsuff);
if (stat(manpage, &manstat) < 0) {
warn("can't stat %s", manpage);
continue; continue;
} }
if (stat(catdir, &catstat) < 0) { if (!S_ISREG(manstat.st_mode)) {
if (errno != ENOENT) { warnx("not a regular file %s",manpage);
warn("can't stat %s", catdir); continue;
closedir(dirp);
continue;
}
if (f_noprint == 0)
printf("mkdir %s\n", catdir);
if (f_noaction == 0 && mkdir(catdir, 0755) < 0) {
warn("can't create %s", catdir);
closedir(dirp);
return;
}
} }
while ((dp = readdir(dirp)) != NULL) { if ((error = stat(catpage, &catstat)) &&
if (strcmp(dp->d_name, ".") == 0 || errno != ENOENT) {
strcmp(dp->d_name, "..") == 0) warn("can't stat %s", catpage);
continue; continue;
}
sprintf(manpage, "%s/%s", mandir, dp->d_name); if ((error && errno == ENOENT) ||
sprintf(catpage, "%s/%s", catdir, dp->d_name); manstat.st_mtime >= catstat.st_mtime) {
if ((tmp = strrchr(catpage, '.')) != NULL) if (f_noformat) {
strcpy(tmp, ".0"); dowhatis = 1;
else } else {
continue; /*
* reformat out of date manpage
if (stat(manpage, &manstat) < 0) { */
warn("can't stat %s", manpage); makecat(manpage, catpage, buildcmd, crunchcmd);
continue; dowhatis = 1;
} }
}
if (!S_ISREG(manstat.st_mode)) { if(*linkname != '\0') {
warnx("not a regular file %s", manpage); strcpy(tmp, catpage);
continue; snprintf(tmp, sizeof(tmp), "%s/%s", dirname(tmp),
} linkname);
if ((error = stat(catpage, &catstat)) && if ((error = lstat(tmp, &lnkstat)) &&
errno != ENOENT) { errno != ENOENT) {
warn("can't stat %s", catpage); warn("can't stat %s", tmp);
continue; continue;
} }
if ((error && errno == ENOENT) || if (error && errno == ENOENT) {
manstat.st_mtime >= catstat.st_mtime) { if (f_noformat) {
if (f_noformat)
dowhatis = 1; dowhatis = 1;
else { } else {
/* /*
* manpage is out of date, * create symbolic link
* reformat
*/ */
sprintf(sysbuf, "nroff -mandoc %s > %s",
manpage, catpage);
if (f_noprint == 0) if (f_noprint == 0)
printf("%s\n", sysbuf); printf("ln -s %s %s\n", catpage,
if (f_noaction == 0) linkname);
dosystem(sysbuf); if (f_noaction == 0) {
strcpy(tmp, catpage);
if(chdir(dirname(tmp)) == -1) {
warn("can't chdir");
continue;
}
if(symlink(catpage, linkname)
== -1) {
warn("can't create"
" symbolic"
" link %s",
linkname);
continue;
}
}
dowhatis = 1; dowhatis = 1;
} }
} }
} }
closedir(dirp);
} }
closedir(dirp);
} }
void static int
makewhatis(path) splitentry(s, first, second)
const char *path; char *s;
char *first;
char *second;
{ {
char sysbuf[1024]; char *c;
for(c = s; *c != '\0' && !isspace(*c); ++c);
if(*c == '\0')
return(0);
strncpy(first, s, c-s);
first[c-s] = '\0';
for(; *c != '\0' && isspace(*c); ++c);
strcpy(second, c);
return(1);
}
static void
setcatsuffix(catpage, suffix, crunchsuff)
char *catpage;
const char *suffix;
const char *crunchsuff;
{
TAG *tp;
ENTRY *ep;
char *p;
for(p = catpage + strlen(catpage); p!=catpage; p--)
if(!fnmatch(suffix, p, 0)) {
if((tp = getlist("_suffix"))) {
ep = tp->list.tqh_first;
sprintf(p, "%s%s", ep->s, crunchsuff);
} else {
sprintf(p, ".0%s", crunchsuff);
}
break;
}
}
static void
makecat(manpage, catpage, buildcmd, crunchcmd)
const char *manpage;
const char *catpage;
const char *buildcmd;
const char *crunchcmd;
{
char crunchbuf[1024];
char sysbuf[2048];
snprintf(sysbuf, sizeof(sysbuf), buildcmd, manpage);
if(*crunchcmd != '\0') {
snprintf(crunchbuf, sizeof(crunchbuf), crunchcmd, catpage);
snprintf(sysbuf, sizeof(sysbuf), "%s | %s", sysbuf, crunchbuf);
} else {
snprintf(sysbuf, sizeof(sysbuf), "%s > %s", sysbuf, catpage);
}
sprintf(sysbuf, "%s %s", _PATH_MAKEWHATIS, path);
if (f_noprint == 0) if (f_noprint == 0)
printf("%s\n", sysbuf); printf("%s\n", sysbuf);
if (f_noaction == 0) if (f_noaction == 0)
dosystem(sysbuf); dosystem(sysbuf);
} }
void static void
makewhatis(void)
{
TAG *whatdbp;
ENTRY *e_whatdb;
char sysbuf[1024];
whatdbp = getlist("_whatdb");
for(e_whatdb = whatdbp->list.tqh_first; e_whatdb;
e_whatdb = e_whatdb->q.tqe_next) {
snprintf(sysbuf, sizeof(sysbuf), "%s %s",
_PATH_WHATIS, dirname(e_whatdb->s));
if (f_noprint == 0)
printf("%s\n", sysbuf);
if (f_noaction == 0)
dosystem(sysbuf);
}
}
static void
dosystem(cmd) dosystem(cmd)
const char *cmd; const char *cmd;
{ {
@ -263,10 +643,12 @@ dosystem(cmd)
warnx("*** Exited %d (continuing)", status); warnx("*** Exited %d (continuing)", status);
} }
void static void
usage() usage(void)
{ {
(void)fprintf(stderr, (void)fprintf(stderr,
"usage: catman [-knpsw] [-M manpath] [sections]\n"); "usage: catman [-knpsw] [-m manpath] [sections]\n");
(void)fprintf(stderr,
" catman [-knpsw] [-M manpath] [sections]\n");
exit(1); exit(1);
} }

216
usr.sbin/catman/config.c Normal file
View File

@ -0,0 +1,216 @@
/* $NetBSD: config.c,v 1.1 1999/04/04 10:56:38 dante 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)config.c 8.8 (Berkeley) 1/31/95";
#else
__RCSID("$NetBSD: config.c,v 1.1 1999/04/04 10:56:38 dante Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "pathnames.h"
struct _head head;
/*
* config --
*
* Read the configuration file and build a doubly linked
* list that looks like:
*
* tag1 <-> record <-> record <-> record
* |
* tag2 <-> record <-> record <-> record
*/
void
config(fname)
char *fname;
{
TAG *tp;
ENTRY *ep;
FILE *cfp;
size_t len;
int lcnt;
char *p, *t;
if (fname == NULL)
fname = _PATH_MANCONF;
if ((cfp = fopen(fname, "r")) == NULL)
err(1, "%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 (; *p != '\0' && isspace((unsigned char)*p); ++p);
/* Skip empty/comment lines. */
if (*p == '\0' || *p == '#')
continue;
/* Find first token. */
for (t = p; *t && !isspace((unsigned char)*t); ++t);
if (*t == '\0') /* Need more than one token.*/
continue;
*t = '\0';
for (tp = head.tqh_first; /* Find any matching tag. */
tp != NULL && strcmp(p, tp->s); tp = tp->q.tqe_next);
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.
*/
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);
}
}
fclose(cfp);
}
/*
* addlist --
* Add a tag to the list.
*/
TAG *
addlist(name)
char *name;
{
TAG *tp;
if ((tp = calloc(1, sizeof(TAG))) == NULL ||
(tp->s = strdup(name)) == NULL)
err(1, "malloc");
TAILQ_INIT(&tp->list);
TAILQ_INSERT_TAIL(&head, tp, q);
return (tp);
}
/*
* getlist --
* Return the linked list of entries for a tag if it exists.
*/
TAG *
getlist(name)
char *name;
{
TAG *tp;
for (tp = head.tqh_first; tp != NULL; tp = tp->q.tqe_next)
if (!strcmp(name, tp->s))
return (tp);
return (NULL);
}
void
removelist(name)
char *name;
{
TAG *tp;
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)))
err(1, "malloc");
return (tp);
}
void
debug(l)
char *l;
{
TAG *tp;
ENTRY *ep;
(void)printf("%s ===============\n", l);
for (tp = head.tqh_first; tp != NULL; tp = tp->q.tqe_next) {
printf("%s\n", tp->s);
for (ep = tp->list.tqh_first; ep != NULL; ep = ep->q.tqe_next)
printf("\t%s\n", ep->s);
}
}

61
usr.sbin/catman/config.h Normal file
View File

@ -0,0 +1,61 @@
/* $NetBSD: config.h,v 1.1 1999/04/04 10:56:39 dante 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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
*/
typedef struct _tag {
TAILQ_ENTRY(_tag) q; /* Queue of tags. */
TAILQ_HEAD(tqh, _entry) list; /* Queue of entries. */
char *s; /* Associated string. */
size_t len; /* Length of 's'. */
} TAG;
typedef struct _entry {
TAILQ_ENTRY(_entry) q; /* Queue of entries. */
char *s; /* Associated string. */
size_t len; /* Length of 's'. */
} 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 *));

View File

@ -1,6 +1,8 @@
/* $NetBSD: pathnames.h,v 1.4 1999/04/04 10:56:39 dante Exp $ */
/* /*
* Copyright (c) 1994 Christopher G. Demetriou * Copyright (c) 1989, 1993
* All rights reserved. * The Regents of the University of California. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -12,25 +14,28 @@
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software * 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement: * must display the following acknowledgement:
* This product includes software developed by Christopher G. Demetriou. * This product includes software developed by the University of
* 4. The name of the author may not be used to endorse or promote products * California, Berkeley and its contributors.
* derived from this software without specific prior written permission * 4. 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* *
* $NetBSD: pathnames.h,v 1.3 1997/10/24 01:31:39 mrg Exp $ * @(#)pathnames.h 8.3 (Berkeley) 1/2/94
*/ */
#define _MAN_SECTIONS "123456789" /* l, n, o, and p, too? */ #define _PATH_MANCONF "/etc/man.conf"
#define _PATH_MAKEWHATIS "/usr/libexec/makewhatis" #define _PATH_PAGER "/usr/bin/more -s"
#define _PATH_MANPAGES "man" #define _PATH_TMP "/tmp/man.XXXXXX"
#define _PATH_CATPAGES "cat" #define _PATH_WHATIS "/usr/libexec/makewhatis"