NetBSD Problem Report #1904

From gnats  Sat Jan  6 15:36:20 1996
Received: from snarf.umiacs.umd.edu by pain.lcs.mit.edu (8.6.12/8.6.9) with ESMTP id PAA09414 for <gnats-bugs@gnats.netbsd.org>; Sat, 6 Jan 1996 15:31:36 -0500
Message-Id: <199601062031.PAA19882@snarf.umiacs.umd.edu>
Date: Sat, 6 Jan 1996 15:31:23 -0500
From: kashmir@umiacs.umd.edu
To: gnats-bugs@gnats.netbsd.org
Subject: changes to man programs
X-Send-Pr-Version: 3.95


>Number:         1904
>Category:       bin
>Synopsis:       changes to man programs
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sat Jan 06 15:50:01 +0000 1996
>Closed-Date:    
>Last-Modified:  Thu Mar 22 20:35:49 +0000 2001
>Originator:     Mike Grupenhoff
>Release:        19960106
>Organization:
nyuk nyuk
>Environment:
System: NetBSD snarf.umiacs.umd.edu 1.1A NetBSD 1.1A (SNARF) #7: Fri Dec 29 23:04:19 EST 1995 kashmir@snarf.umiacs.umd.edu:/usr/src/sys/arch/i386/compile/SNARF i386
>Description:


- apropos and whatis can't handle multiple whatis db's when they
  are specified in shell glob syntax.  For example, a line like:


  _whatdb         /usr/{share,local,afs,X11}/man/whatis.db


  in /etc/man.conf will not be handled properly.


- catman doesn't work with /etc/man.conf and linked manpages


- bsd.man.mk doesn't use the build rules listed in /etc/man.conf
  catman should be used in bsd.man.mk instead of nroff

  
>How-To-Repeat:
look at the source
>Fix:
4 patches are attached.


The first patch adds support to apropos for globbing _whatdb.


-----cut-here-----
Index: apropos.c
===================================================================
RCS file: /snarf/netbsd/master/src/usr.bin/apropos/apropos.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 apropos.c
--- apropos.c	1995/11/16 02:27:00	1.1.1.1
+++ apropos.c	1996/01/02 05:28:43
@@ -52,6 +52,7 @@

 
 #include <ctype.h>
 #include <err.h>
+#include <glob.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -77,6 +78,7 @@
 	TAG *tp;
 	int ch, rv;
 	char *conffile, **p, *p_augment, *p_path;
+	glob_t pg;

 
 	conffile = NULL;
 	p_augment = p_path = NULL;
@@ -117,8 +119,15 @@
 		config(conffile);
 		ep = (tp = getlist("_whatdb")) == NULL ?
 		    NULL : tp->list.tqh_first;
-		for (; ep != NULL; ep = ep->q.tqe_next)
-			apropos(argv, ep->s, 0);
+		for (; ep != NULL; ep = ep->q.tqe_next) {
+			if (glob(ep->s, GLOB_BRACE|GLOB_QUOTE, NULL, &pg) != 0)
+				err(1, "glob");
+			if (pg.gl_matchc == 0)
+				continue;
+			for (ch = 0; pg.gl_pathv[ch] != NULL; ch++)
+				apropos(argv, pg.gl_pathv[ch], 0);
+			globfree(&pg);
+		}
 	}

 
 	if (!foundman)
-----cut-here-----






The second patch adds glob support to whatis.


-----cut-here-----
Index: whatis.c
===================================================================
RCS file: /snarf/netbsd/master/src/usr.bin/whatis/whatis.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 whatis.c
--- whatis.c	1995/11/16 02:28:52	1.1.1.1
+++ whatis.c	1996/01/02 05:27:59
@@ -1,3 +1,5 @@
+/*	$NetBSD$	*/
+
 /*
  * Copyright (c) 1987, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -38,7 +40,11 @@
 #endif /* not lint */

 
 #ifndef lint
+#if 0
 static char sccsid[] = "@(#)whatis.c	8.5 (Berkeley) 11/26/93";
+#else
+static char rcsid[] = "$NetBSD$";
+#endif
 #endif /* not lint */

 
 #include <sys/param.h>
@@ -46,6 +52,7 @@

 
 #include <ctype.h>
 #include <err.h>
+#include <glob.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -71,6 +78,7 @@
 	TAG *tp;
 	int ch, rv;
 	char *beg, *conffile, **p, *p_augment, *p_path;
+	glob_t pg;

 
 	conffile = NULL;
 	p_augment = p_path = NULL;
@@ -112,8 +120,15 @@
 		config(conffile);
 		ep = (tp = getlist("_whatdb")) == NULL ?
 		   NULL : tp->list.tqh_first;
-		for (; ep != NULL; ep = ep->q.tqe_next)
-			whatis(argv, ep->s, 0);
+		for (; ep != NULL; ep = ep->q.tqe_next) {
+			if (glob(ep->s, GLOB_BRACE|GLOB_QUOTE, NULL, &pg) != 0)
+				err(1, "glob");
+			if (pg.gl_matchc == 0)
+				continue;
+			for (ch = 0; pg.gl_pathv[ch] != NULL; ch++)
+				whatis(argv, pg.gl_pathv[ch], 0);
+			globfree(&pg);
+		}
 	}

 
 	if (!foundman) {
-----cut-here-----






The third patch is for catman.  It does the following:


	-adds $NetBSD$ rcsids


	-adds support for parsing man.conf


	-adds support for handling hard and symlinked manpages (it hard
	 links the catpage together in both cases)


	-adds a second mode of operation:


		catman <manpage>


	 will format the manpage using the build rules in /etc/man.conf,
	 and dump it to stdout.  This can be used in bsd.man.mk to
	 format manpages instead of assuming everything works with
	 nroff -man.


After applying this patch, TODO and pathnames.h should be removed from the
catman directory.  Note that this patch also modifies pathnames.h in the man
src directory (it adds _PATH_MAKEWHATIS).




-----cut-here-----
Index: Makefile
===================================================================
RCS file: /snarf/netbsd/master/src/usr.sbin/catman/Makefile,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 Makefile
--- Makefile	1995/11/16 02:29:24	1.1.1.1
+++ Makefile	1996/01/02 02:45:05
@@ -1,7 +1,8 @@
-#	$Id: Makefile,v 1.1.1.1 1995/11/16 02:29:24 kashmir Exp $
+#	$NetBSD$

 
-BINDIR=		/usr/sbin
 PROG=		catman
+SRCS=		catman.c config.c
 MAN=		catman.8
+.PATH:		${.CURDIR}/../../usr.bin/man

 
 .include <bsd.prog.mk>
Index: catman.8
===================================================================
RCS file: /snarf/netbsd/master/src/usr.sbin/catman/catman.8,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 catman.8
--- catman.8	1995/11/16 02:29:24	1.1.1.1
+++ catman.8	1996/01/02 02:29:22
@@ -1,3 +1,4 @@
+.\"	$NetBSD$
 .\"
 .\" Copyright (c) 1993 Winning Strategies, Inc.
 .\" All rights reserved.
@@ -27,9 +28,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\"	$Id: catman.8,v 1.1.1.1 1995/11/16 02:29:24 kashmir Exp $
-.\"
-.Dd July 30, 1993
+.Dd January 1, 1995
 .Dt CATMAN 8
 .Os
 .Sh NAME
@@ -38,13 +37,20 @@
 .Sh SYNOPSIS
 .Nm catman
 .Op Fl knpsw
+.Op Fl C Ar file
 .Op Fl M Ar directory
 .Op Ar sections
+.Nm catman
+.Op Fl C Ar file
+.Ar manpage
 .Sh DESCRIPTION
 .Nm Catman 
 creates formatted versions of the on-line manual pages from their 
 .Xr nroff 1
 source.
+.Pp
+The first form of the command operates on the man directories specified in
+/etc/man.conf.
 Manual pages whose formatted versions are missing or out of date are 
 regenerated.
 If manual pages are regenerated, 
@@ -66,6 +72,9 @@
 .Nm catman
 will try to operate on all of the known manual sections.
 .Pp
+The second form of the command takes a filename on the command line and
+generates formatted output to stdout.
+.Pp
 The options are as follows:
 .Bl -tag -width indent
 .It Fl k
@@ -86,15 +95,32 @@
 Only create the 
 .Nm whatis 
 database.
+.It Fl C Ar file
+Use the specified
+.Ar file
+instead of the default configuration file.
 .It Fl M Ar directory
 Update manual pages in 
 .Ar directory.
 .El
+.Sh ENVIRONMENT
+.Bl -tag -width MANPATH
+.It Ev MANPATH
+The standard search path may be overridden by specifying a path in the
+.Ev MANPATH
+environment variable.
+.El
+.Sh FILES
+.Bl -tag
+.It Pa /etc/man.conf
+default man configuration file.
+.El
+.Bl -tag
+.It Pa whatis.db
+name of the whatis database.
+.El
 .Sh SEE ALSO
 .Xr apropos 1 ,
 .Xr man 1 ,
 .Xr whatis 1
-.Sh BUGS
-Currently knows nothing about 
-.Pa /etc/man.conf 
-and machine specific man pages.
+.Xr man.conf 5
Index: catman.c
===================================================================
RCS file: /snarf/netbsd/master/src/usr.sbin/catman/catman.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 catman.c
--- catman.c	1995/11/16 02:29:24	1.1.1.1
+++ catman.c	1996/01/06 19:49:46
@@ -1,4 +1,7 @@
+/*	$NetBSD$	*/
+
 /*
+ * Copyright (c) 1996 Michael E. Grupenhoff.  All rights reserved.
  * Copyright (c) 1993 Winning Strategies, Inc.
  * All rights reserved.
  *
@@ -29,23 +32,28 @@
  */

 
 #ifndef lint
-static char rcsid[] = "$Id: catman.c,v 1.1.1.1 1995/11/16 02:29:24 kashmir Exp $";
+static char rcsid[] = "$NetBSD$";
 #endif /* not lint */

 
 #include <sys/types.h>
+#include <sys/queue.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
+
+#include <ctype.h>
 #include <dirent.h>
 #include <err.h>
 #include <errno.h>
+#include <fnmatch.h>
+#include <glob.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <paths.h>

 
-#include "pathnames.h"
+#include "../../usr.bin/man/config.h"
+#include "../../usr.bin/man/pathnames.h"

 
 int f_nowhatis;
 int f_noaction;
@@ -53,23 +61,29 @@
 int f_ignerr;
 int f_noprint;

 
-int dowhatis;
-
-char *mp = _PATH_MAN;
-char *sp = _MAN_SECTIONS;
-
-void usage __P((void));
-void catman __P((const char *, char *));
-void makewhatis __P((const char *));
+int catman __P((const char *));
+int dirformat __P((char *, char *, char *));
 void dosystem __P((const char *));
+void lncatpages __P((char *, char *, char *, char *, char *));
+void makedefault __P((char *));
+void makesubdir __P((const char *));
+void makewhatis __P((const char *));
+void mformat __P((char *, char *));
+void usage __P((void));

 
 int
 main(argc, argv)
 	int argc;
 	char **argv;
 {
-	int c;
+	int c, needwhatis;
+	char *conffile, *mp;
+	glob_t pg;
+	ENTRY *ep;
+	TAG *tp;

 
+	mp = NULL;
+	conffile = _PATH_MANCONF;
 	while ((c = getopt(argc, argv, "knpswM:")) != EOF) {
 		switch (c) {
 		case 'k':
@@ -87,6 +101,9 @@
 		case 'w':
 			f_noformat = 1;
 			break;
+		case 'C':
+			conffile = optarg;
+			break;
 		case 'M':
 			mp = optarg;
 			break;
@@ -105,37 +122,167 @@

 
 	if (argc > 1)
 		usage();
-	if (argc == 1)
-		sp = *argv;

 
-	if (f_noformat == 0 || f_nowhatis == 0)
-		catman(mp, sp);
-	if (f_nowhatis == 0 && dowhatis)
-		makewhatis(mp);
+	config(conffile);
+
+	/*
+	 * Remaining argument could either be an nroff source file, in
+	 * which case we format it to stdout, or a list of man sections.
+	 */
+	if (argc == 1)
+		if (access(*argv, F_OK) == 0) {
+			mformat(*argv, NULL);
+			exit(0);
+		} else
+			makesubdir(*argv);
+
+	if (mp != NULL || (mp = getenv("MANPATH")) != NULL)
+		makedefault(mp);
+
+	if ((tp = getlist("_default")) == NULL)
+		errx(1, "No manpath in %s.\n", _PATH_MANCONF);
+	for (ep = tp->list.tqh_first; ep != NULL; ep = ep->q.tqe_next) {
+		memset(&pg, 0, sizeof(pg));
+		if (glob(ep->s, GLOB_BRACE | GLOB_QUOTE, NULL, &pg) != 0)
+			err(1, "glob");
+		if (pg.gl_matchc == 0)
+			continue;
+		for (c = 0; pg.gl_pathv[c] != NULL; c++) {
+			if (f_noformat == 0 || f_nowhatis == 0)
+				needwhatis = catman(pg.gl_pathv[c]);
+			if (f_noformat || (needwhatis && f_nowhatis == 0))
+				makewhatis(pg.gl_pathv[c]);
+		}
+		globfree(&pg);
+	}

 
 	exit(0);
 }

 
-
-void
-catman(path, section)
+int
+catman(path)
 	const char *path;
-	char *section;
 {
+	int rval;
 	char mandir[PATH_MAX];
 	char catdir[PATH_MAX];
-	char manpage[PATH_MAX];
-	char catpage[PATH_MAX];
+	char *catsuffix, *slash;
+	TAG *subdirp, *sufp;
+	ENTRY *ep;
+
+	if (chdir(path) != 0) {
+		warn(path);
+		return (0);
+	}
+
+	if (path[strlen(path) - 1] == '/')
+		slash = "";
+	else
+		slash = "/";
+
+	if ((sufp = getlist("_suffix")) == NULL)
+		catsuffix = ".0";
+	else
+		catsuffix = sufp->list.tqh_first->s;
+
+	if ((subdirp = getlist("_subdir")) == NULL)
+		errx(1, "No man subdirectories to scan!\n");
+
+	rval = 0;
+	for (ep = subdirp->list.tqh_first; ep != NULL; ep = ep->q.tqe_next) {
+		if (strncmp(ep->s, "man", strlen("man")) != 0)
+			continue;
+		sprintf(mandir, "%s%s%s", path, slash, ep->s);
+		sprintf(catdir, "%s%scat%c", path, slash, ep->s[3]);
+		rval |= dirformat(mandir, catdir, catsuffix);
+	}
+
+	return (rval);
+}
+
+void
+makewhatis(path)
+	const char *path;
+{
 	char sysbuf[1024];
-	struct stat manstat;
-	struct stat catstat;
-	struct dirent *dp;
-	DIR *dirp;
-	char *s, *tmp;
-	int sectlen, error;

 
-	for (s = section; *s; s += sectlen) {
-#ifdef notdef
+	sprintf(sysbuf, "%s %s", _PATH_MAKEWHATIS, path);
+	if (f_noprint == 0)
+		printf("%s\n", sysbuf);
+	if (f_noaction == 0)
+		dosystem(sysbuf);
+}
+
+void
+dosystem(cmd)
+	const char *cmd;
+{
+	int status;
+
+	if ((status = system(cmd)) == 0)
+		return;
+
+	if (status == -1)
+		err(1, "cannot execute action");
+	if (WIFSIGNALED(status))
+		errx(1, "child was signaled to quit. aborting");
+	if (WIFSTOPPED(status))
+		errx(1, "child was stopped. aborting");
+	if (f_ignerr == 0)
+		errx(1, "*** Exited %d", status);
+	warnx("*** Exited %d (continuing)", status);
+}
+
+/*
+ * Replace the current _default entry
+ */
+void
+makedefault(mp)
+	char *mp;
+{
+	ENTRY *ep;
+	TAG *defp;
+	char *p;
+
+	if ((defp = getlist("_default")) == NULL)
+		defp = addlist("_default");
+	while ((ep = defp->list.tqh_first) != NULL) {
+		free(ep->s);
+		TAILQ_REMOVE(&defp->list, ep, q);
+		free(ep);
+	}
+
+	for (p = strsep(&mp, ":"); p != NULL; p = strsep(&mp, ":")) {
+		if (*p == '\0')
+			continue;
+		if ((ep = malloc(sizeof(ENTRY))) == NULL ||
+		    (ep->s = strdup(p)) == NULL)
+			errx(1, "Out of memory");
+		TAILQ_INSERT_TAIL(&defp->list, ep, q);
+	}
+}
+
+/*
+ * Replace the current _subdir entry
+ */
+void
+makesubdir(subsec)
+	const char *subsec;
+{
+	ENTRY *ep;
+	TAG *subdirp;
+	const char *s, *tmp;
+	int sectlen;
+
+	if ((subdirp = getlist("_subdir")) == NULL)
+		subdirp = addlist("_subdir");
+	while ((ep = subdirp->list.tqh_first) != NULL) {
+		free(ep->s);
+		TAILQ_REMOVE(&subdirp->list, ep, q);
+		free(ep);
+	}
+
+	for (s = subsec, sectlen = 0; *s; s += sectlen) {
 		tmp = s;
 		sectlen = 0;
 		if (isdigit(*tmp)) {
@@ -146,123 +293,225 @@
 				tmp++;
 			}
 		}
-#else
-		sectlen = 1;
-#endif
 		if (sectlen == 0)
-			errx(1, "malformed section string");
+			errx(1, "malformed section string \"%s\"", subsec);

 
-		sprintf(mandir, "%s/%s%.*s", path, _PATH_MANPAGES, sectlen, s);
-		sprintf(catdir, "%s/%s%.*s", path, _PATH_CATPAGES, sectlen, s);
+		if ((ep = malloc(sizeof(ENTRY))) == NULL ||
+		    (ep->s = malloc(sectlen + strlen("man") + 1)) == NULL)
+			err(1, "Out of memory");
+		sprintf(ep->s, "man%.*s", sectlen, s);
+		TAILQ_INSERT_TAIL(&subdirp->list, ep, q);
+	}
+}

 
-		if ((dirp = opendir(mandir)) == 0) {
-			warn("can't open %s", mandir);
+void
+lncatpages(mandir, manpage, catdir, catpage, catsuffix)
+	char *mandir, *manpage, *catdir, *catpage, *catsuffix;
+{
+	DIR *dirp;
+	struct dirent *dp;
+	struct stat st, manstat;
+	char manfile[PATH_MAX];
+	char catfile[PATH_MAX];
+	char *tmp;
+
+	if (stat(manpage, &manstat) < 0) {
+		warn("can't stat %s", manpage);
+		return;
+	}
+	if ((dirp = opendir(mandir)) == NULL) {
+		warn(mandir);
+		return;
+	}
+	while ((dp = readdir(dirp)) != NULL) {
+		if (strcmp(dp->d_name, ".") == 0 ||
+		    strcmp(dp->d_name, "..") == 0)
+			continue;
+		sprintf(manfile, "%s/%s", mandir, dp->d_name);
+		if (strcmp(manfile, manpage) == 0)
+			continue;
+		if (stat(manfile, &st) < 0) {
+			warn("can't stat %s", manfile);
 			continue;
 		}
-
-		if (stat(catdir, &catstat) < 0) {
-			if (errno != ENOENT) {
-				warn("can't stat %s", catdir);
-				closedir(dirp);
+		if (st.st_ino == manstat.st_ino) {
+			sprintf(catfile, "%s/%s", catdir, dp->d_name);
+			if ((tmp = strrchr(catfile, '.')) == NULL)
 				continue;
-			}
+			strcpy(tmp, catsuffix);
+			unlink(catfile);
 			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;
+				printf("ln %s %s\n", catpage, catfile);
+			if (f_noaction == 0 && link(catpage, catfile) < 0) {
+				warn("can't link %s to %s", catpage, catfile);
+				continue;
 			}
+		}
+	}
+	closedir(dirp);
+}

 
+/*
+ * Format all pages in mandir, placing the output in catdir.
+ */
+int
+dirformat(mandir, catdir, catsuffix)
+	char *mandir, *catdir, *catsuffix;
+{
+	int error, rval, symlink;
+	char manpage[PATH_MAX];
+	char catpage[PATH_MAX];
+	char *tmp, *mansuffix;
+	DIR *dirp;
+	struct dirent *dp;
+	struct stat manstat;
+	struct stat catstat;
+
+	if (chdir(mandir) || (dirp = opendir(".")) == NULL) {
+		if (errno != ENOENT)
+			warn(mandir);
+		return (0);
+	}
+	if (stat(catdir, &catstat) < 0) {
+		if (errno != ENOENT) {
+			warn("can't stat %s", catdir);
+			closedir(dirp);
+			return (0);
+		}
+		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 (0);
 		}

 
-		while ((dp = readdir(dirp)) != NULL) {
-			if (strcmp(dp->d_name, ".") == 0 ||
-			    strcmp(dp->d_name, "..") == 0)
-				continue;
+	}

 
-			sprintf(manpage, "%s/%s", mandir, dp->d_name);
-			sprintf(catpage, "%s/%s", catdir, dp->d_name);
-			if ((tmp = strrchr(catpage, '.')) != NULL)
-				strcpy(tmp, ".0");
-			else
-				continue;
+	rval = 0;
+	while ((dp = readdir(dirp)) != NULL) {
+		if (strcmp(dp->d_name, ".") == 0 ||
+		    strcmp(dp->d_name, "..") == 0)
+			continue;

 
+		sprintf(manpage, "%s/%s", mandir, dp->d_name);
+		sprintf(catpage, "%s/%s", catdir, dp->d_name);
+
+		if (lstat(manpage, &manstat) < 0) {
+			warn("can't stat %s", manpage);
+			continue;
+		}
+
+		symlink = 0;
+		if (S_ISLNK(manstat.st_mode)) {
+			symlink = 1;
 			if (stat(manpage, &manstat) < 0) {
 				warn("can't stat %s", manpage);
 				continue;
 			}
+		}

 
-			if (!S_ISREG(manstat.st_mode)) {
+		if (!S_ISREG(manstat.st_mode)) {
+			/*
+			 * Subdirectories within man directories contain
+			 * architecture specific pages.
+			 */
+			if (S_ISDIR(manstat.st_mode))
+				dirformat(manpage, catpage, catsuffix);
+			else
 				warnx("not a regular file %s", manpage);
-				continue;
-			}
-			if ((error = stat(catpage, &catstat)) &&
-			    errno != ENOENT) {
-				warn("can't stat %s", catpage);
-				continue;
-			}
-
-			if ((error && errno == ENOENT) || 
-			    manstat.st_mtime >= catstat.st_mtime) {
-				if (f_noformat)
-					dowhatis = 1;
-				else {
-					/*
-					 * manpage is out of date,
-					 * reformat
-					 */
-					sprintf(sysbuf, "nroff -mandoc %s > %s",
-					    manpage, catpage);
-					if (f_noprint == 0)
-						printf("%s\n", sysbuf);
-					if (f_noaction == 0)
-						dosystem(sysbuf);
-					dowhatis = 1;
-				}
-			}
+			continue;
 		}
-		closedir(dirp);
-	}
-}

 
-void
-makewhatis(path)
-	const char *path;
-{
-	char sysbuf[1024];
+		if ((mansuffix = strrchr(manpage, '.')) == NULL)
+			continue;
+		if ((tmp = strrchr(catpage, '.')) == NULL)
+			continue;
+		else
+			strcpy(tmp, catsuffix);

 
-	sprintf(sysbuf, "%s %s", _PATH_MAKEWHATIS, path);
-	if (f_noprint == 0)
-		printf("%s\n", sysbuf);
-	if (f_noaction == 0)
-		dosystem(sysbuf);
+		if ((error = stat(catpage, &catstat)) &&
+		    errno != ENOENT) {
+			warn("can't stat %s", catpage);
+			continue;
+		}
+
+		/*
+		 * If manpage is out of date, reformat
+		 */
+		if ((error && errno == ENOENT) || 
+		    (manstat.st_mtime >= catstat.st_mtime &&
+		    f_noformat == 0)) {
+			mformat(manpage, catpage);
+			/*
+			 * If manpages hardlinked together, duplicate
+			 * with catpages.
+			 */
+			if (manstat.st_nlink > 1 || symlink)
+				lncatpages(mandir, manpage, catdir, catpage,
+				    catsuffix);
+			rval = 1;
+		}
+	}
+	closedir(dirp);
+	return (rval);
 }

 
 void
-dosystem(cmd)
-	const char *cmd;
+mformat(manpage, catpage)
+	char *manpage, *catpage;
 {
-	int status;
-
-	if ((status = system(cmd)) == 0)
-		return;
+	int fnd;
+	char buf[1024], fmtbuf[1024], *p, *sufent, *mansuffix;
+	TAG *sufp;
+	ENTRY *e_sufp;
+
+	if ((mansuffix = strrchr(manpage, '.')) == NULL)
+		mansuffix = ".1";
+
+	if ((sufp = getlist("_build")) == NULL)
+		errx(1, "No _build keywords found in %s", _PATH_MANCONF);
+
+	for (fnd = 0, e_sufp = sufp->list.tqh_first; e_sufp != NULL;
+	    e_sufp = e_sufp->q.tqe_next) {
+		if ((sufent = strdup(e_sufp->s)) == NULL)
+			errx(1, "Out of memory");
+		for (p = sufent; *p != '\0' && !isspace(*p); p++);
+		if (*p == '\0') {
+			free(sufent);
+			continue;
+		}
+		*p = '\0';
+		if (fnmatch(sufent, mansuffix, 0) != 0) {
+			free(sufent);
+			continue;
+		}
+		fnd = 1;

 
-	if (status == -1)
-		err(1, "cannot execute action");
-	if (WIFSIGNALED(status))
-		errx(1, "child was signaled to quit. aborting");
-	if (WIFSTOPPED(status))
-		errx(1, "child was stopped. aborting");
-	if (f_ignerr == 0)
-		errx(1,"*** Exited %d");
-	warnx("*** Exited %d (continuing)");
+		for (++p; isspace(*p); p++);
+		/*
+		 * If catpage is NULL, then we send it to stdout
+		 */
+		if (catpage == NULL)
+			strncpy(fmtbuf, p, sizeof(fmtbuf));
+		else
+			snprintf(fmtbuf, sizeof(fmtbuf), "%s > %s", p, catpage);
+		snprintf(buf, sizeof(buf), fmtbuf, manpage);
+		if (f_noprint == 0 && catpage != NULL)
+			printf("%s\n", buf);
+		if (f_noaction == 0)
+			dosystem(buf);
+		free(sufent);
+	}
+	if (fnd == 0)
+		warnx("Don't know how to format %s", manpage);
 }

 
 void
 usage()
 {
 	(void)fprintf(stderr,
-	    "usage: catman [-knpsw] [-M manpath] [sections]\n");
+	    "usage: catman [-knpsw] [-C file] [-M manpath] [sections]\n"
+	    "       catman [-C file] manpage\n");
 	exit(1);
 }
Index: ../../usr.bin/man/config.c
===================================================================
RCS file: /snarf/netbsd/master/src/usr.bin/man/config.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 config.c
--- config.c	1995/11/16 02:27:52	1.1.1.1
+++ config.c	1996/01/02 02:43:53
@@ -119,12 +119,12 @@
 			while (*++t && isspace(*t));
 			if ((ep = malloc(sizeof(ENTRY))) == NULL ||
 			    (ep->s = strdup(t)) == NULL)
-				err(1, NULL);
+				err(1, "Out of memory");
 			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, NULL);
+				err(1, "Out of memory");
 			TAILQ_INSERT_TAIL(&tp->list, ep, q);
 		}
 	}
@@ -144,7 +144,7 @@

 
 	if ((tp = calloc(1, sizeof(TAG))) == NULL ||
 	    (tp->s = strdup(name)) == NULL)
-		err(1, NULL);
+		err(1, "Out of memory");
 	TAILQ_INIT(&tp->list);
 	TAILQ_INSERT_TAIL(&head, tp, q);
 	return (tp);
Index: ../../usr.bin/man/pathnames.h
===================================================================
RCS file: /snarf/netbsd/master/src/usr.bin/man/pathnames.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 pathnames.h
--- pathnames.h	1995/11/16 02:27:53	1.1.1.1
+++ pathnames.h	1996/01/01 20:16:32
@@ -35,6 +35,7 @@
  *	@(#)pathnames.h	8.3 (Berkeley) 1/2/94
  */

 
+#define	_PATH_MAKEWHATIS	"/usr/libexec/makewhatis"
 #define	_PATH_MANCONF	"/etc/man.conf"
 #define	_PATH_PAGER	"/usr/bin/more -s"
 #define	_PATH_TMP	"/tmp/man.XXXXXX"
-----cut-here-----




This final patch changes bsd.man.mk to use catman instead of nroff.
-----cut-here-----
Index: bsd.man.mk
===================================================================
RCS file: /snarf/netbsd/master/src/share/mk/bsd.man.mk,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 bsd.man.mk
--- bsd.man.mk	1995/12/15 12:08:10	1.1.1.2
+++ bsd.man.mk	1996/01/02 01:37:48
@@ -15,8 +15,8 @@
 	.cat7 .cat8 .cat9

 
 .9.cat9 .8.cat8 .7.cat7 .6.cat6 .5.cat5 .4.cat4 .3.cat3 .2.cat2 .1.cat1:
-	@echo "nroff -mandoc ${.IMPSRC} > ${.TARGET}"
-	@nroff -mandoc ${.IMPSRC} > ${.TARGET} || ( rm -f ${.TARGET} ; false )
+	@echo "catman ${.IMPSRC} > ${.TARGET}"
+	@catman ${.IMPSRC} > ${.TARGET} || ( rm -f ${.TARGET} ; false )

 
 .if defined(MAN) && !empty(MAN)
 MANALL=	${MAN:S/.1$/.cat1/g:S/.2$/.cat2/g:S/.3$/.cat3/g:S/.4$/.cat4/g:S/.5$/.cat5/g:S/.6$/.cat6/g:S/.7$/.cat7/g:S/.8$/.cat8/g:S/.9$/.cat9/g}
-----cut-here-----


>Release-Note:
>Audit-Trail:


From: Mike Grupenhoff <kashmir@umiacs.umd.edu>
To: gnats-bugs@gnats.netbsd.org
Cc:  Subject: Re: bin/1904
Date: Mon, 8 Jan 1996 20:25:28 -0500 (EST)


 The patch to catman that I sent in bin/1904 was incomplete with respect to
 handling manpages with extentions with more then one period (foo.1.gz, etc). 
 I wasn't sure at the time about the proper way to handle this, since a
 manpage might have a period in its name. 

 
 The previous patch did a strrchr(manpage, '.') to get the extension, 
 which obviously breaks with compressed pages.  At the bottom of this mail 
 is a patch which does a better job of guessing what the extension really 
 is.  Of course, if someone could guarantee to me that a manpage name will 
 never contain a '.', this could all be done a lot cleaner.  alas..

 
 I apologize for not getting this right the first time, in the first patch.  I
 had a moment of clarity today while shoveling snow, and came up with this
 workaround.  If you have a better way of handling this, let me know. 

 
 mike

 
 This patch should be applied after applying the one in bin/1904.

 
 Index: catman.c
 ===================================================================
 RCS file: /snarf/netbsd/master/src/usr.sbin/catman/catman.c,v
 retrieving revision 1.2
 diff -u -r1.2 catman.c
 --- catman.c	1996/01/07 15:50:45	1.2
 +++ catman.c	1996/01/08 01:51:53
 @@ -62,13 +62,14 @@
  int f_noprint;

  
  int catman __P((const char *));
 -int dirformat __P((char *, char *, char *));
 +int dirformat __P((char *, char *));
  void dosystem __P((const char *));
 -void lncatpages __P((char *, char *, char *, char *, char *));
 +void lncatpages __P((char *, char *, char *, char *));
  void makedefault __P((char *));
  void makesubdir __P((const char *));
  void makewhatis __P((const char *));
 -void mformat __P((char *, char *));
 +int mformat __P((char *, struct stat *, char *));
 +void mkcatsuff __P((char *, char *));
  void usage __P((void));

  
  int
 @@ -131,7 +132,7 @@
  	 */
  	if (argc == 1)
  		if (access(*argv, F_OK) == 0) {
 -			mformat(*argv, NULL);
 +			mformat(*argv, NULL, NULL);
  			exit(0);
  		} else
  			makesubdir(*argv);
 @@ -166,8 +167,8 @@
  	int rval;
  	char mandir[PATH_MAX];
  	char catdir[PATH_MAX];
 -	char *catsuffix, *slash;
 -	TAG *subdirp, *sufp;
 +	char *slash;
 +	TAG *subdirp;
  	ENTRY *ep;

  
  	if (chdir(path) != 0) {
 @@ -180,11 +181,6 @@
  	else
  		slash = "/";

  
 -	if ((sufp = getlist("_suffix")) == NULL)
 -		catsuffix = ".0";
 -	else
 -		catsuffix = sufp->list.tqh_first->s;
 -
  	if ((subdirp = getlist("_subdir")) == NULL)
  		errx(1, "No man subdirectories to scan!\n");

  
 @@ -194,7 +190,7 @@
  			continue;
  		sprintf(mandir, "%s%s%s", path, slash, ep->s);
  		sprintf(catdir, "%s%scat%c", path, slash, ep->s[3]);
 -		rval |= dirformat(mandir, catdir, catsuffix);
 +		rval |= dirformat(mandir, catdir);
  	}

  
  	return (rval);
 @@ -305,15 +301,14 @@
  }

  
  void
 -lncatpages(mandir, manpage, catdir, catpage, catsuffix)
 -	char *mandir, *manpage, *catdir, *catpage, *catsuffix;
 +lncatpages(mandir, manpage, catdir, catpage)
 +	char *mandir, *manpage, *catdir, *catpage;
  {
  	DIR *dirp;
  	struct dirent *dp;
  	struct stat st, manstat;
  	char manfile[PATH_MAX];
  	char catfile[PATH_MAX];
 -	char *tmp;

  
  	if (stat(manpage, &manstat) < 0) {
  		warn("can't stat %s", manpage);
 @@ -336,9 +331,7 @@
  		}
  		if (st.st_ino == manstat.st_ino) {
  			sprintf(catfile, "%s/%s", catdir, dp->d_name);
 -			if ((tmp = strrchr(catfile, '.')) == NULL)
 -				continue;
 -			strcpy(tmp, catsuffix);
 +			mkcatsuff(manfile, catfile);
  			unlink(catfile);
  			if (f_noprint == 0)
  				printf("ln %s %s\n", catpage, catfile);
 @@ -355,24 +348,22 @@
   * Format all pages in mandir, placing the output in catdir.
   */
  int
 -dirformat(mandir, catdir, catsuffix)
 -	char *mandir, *catdir, *catsuffix;
 +dirformat(mandir, catdir)
 +	char *mandir, *catdir;
  {
 -	int error, rval, symlink;
 +	int rval, slink;
  	char manpage[PATH_MAX];
  	char catpage[PATH_MAX];
 -	char *tmp, *mansuffix;
  	DIR *dirp;
  	struct dirent *dp;
  	struct stat manstat;
 -	struct stat catstat;

  
  	if (chdir(mandir) || (dirp = opendir(".")) == NULL) {
  		if (errno != ENOENT)
  			warn(mandir);
  		return (0);
  	}
 -	if (stat(catdir, &catstat) < 0) {
 +	if (stat(catdir, &manstat) < 0) {
  		if (errno != ENOENT) {
  			warn("can't stat %s", catdir);
  			closedir(dirp);
 @@ -402,9 +393,9 @@
  			continue;
  		}

  
 -		symlink = 0;
 +		slink = 0;
  		if (S_ISLNK(manstat.st_mode)) {
 -			symlink = 1;
 +			slink = 1;
  			if (stat(manpage, &manstat) < 0) {
  				warn("can't stat %s", manpage);
  				continue;
 @@ -417,39 +408,19 @@
  			 * architecture specific pages.
  			 */
  			if (S_ISDIR(manstat.st_mode))
 -				dirformat(manpage, catpage, catsuffix);
 +				dirformat(manpage, catpage);
  			else
  				warnx("not a regular file %s", manpage);
  			continue;
  		}

  
 -		if ((mansuffix = strrchr(manpage, '.')) == NULL)
 -			continue;
 -		if ((tmp = strrchr(catpage, '.')) == NULL)
 -			continue;
 -		else
 -			strcpy(tmp, catsuffix);
 -
 -		if ((error = stat(catpage, &catstat)) &&
 -		    errno != ENOENT) {
 -			warn("can't stat %s", catpage);
 -			continue;
 -		}
 -
 -		/*
 -		 * If manpage is out of date, reformat
 -		 */
 -		if ((error && errno == ENOENT) || 
 -		    (manstat.st_mtime >= catstat.st_mtime &&
 -		    f_noformat == 0)) {
 -			mformat(manpage, catpage);
 +		if (mformat(manpage, &manstat, catpage)) {
  			/*
  			 * If manpages hardlinked together, duplicate
  			 * with catpages.
  			 */
 -			if (manstat.st_nlink > 1 || symlink)
 -				lncatpages(mandir, manpage, catdir, catpage,
 -				    catsuffix);
 +			if (manstat.st_nlink > 1 || slink)
 +				lncatpages(mandir, manpage, catdir, catpage);
  			rval = 1;
  		}
  	}
 @@ -457,12 +428,14 @@
  	return (rval);
  }

  
 -void
 -mformat(manpage, catpage)
 +int
 +mformat(manpage, manstat, catpage)
  	char *manpage, *catpage;
 +	struct stat *manstat;
  {
 -	int fnd;
 +	int error, fnd, rval;
  	char buf[1024], fmtbuf[1024], *p, *sufent, *mansuffix;
 +	struct stat catstat;
  	TAG *sufp;
  	ENTRY *e_sufp;

  
 @@ -472,7 +445,7 @@
  	if ((sufp = getlist("_build")) == NULL)
  		errx(1, "No _build keywords found in %s", _PATH_MANCONF);

  
 -	for (fnd = 0, e_sufp = sufp->list.tqh_first; e_sufp != NULL;
 +	for (rval = fnd = 0, e_sufp = sufp->list.tqh_first; e_sufp != NULL;
  	    e_sufp = e_sufp->q.tqe_next) {
  		if ((sufent = strdup(e_sufp->s)) == NULL)
  			errx(1, "Out of memory");
 @@ -482,7 +455,9 @@
  			continue;
  		}
  		*p = '\0';
 -		if (fnmatch(sufent, mansuffix, 0) != 0) {
 +
 +		snprintf(buf, sizeof(buf), "*%s", sufent);
 +		if (fnmatch(buf, manpage, 0) != 0) {
  			free(sufent);
  			continue;
  		}
 @@ -494,17 +469,70 @@
  		 */
  		if (catpage == NULL)
  			strncpy(fmtbuf, p, sizeof(fmtbuf));
 -		else
 -			snprintf(fmtbuf, sizeof(fmtbuf), "%s > %s", p, catpage);
 +		else {
 +			mkcatsuff(sufent, catpage);
 +			if ((error = stat(catpage, &catstat)) &&
 +			    errno != ENOENT) {
 +				warn("can't stat %s", catpage);
 +				continue;
 +			}
 +
 +			/*
 +			 * See if manpage is out of date.
 +			 */
 +			if ((error && errno == ENOENT) || 
 +			    (manstat->st_mtime >= catstat.st_mtime &&
 +			    f_noformat == 0))
 +				snprintf(fmtbuf, sizeof(fmtbuf), "%s > %s", p,
 +				    catpage);
 +			else {
 +				free(sufent);
 +				break;
 +			}
 +		}
  		snprintf(buf, sizeof(buf), fmtbuf, manpage);
  		if (f_noprint == 0 && catpage != NULL)
  			printf("%s\n", buf);
  		if (f_noaction == 0)
  			dosystem(buf);
  		free(sufent);
 +		rval = 1;
  	}
  	if (fnd == 0)
  		warnx("Don't know how to format %s", manpage);
 +	return (rval);
 +}
 +
 +/*
 + * Given a path to a manpage and a path to a catpage, change
 + * the catpage suffix to _suffix.
 + */
 +void
 +mkcatsuff(mansuffix, catpage)
 +	char *mansuffix, *catpage;
 +{
 +	int ndots;
 +	char *q;
 +	static char *catsuffix = NULL;
 +	TAG *sufp;
 +
 +	if (catsuffix == NULL)
 +		if ((sufp = getlist("_suffix")) == NULL)
 +			catsuffix = ".0";
 +		else
 +			catsuffix = sufp->list.tqh_first->s;
 +
 +	/*
 +	 * Hack:  We count the number of dots in the manpage suffix
 +	 * and jump back that many dots in the catpage.
 +	 */
 +	for (ndots = 0, q = mansuffix; *q; q++)
 +		if (*q == '.')
 +			ndots++;
 +	for (q = catpage + strlen(catpage); ndots; q--)
 +		if (*q == '.')
 +			ndots--;
 +	strcpy(q + 1, catsuffix);
  }

  
  void


Responsible-Changed-From-To: bin-bug-people->mikel
Responsible-Changed-By: mikel
Responsible-Changed-When: Sat Sep 27 23:06:15 1997
Responsible-Changed-Why:
I'm handling this one.

 
Responsible-Changed-From-To: mikel->bin-bug-people 
Responsible-Changed-By: fair 
Responsible-Changed-When: Thu Mar 22 12:29:11 PST 2001 
Responsible-Changed-Why:  
Mike Long's E-mail address now bounces, so he appears to have vanished. 
Back to the role account this PR goes, ready for some other intrepid 
developer to step up to the plate. 
>Unformatted:



NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.36 2007/11/24 03:27:39 kano Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.