source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Rename mandoc-db to makewhatis.
@ 2011-05-13  0:42 kristaps
  0 siblings, 0 replies; only message in thread
From: kristaps @ 2011-05-13  0:42 UTC (permalink / raw)
  To: source

Log Message:
-----------
Rename mandoc-db to makewhatis.  On the suggestion of schwarze@; I agree.
Add initial version notes.

Modified Files:
--------------
    mdocml:
        Makefile
        index.sgml

Added Files:
-----------
    mdocml:
        makewhatis.1
        makewhatis.c

Removed Files:
-------------
    mdocml:
        mandoc-db.1
        mandoc-db.c

Revision Data
-------------
--- /dev/null
+++ makewhatis.c
@@ -0,0 +1,962 @@
+/*	$Id: makewhatis.c,v 1.1 2011/05/13 00:42:26 kristaps Exp $ */
+/*
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+
+#include <assert.h>
+#ifdef __linux__
+# include <db_185.h>
+#else
+# include <db.h>
+#endif
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "man.h"
+#include "mdoc.h"
+#include "mandoc.h"
+
+#define	MANDOC_DB	 "mandoc.db"
+#define	MANDOC_IDX	 "mandoc.index"
+#define	MANDOC_BUFSZ	  BUFSIZ
+#define	MANDOC_FLAGS	  O_CREAT|O_TRUNC|O_RDWR
+
+enum	type {
+	MANDOC_NONE = 0,
+	MANDOC_NAME,
+	MANDOC_FUNCTION,
+	MANDOC_UTILITY,
+	MANDOC_INCLUDES,
+	MANDOC_VARIABLE,
+	MANDOC_STANDARD,
+	MANDOC_AUTHOR,
+	MANDOC_CONFIG
+};
+
+#define	MAN_ARGS	  DB *db, \
+			  const char *dbn, \
+			  DBT *key, size_t *ksz, \
+			  DBT *val, \
+			  DBT *rval, size_t *rsz, \
+			  const struct man_node *n
+#define	MDOC_ARGS	  DB *db, \
+			  const char *dbn, \
+			  DBT *key, size_t *ksz, \
+			  DBT *val, \
+			  DBT *rval, size_t *rsz, \
+			  const struct mdoc_node *n
+
+static	void		  dbt_append(DBT *, size_t *, const char *);
+static	void		  dbt_appendb(DBT *, size_t *, 
+				const void *, size_t);
+static	void		  dbt_init(DBT *, size_t *);
+static	void		  dbt_put(DB *, const char *, DBT *, DBT *);
+static	void		  usage(void);
+static	void		  pman(DB *, const char *, DBT *, size_t *, 
+				DBT *, DBT *, size_t *, struct man *);
+static	int		  pman_node(MAN_ARGS);
+static	void		  pmdoc(DB *, const char *, DBT *, size_t *, 
+				DBT *, DBT *, size_t *, struct mdoc *);
+static	void		  pmdoc_node(MDOC_ARGS);
+static	void		  pmdoc_An(MDOC_ARGS);
+static	void		  pmdoc_Cd(MDOC_ARGS);
+static	void		  pmdoc_Fd(MDOC_ARGS);
+static	void		  pmdoc_In(MDOC_ARGS);
+static	void		  pmdoc_Fn(MDOC_ARGS);
+static	void		  pmdoc_Fo(MDOC_ARGS);
+static	void		  pmdoc_Nd(MDOC_ARGS);
+static	void		  pmdoc_Nm(MDOC_ARGS);
+static	void		  pmdoc_St(MDOC_ARGS);
+static	void		  pmdoc_Vt(MDOC_ARGS);
+
+typedef	void		(*pmdoc_nf)(MDOC_ARGS);
+
+static	const char	 *progname;
+
+static	const pmdoc_nf	  mdocs[MDOC_MAX] = {
+	NULL, /* Ap */
+	NULL, /* Dd */
+	NULL, /* Dt */
+	NULL, /* Os */
+	NULL, /* Sh */ 
+	NULL, /* Ss */ 
+	NULL, /* Pp */ 
+	NULL, /* D1 */
+	NULL, /* Dl */
+	NULL, /* Bd */
+	NULL, /* Ed */
+	NULL, /* Bl */ 
+	NULL, /* El */
+	NULL, /* It */
+	NULL, /* Ad */ 
+	pmdoc_An, /* An */ 
+	NULL, /* Ar */
+	pmdoc_Cd, /* Cd */ 
+	NULL, /* Cm */
+	NULL, /* Dv */ 
+	NULL, /* Er */ 
+	NULL, /* Ev */ 
+	NULL, /* Ex */ 
+	NULL, /* Fa */ 
+	pmdoc_Fd, /* Fd */
+	NULL, /* Fl */
+	pmdoc_Fn, /* Fn */ 
+	NULL, /* Ft */ 
+	NULL, /* Ic */ 
+	pmdoc_In, /* In */ 
+	NULL, /* Li */
+	pmdoc_Nd, /* Nd */
+	pmdoc_Nm, /* Nm */
+	NULL, /* Op */
+	NULL, /* Ot */
+	NULL, /* Pa */
+	NULL, /* Rv */
+	pmdoc_St, /* St */ 
+	pmdoc_Vt, /* Va */
+	pmdoc_Vt, /* Vt */ 
+	NULL, /* Xr */ 
+	NULL, /* %A */
+	NULL, /* %B */
+	NULL, /* %D */
+	NULL, /* %I */
+	NULL, /* %J */
+	NULL, /* %N */
+	NULL, /* %O */
+	NULL, /* %P */
+	NULL, /* %R */
+	NULL, /* %T */
+	NULL, /* %V */
+	NULL, /* Ac */
+	NULL, /* Ao */
+	NULL, /* Aq */
+	NULL, /* At */ 
+	NULL, /* Bc */
+	NULL, /* Bf */
+	NULL, /* Bo */
+	NULL, /* Bq */
+	NULL, /* Bsx */
+	NULL, /* Bx */
+	NULL, /* Db */
+	NULL, /* Dc */
+	NULL, /* Do */
+	NULL, /* Dq */
+	NULL, /* Ec */
+	NULL, /* Ef */ 
+	NULL, /* Em */ 
+	NULL, /* Eo */
+	NULL, /* Fx */
+	NULL, /* Ms */ 
+	NULL, /* No */
+	NULL, /* Ns */
+	NULL, /* Nx */
+	NULL, /* Ox */
+	NULL, /* Pc */
+	NULL, /* Pf */
+	NULL, /* Po */
+	NULL, /* Pq */
+	NULL, /* Qc */
+	NULL, /* Ql */
+	NULL, /* Qo */
+	NULL, /* Qq */
+	NULL, /* Re */
+	NULL, /* Rs */
+	NULL, /* Sc */
+	NULL, /* So */
+	NULL, /* Sq */
+	NULL, /* Sm */ 
+	NULL, /* Sx */
+	NULL, /* Sy */
+	NULL, /* Tn */
+	NULL, /* Ux */
+	NULL, /* Xc */
+	NULL, /* Xo */
+	pmdoc_Fo, /* Fo */ 
+	NULL, /* Fc */ 
+	NULL, /* Oo */
+	NULL, /* Oc */
+	NULL, /* Bk */
+	NULL, /* Ek */
+	NULL, /* Bt */
+	NULL, /* Hf */
+	NULL, /* Fr */
+	NULL, /* Ud */
+	NULL, /* Lb */
+	NULL, /* Lp */ 
+	NULL, /* Lk */ 
+	NULL, /* Mt */ 
+	NULL, /* Brq */ 
+	NULL, /* Bro */ 
+	NULL, /* Brc */ 
+	NULL, /* %C */
+	NULL, /* Es */
+	NULL, /* En */
+	NULL, /* Dx */
+	NULL, /* %Q */
+	NULL, /* br */
+	NULL, /* sp */
+	NULL, /* %U */
+	NULL, /* Ta */
+};
+
+int
+main(int argc, char *argv[])
+{
+	struct mparse	*mp; /* parse sequence */
+	struct mdoc	*mdoc; /* resulting mdoc */
+	struct man	*man; /* resulting man */
+	char		*fn; /* current file being parsed */
+	const char	*msec, /* manual section */
+	      	 	*mtitle, /* manual title */
+			*arch, /* manual architecture */
+	      		*dir; /* result dir (default: cwd) */
+	char		 ibuf[MAXPATHLEN], /* index fname */
+			 ibbuf[MAXPATHLEN], /* index backup fname */
+			 fbuf[MAXPATHLEN],  /* btree fname */
+			 fbbuf[MAXPATHLEN]; /* btree backup fname */
+	int		 ch;
+	DB		*idx, /* index database */
+			*db; /* keyword database */
+	DBT		 rkey, rval, /* recno entries */
+			 key, val; /* persistent keyword entries */
+	size_t		 sv,
+			 ksz, rsz; /* entry buffer size */
+	char		 vbuf[8]; /* stringified record number */
+	BTREEINFO	 info; /* btree configuration */
+	recno_t		 rec; /* current record number */
+	extern int	 optind;
+	extern char	*optarg;
+
+	progname = strrchr(argv[0], '/');
+	if (progname == NULL)
+		progname = argv[0];
+	else
+		++progname;
+
+	dir = "";
+
+	while (-1 != (ch = getopt(argc, argv, "d:")))
+		switch (ch) {
+		case ('d'):
+			dir = optarg;
+			break;
+		default:
+			usage();
+			return((int)MANDOCLEVEL_BADARG);
+		}
+
+	argc -= optind;
+	argv += optind;
+
+	/*
+	 * Set up temporary file-names into which we're going to write
+	 * all of our data (both for the index and database).  These
+	 * will be securely renamed to the real file-names after we've
+	 * written all of our data.
+	 */
+
+	ibuf[0] = ibuf[MAXPATHLEN - 2] =
+		ibbuf[0] = ibbuf[MAXPATHLEN - 2] = 
+		fbuf[0] = fbuf[MAXPATHLEN - 2] = 
+		fbbuf[0] = fbbuf[MAXPATHLEN - 2] = '\0';
+
+	strlcat(fbuf, dir, MAXPATHLEN);
+	strlcat(fbuf, MANDOC_DB, MAXPATHLEN);
+
+	strlcat(fbbuf, fbuf, MAXPATHLEN);
+	strlcat(fbbuf, "~", MAXPATHLEN);
+
+	strlcat(ibuf, dir, MAXPATHLEN);
+	strlcat(ibuf, MANDOC_IDX, MAXPATHLEN);
+
+	strlcat(ibbuf, ibuf, MAXPATHLEN);
+	strlcat(ibbuf, "~", MAXPATHLEN);
+
+	if ('\0' != fbuf[MAXPATHLEN - 2] ||
+			'\0' != fbbuf[MAXPATHLEN - 2] ||
+			'\0' != ibuf[MAXPATHLEN - 2] ||
+			'\0' != ibbuf[MAXPATHLEN - 2]) {
+		fprintf(stderr, "%s: Path too long\n", progname);
+		exit((int)MANDOCLEVEL_SYSERR);
+	}
+
+	/*
+	 * For the keyword database, open a BTREE database that allows
+	 * duplicates.  For the index database, use a standard RECNO
+	 * database type.
+	 */
+
+	memset(&info, 0, sizeof(BTREEINFO));
+	info.flags = R_DUP;
+	db = dbopen(fbbuf, MANDOC_FLAGS, 0644, DB_BTREE, &info);
+
+	if (NULL == db) {
+		perror(fbbuf);
+		exit((int)MANDOCLEVEL_SYSERR);
+	}
+
+	idx = dbopen(ibbuf, MANDOC_FLAGS, 0644, DB_RECNO, NULL);
+
+	if (NULL == db) {
+		perror(ibbuf);
+		(*db->close)(db);
+		exit((int)MANDOCLEVEL_SYSERR);
+	}
+
+	/*
+	 * Try parsing the manuals given on the command line.  If we
+	 * totally fail, then just keep on going.  Take resulting trees
+	 * and push them down into the database code.
+	 * Use the auto-parser and don't report any errors.
+	 */
+
+	mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL);
+
+	memset(&key, 0, sizeof(DBT));
+	memset(&val, 0, sizeof(DBT));
+	memset(&rkey, 0, sizeof(DBT));
+	memset(&rval, 0, sizeof(DBT));
+
+	val.size = sizeof(vbuf);
+	val.data = vbuf;
+	rkey.size = sizeof(recno_t);
+
+	rec = 1;
+	ksz = rsz = 0;
+
+	while (NULL != (fn = *argv++)) {
+		mparse_reset(mp);
+
+		/* Parse and get (non-empty) AST. */
+
+		if (mparse_readfd(mp, -1, fn) >= MANDOCLEVEL_FATAL) {
+			fprintf(stderr, "%s: Parse failure\n", fn);
+			continue;
+		}
+		mparse_result(mp, &mdoc, &man);
+		if (NULL == mdoc && NULL == man)
+			continue;
+
+		/* Manual section: can be empty string. */
+
+		msec = NULL != mdoc ? 
+			mdoc_meta(mdoc)->msec :
+			man_meta(man)->msec;
+		mtitle = NULL != mdoc ? 
+			mdoc_meta(mdoc)->title :
+			man_meta(man)->title;
+		arch = NULL != mdoc ? mdoc_meta(mdoc)->arch : NULL;
+
+		assert(msec);
+		assert(mtitle);
+
+		/* 
+		 * The index record value consists of a nil-terminated
+		 * filename, a nil-terminated manual section, and a
+		 * nil-terminated description.  Since the description
+		 * may not be set, we set a sentinel to see if we're
+		 * going to write a nil byte in its place.
+		 */
+
+		dbt_init(&rval, &rsz);
+		dbt_appendb(&rval, &rsz, fn, strlen(fn) + 1);
+		dbt_appendb(&rval, &rsz, msec, strlen(msec) + 1);
+		dbt_appendb(&rval, &rsz, mtitle, strlen(mtitle) + 1);
+		dbt_appendb(&rval, &rsz, arch ? arch : "", 
+				arch ? strlen(arch) + 1 : 1);
+
+		sv = rval.size;
+
+		/* Fix the record number in the btree value. */
+
+		memset(val.data, 0, sizeof(uint32_t));
+		memcpy(val.data + 4, &rec, sizeof(uint32_t));
+
+		if (mdoc)
+			pmdoc(db, fbbuf, &key, &ksz, 
+				&val, &rval, &rsz, mdoc);
+		else 
+			pman(db, fbbuf, &key, &ksz, 
+				&val, &rval, &rsz, man);
+		
+		/*
+		 * Apply this to the index.  If we haven't had a
+		 * description set, put an empty one in now.
+		 */
+
+		if (rval.size == sv)
+			dbt_appendb(&rval, &rsz, "", 1);
+
+		rkey.data = &rec;
+		dbt_put(idx, ibbuf, &rkey, &rval);
+
+		printf("Indexed: %s\n", fn);
+		rec++;
+	}
+
+	(*db->close)(db);
+	(*idx->close)(idx);
+
+	mparse_free(mp);
+
+	free(key.data);
+	free(rval.data);
+
+	/* Atomically replace the file with our temporary one. */
+
+	if (-1 == rename(fbbuf, fbuf))
+		perror(fbuf);
+	if (-1 == rename(ibbuf, ibuf))
+		perror(fbuf);
+
+	return((int)MANDOCLEVEL_OK);
+}
+
+/*
+ * Initialise the stored database key whose data buffer is shared
+ * between uses (as the key must sometimes be constructed from an array
+ * of 
+ */
+static void
+dbt_init(DBT *key, size_t *ksz)
+{
+
+	if (0 == *ksz) {
+		assert(0 == key->size);
+		assert(NULL == key->data);
+		key->data = mandoc_malloc(MANDOC_BUFSZ);
+		*ksz = MANDOC_BUFSZ;
+	}
+
+	key->size = 0;
+}
+
+/*
+ * Append a binary value to a database entry.  This can be invoked
+ * multiple times; the buffer is automatically resized.
+ */
+static void
+dbt_appendb(DBT *key, size_t *ksz, const void *cp, size_t sz)
+{
+
+	assert(key->data);
+
+	/* Overshoot by MANDOC_BUFSZ. */
+
+	while (key->size + sz >= *ksz) {
+		*ksz = key->size + sz + MANDOC_BUFSZ;
+		key->data = mandoc_realloc(key->data, *ksz);
+	}
+
+#if 0
+	dstp = key->data + (int)key->size;
+
+	while (NULL != (endp = memchr(cp, '\\', sz))) {
+		ssz = endp - cp;
+		memcpy(dstp, cp, ssz);
+
+		dstp += ssz;
+		key->size += ssz;
+		sz -= ssz;
+
+		cp = endp++;
+		/* FIXME: expects nil-terminated string! */
+		esc = mandoc_escape((const char **)&endp, NULL, NULL);
+
+		switch (esc) {
+		case (ESCAPE_ERROR):
+			/* Nil-terminate this point. */
+			memcpy(dstp, "", 1);
+			key->size++;
+			return;
+		case (ESCAPE_PREDEF):
+			/* FALLTHROUGH */
+		case (ESCAPE_SPECIAL):
+			break;
+		default:
+			sz -= endp - cp;
+			cp = endp;
+			continue;
+		}
+
+		ssz = endp - cp;
+		memcpy(dstp, cp, ssz);
+
+		dstp += ssz;
+		key->size += ssz;
+		sz -= ssz;
+
+		cp = endp;
+	}
+#endif
+
+	memcpy(key->data + (int)key->size, cp, sz);
+	key->size += sz;
+}
+
+/*
+ * Append a nil-terminated string to the database entry.  This can be
+ * invoked multiple times.  The database entry will be nil-terminated as
+ * well; if invoked multiple times, a space is put between strings.
+ */
+static void
+dbt_append(DBT *key, size_t *ksz, const char *cp)
+{
+	size_t		 sz;
+
+	if (0 == (sz = strlen(cp)))
+		return;
+
+	assert(key->data);
+
+	if (key->size)
+		((char *)key->data)[(int)key->size - 1] = ' ';
+
+	dbt_appendb(key, ksz, cp, sz + 1);
+}
+
+/* ARGSUSED */
+static void
+pmdoc_An(MDOC_ARGS)
+{
+	uint32_t	 fl;
+	
+	if (SEC_AUTHORS != n->sec)
+		return;
+
+	for (n = n->child; n; n = n->next)
+		if (MDOC_TEXT == n->type)
+			dbt_append(key, ksz, n->string);
+
+	fl = (uint32_t)MANDOC_AUTHOR;
+	memcpy(val->data, &fl, 4);
+}
+
+/* ARGSUSED */
+static void
+pmdoc_Fd(MDOC_ARGS)
+{
+	uint32_t	 fl;
+	const char	*start, *end;
+	size_t		 sz;
+	
+	if (SEC_SYNOPSIS != n->sec)
+		return;
+	if (NULL == (n = n->child) || MDOC_TEXT != n->type)
+		return;
+
+	/*
+	 * Only consider those `Fd' macro fields that begin with an
+	 * "inclusion" token (versus, e.g., #define).
+	 */
+	if (strcmp("#include", n->string))
+		return;
+
+	if (NULL == (n = n->next) || MDOC_TEXT != n->type)
+		return;
+
+	/*
+	 * Strip away the enclosing angle brackets and make sure we're
+	 * not zero-length.
+	 */
+
+	start = n->string;
+	if ('<' == *start || '"' == *start)
+		start++;
+
+	if (0 == (sz = strlen(start)))
+		return;
+
+	end = &start[(int)sz - 1];
+	if ('>' == *end || '"' == *end)
+		end--;
+
+	assert(end >= start);
+	dbt_appendb(key, ksz, start, (size_t)(end - start + 1));
+	dbt_appendb(key, ksz, "", 1);
+
+	fl = (uint32_t)MANDOC_INCLUDES;
+	memcpy(val->data, &fl, 4);
+}
+
+/* ARGSUSED */
+static void
+pmdoc_Cd(MDOC_ARGS)
+{
+	uint32_t	 fl;
+	
+	if (SEC_SYNOPSIS != n->sec)
+		return;
+
+	for (n = n->child; n; n = n->next)
+		if (MDOC_TEXT == n->type)
+			dbt_append(key, ksz, n->string);
+
+	fl = (uint32_t)MANDOC_CONFIG;
+	memcpy(val->data, &fl, 4);
+}
+
+/* ARGSUSED */
+static void
+pmdoc_In(MDOC_ARGS)
+{
+	uint32_t	 fl;
+	
+	if (SEC_SYNOPSIS != n->sec)
+		return;
+	if (NULL == n->child || MDOC_TEXT != n->child->type)
+		return;
+
+	dbt_append(key, ksz, n->child->string);
+	fl = (uint32_t)MANDOC_INCLUDES;
+	memcpy(val->data, &fl, 4);
+}
+
+/* ARGSUSED */
+static void
+pmdoc_Fn(MDOC_ARGS)
+{
+	uint32_t	 fl;
+	const char	*cp;
+	
+	if (SEC_SYNOPSIS != n->sec)
+		return;
+	if (NULL == n->child || MDOC_TEXT != n->child->type)
+		return;
+
+	/* .Fn "struct type *arg" "foo" */
+
+	cp = strrchr(n->child->string, ' ');
+	if (NULL == cp)
+		cp = n->child->string;
+
+	/* Strip away pointer symbol. */
+
+	while ('*' == *cp)
+		cp++;
+
+	dbt_append(key, ksz, cp);
+	fl = (uint32_t)MANDOC_FUNCTION;
+	memcpy(val->data, &fl, 4);
+}
+
+/* ARGSUSED */
+static void
+pmdoc_St(MDOC_ARGS)
+{
+	uint32_t	 fl;
+	
+	if (SEC_STANDARDS != n->sec)
+		return;
+	if (NULL == n->child || MDOC_TEXT != n->child->type)
+		return;
+
+	dbt_append(key, ksz, n->child->string);
+	fl = (uint32_t)MANDOC_STANDARD;
+	memcpy(val->data, &fl, 4);
+}
+
+/* ARGSUSED */
+static void
+pmdoc_Vt(MDOC_ARGS)
+{
+	uint32_t	 fl;
+	const char	*start;
+	size_t		 sz;
+	
+	if (SEC_SYNOPSIS != n->sec)
+		return;
+	if (MDOC_Vt == n->tok && MDOC_BODY != n->type)
+		return;
+	if (NULL == n->last || MDOC_TEXT != n->last->type)
+		return;
+
+	/*
+	 * Strip away leading pointer symbol '*' and trailing ';'.
+	 */
+
+	start = n->last->string;
+
+	while ('*' == *start)
+		start++;
+
+	if (0 == (sz = strlen(start)))
+		return;
+
+	if (';' == start[(int)sz - 1])
+		sz--;
+
+	if (0 == sz)
+		return;
+
+	dbt_appendb(key, ksz, start, sz);
+	dbt_appendb(key, ksz, "", 1);
+
+	fl = (uint32_t)MANDOC_VARIABLE;
+	memcpy(val->data, &fl, 4);
+}
+
+/* ARGSUSED */
+static void
+pmdoc_Fo(MDOC_ARGS)
+{
+	uint32_t	 fl;
+	
+	if (SEC_SYNOPSIS != n->sec || MDOC_HEAD != n->type)
+		return;
+	if (NULL == n->child || MDOC_TEXT != n->child->type)
+		return;
+
+	dbt_append(key, ksz, n->child->string);
+	fl = (uint32_t)MANDOC_FUNCTION;
+	memcpy(val->data, &fl, 4);
+}
+
+
+/* ARGSUSED */
+static void
+pmdoc_Nd(MDOC_ARGS)
+{
+	int		 first;
+	
+	for (first = 1, n = n->child; n; n = n->next) {
+		if (MDOC_TEXT != n->type)
+			continue;
+		if (first) 
+			dbt_appendb(rval, rsz, n->string, strlen(n->string) + 1);
+		else
+			dbt_append(rval, rsz, n->string);
+		first = 0;
+	}
+}
+
+/* ARGSUSED */
+static void
+pmdoc_Nm(MDOC_ARGS)
+{
+	uint32_t	 fl;
+	
+	if (SEC_NAME == n->sec) {
+		for (n = n->child; n; n = n->next) {
+			if (MDOC_TEXT != n->type)
+				continue;
+			dbt_append(key, ksz, n->string);
+		}
+		fl = (uint32_t)MANDOC_NAME;
+		memcpy(val->data, &fl, 4);
+		return;
+	} else if (SEC_SYNOPSIS != n->sec || MDOC_HEAD != n->type)
+		return;
+
+	for (n = n->child; n; n = n->next) {
+		if (MDOC_TEXT != n->type)
+			continue;
+		dbt_append(key, ksz, n->string);
+	}
+
+	fl = (uint32_t)MANDOC_UTILITY;
+	memcpy(val->data, &fl, 4);
+}
+
+static void
+dbt_put(DB *db, const char *dbn, DBT *key, DBT *val)
+{
+
+	if (0 == key->size)
+		return;
+
+	assert(key->data);
+	assert(val->size);
+	assert(val->data);
+
+	if (0 == (*db->put)(db, key, val, 0))
+		return;
+	
+	perror(dbn);
+	exit((int)MANDOCLEVEL_SYSERR);
+	/* NOTREACHED */
+}
+
+/*
+ * Call out to per-macro handlers after clearing the persistent database
+ * key.  If the macro sets the database key, flush it to the database.
+ */
+static void
+pmdoc_node(MDOC_ARGS)
+{
+
+	if (NULL == n)
+		return;
+
+	switch (n->type) {
+	case (MDOC_HEAD):
+		/* FALLTHROUGH */
+	case (MDOC_BODY):
+		/* FALLTHROUGH */
+	case (MDOC_TAIL):
+		/* FALLTHROUGH */
+	case (MDOC_BLOCK):
+		/* FALLTHROUGH */
+	case (MDOC_ELEM):
+		if (NULL == mdocs[n->tok])
+			break;
+
+		dbt_init(key, ksz);
+
+		(*mdocs[n->tok])(db, dbn, key, ksz, val, rval, rsz, n);
+		dbt_put(db, dbn, key, val);
+		break;
+	default:
+		break;
+	}
+
+	pmdoc_node(db, dbn, key, ksz, val, rval, rsz, n->child);
+	pmdoc_node(db, dbn, key, ksz, val, rval, rsz, n->next);
+}
+
+static int
+pman_node(MAN_ARGS)
+{
+	const struct man_node *head, *body;
+	const char	*start, *sv;
+	size_t		 sz;
+	uint32_t	 fl;
+
+	if (NULL == n)
+		return(0);
+
+	/*
+	 * We're only searching for one thing: the first text child in
+	 * the BODY of a NAME section.  Since we don't keep track of
+	 * sections in -man, run some hoops to find out whether we're in
+	 * the correct section or not.
+	 */
+
+	if (MAN_BODY == n->type && MAN_SH == n->tok) {
+		body = n;
+		assert(body->parent);
+		if (NULL != (head = body->parent->head) &&
+				1 == head->nchild &&
+				NULL != (head = (head->child)) &&
+				MAN_TEXT == head->type &&
+				0 == strcmp(head->string, "NAME") &&
+				NULL != (body = body->child) &&
+				MAN_TEXT == body->type) {
+
+			fl = (uint32_t)MANDOC_NAME;
+			memcpy(val->data, &fl, 4);
+
+			assert(body->string);
+			start = sv = body->string;
+
+			/* 
+			 * Go through a special heuristic dance here.
+			 * This is why -man manuals are great!
+			 * (I'm being sarcastic: my eyes are bleeding.)
+			 * Conventionally, one or more manual names are
+			 * comma-specified prior to a whitespace, then a
+			 * dash, then a description.  Try to puzzle out
+			 * the name parts here.
+			 */
+
+			for ( ;; ) {
+				sz = strcspn(start, " ,");
+				if ('\0' == start[(int)sz])
+					break;
+
+				dbt_init(key, ksz);
+				dbt_appendb(key, ksz, start, sz);
+				dbt_appendb(key, ksz, "", 1);
+
+				dbt_put(db, dbn, key, val);
+
+				if (' ' == start[(int)sz]) {
+					start += (int)sz + 1;
+					break;
+				}
+
+				assert(',' == start[(int)sz]);
+				start += (int)sz + 1;
+				while (' ' == *start)
+					start++;
+			}
+
+			if (sv == start) {
+				dbt_init(key, ksz);
+				dbt_append(key, ksz, start);
+				return(1);
+			}
+
+			while (' ' == *start)
+				start++;
+
+			if (0 == strncmp(start, "-", 1))
+				start += 1;
+			else if (0 == strncmp(start, "\\-", 2))
+				start += 2;
+			else if (0 == strncmp(start, "\\(en", 4))
+				start += 4;
+			else if (0 == strncmp(start, "\\(em", 4))
+				start += 4;
+
+			while (' ' == *start)
+				start++;
+
+			dbt_appendb(rval, rsz, start, strlen(start) + 1);
+		}
+	}
+
+	if (pman_node(db, dbn, key, ksz, val, rval, rsz, n->child))
+		return(1);
+	if (pman_node(db, dbn, key, ksz, val, rval, rsz, n->next))
+		return(1);
+
+	return(0);
+}
+
+static void
+pman(DB *db, const char *dbn, DBT *key, size_t *ksz, 
+		DBT *val, DBT *rval, size_t *rsz, struct man *m)
+{
+
+	pman_node(db, dbn, key, ksz, val, rval, rsz, man_node(m));
+}
+
+
+static void
+pmdoc(DB *db, const char *dbn, DBT *key, size_t *ksz, 
+		DBT *val, DBT *rval, size_t *rsz, struct mdoc *m)
+{
+
+	pmdoc_node(db, dbn, key, ksz, val, rval, rsz, mdoc_node(m));
+}
+
+static void
+usage(void)
+{
+
+	fprintf(stderr, "usage: %s "
+			"[-d path] "
+			"[file...]\n", 
+			progname);
+}
--- mandoc-db.1
+++ /dev/null
@@ -1,152 +0,0 @@
-.\"	$Id: mandoc-db.1,v 1.5 2011/05/04 20:43:38 kristaps Exp $
-.\"
-.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\"
-.\" Permission to use, copy, modify, and distribute this software for any
-.\" purpose with or without fee is hereby granted, provided that the above
-.\" copyright notice and this permission notice appear in all copies.
-.\"
-.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.\"
-.Dd $Mdocdate: May 4 2011 $
-.Dt MANDOC-DB 1
-.Os
-.Sh NAME
-.Nm mandoc-db
-.Nd index UNIX manuals
-.Sh SYNOPSIS
-.Nm
-.Op Fl d Ar dir
-.Ar
-.Sh DESCRIPTION
-The
-.Nm
-utility extracts keywords from
-.Ux
-manuals and indexes them for fast retrieval.
-The arguments are as follows:
-.Bl -tag -width Ds
-.It Fl d Ar dir
-The directory into which to write the keyword and index databases.
-.It Ar
-Read input from zero or more files in
-.Xr mdoc 7
-or
-.Xr man 7
-.Ux
-manual format.
-.El
-.Pp
-By default,
-.Nm
-constructs the
-.Sx Index Database
-and
-.Sx Keyword Database
-in the current working directory.
-.Pp
-If fatal parse errors are encountered, the offending file is printed to
-stderr, omitted from the index, and the parse continues with the next
-input file.
-.Ss Index Database
-The index database,
-.Pa mandoc.index ,
-is a
-.Xr recno 3
-database with record values consisting of
-.Pp
-.Bl -enum -compact
-.It
-a nil-terminated filename,
-.It
-a nil-terminated manual section,
-.It
-a nil-terminated manual title,
-.It
-a nil-terminated architecture
-.Pq this is not often available
-.It
-and a nil-terminated description.
-.El
-.Pp
-Both the manual section and description may be zero-length.
-Entries are sequentially-numbered, but the filenames are unordered.
-.Ss Keyword Database
-The keyword database,
-.Pa mandoc.db ,
-is a
-.Xr btree 3
-database of nil-terminated keywords (record length is non-zero string
-length plus one) mapping to a 8-byte binary field consisting of the
-keyword type and source
-.Sx Index Database
-record number.
-The type, an unsigned 32-bit integer in host order, is one of the
-following:
-.Pp
-.Bl -tag -width Ds -offset indent -compact
-.It Li 0x01
-The name of a manual page as given in the NAME section.
-.It Li 0x02
-A function prototype name as given in the SYNOPSIS section.
-.It Li 0x03
-A utility name as given in the SYNOPSIS section.
-.It Li 0x04
-An include file as given in the SYNOPSIS section.
-.It Li 0x05
-A variable name as given in the SYNOPSIS section.
-.It Li 0x06
-A standard as given in the STANDARDS section.
-.It Li 0x07
-An author as given in the AUTHORS section.
-.It Li 0x08
-A configuration as given in the SYNOPSIS section.
-.El
-.Pp
-If a value is encountered outside of this range, the database is
-corrupt.
-.Pp
-The latter four bytes are a host-ordered record number within the
-.Sx Index Database .
-.Pp
-The
-.Nm
-utility is
-.Ud
-.Sh FILES
-.Bl -tag -width Ds
-.It Pa mandoc.db
-A
-.Xr btree 3
-keyword database mapping keywords to a type and file reference in
-.Pa mandoc.index .
-.It Pa mandoc.db~
-Working copy of
-.Pa mandoc.db .
-.It Pa mandoc.index
-A
-.Xr recno 3
-database of indexed file-names.
-.It Pa mandoc.index~
-Working copy of
-.Pa mandoc.index .
-.El
-.Sh EXIT STATUS
-.Ex -std
-.Sh SEE ALSO
-.Xr mandoc 1
-.Sh AUTHORS
-The
-.Nm
-utility was written by
-.An Kristaps Dzonsons Aq kristaps@bsd.lv .
-.Sh CAVEATS
-Only
-.Xr mdoc 7
-manuals are processed.
--- mandoc-db.c
+++ /dev/null
@@ -1,962 +0,0 @@
-/*	$Id: mandoc-db.c,v 1.21 2011/05/12 23:44:51 kristaps Exp $ */
-/*
- * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <sys/param.h>
-
-#include <assert.h>
-#ifdef __linux__
-# include <db_185.h>
-#else
-# include <db.h>
-#endif
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "man.h"
-#include "mdoc.h"
-#include "mandoc.h"
-
-#define	MANDOC_DB	 "mandoc.db"
-#define	MANDOC_IDX	 "mandoc.index"
-#define	MANDOC_BUFSZ	  BUFSIZ
-#define	MANDOC_FLAGS	  O_CREAT|O_TRUNC|O_RDWR
-
-enum	type {
-	MANDOC_NONE = 0,
-	MANDOC_NAME,
-	MANDOC_FUNCTION,
-	MANDOC_UTILITY,
-	MANDOC_INCLUDES,
-	MANDOC_VARIABLE,
-	MANDOC_STANDARD,
-	MANDOC_AUTHOR,
-	MANDOC_CONFIG
-};
-
-#define	MAN_ARGS	  DB *db, \
-			  const char *dbn, \
-			  DBT *key, size_t *ksz, \
-			  DBT *val, \
-			  DBT *rval, size_t *rsz, \
-			  const struct man_node *n
-#define	MDOC_ARGS	  DB *db, \
-			  const char *dbn, \
-			  DBT *key, size_t *ksz, \
-			  DBT *val, \
-			  DBT *rval, size_t *rsz, \
-			  const struct mdoc_node *n
-
-static	void		  dbt_append(DBT *, size_t *, const char *);
-static	void		  dbt_appendb(DBT *, size_t *, 
-				const void *, size_t);
-static	void		  dbt_init(DBT *, size_t *);
-static	void		  dbt_put(DB *, const char *, DBT *, DBT *);
-static	void		  usage(void);
-static	void		  pman(DB *, const char *, DBT *, size_t *, 
-				DBT *, DBT *, size_t *, struct man *);
-static	int		  pman_node(MAN_ARGS);
-static	void		  pmdoc(DB *, const char *, DBT *, size_t *, 
-				DBT *, DBT *, size_t *, struct mdoc *);
-static	void		  pmdoc_node(MDOC_ARGS);
-static	void		  pmdoc_An(MDOC_ARGS);
-static	void		  pmdoc_Cd(MDOC_ARGS);
-static	void		  pmdoc_Fd(MDOC_ARGS);
-static	void		  pmdoc_In(MDOC_ARGS);
-static	void		  pmdoc_Fn(MDOC_ARGS);
-static	void		  pmdoc_Fo(MDOC_ARGS);
-static	void		  pmdoc_Nd(MDOC_ARGS);
-static	void		  pmdoc_Nm(MDOC_ARGS);
-static	void		  pmdoc_St(MDOC_ARGS);
-static	void		  pmdoc_Vt(MDOC_ARGS);
-
-typedef	void		(*pmdoc_nf)(MDOC_ARGS);
-
-static	const char	 *progname;
-
-static	const pmdoc_nf	  mdocs[MDOC_MAX] = {
-	NULL, /* Ap */
-	NULL, /* Dd */
-	NULL, /* Dt */
-	NULL, /* Os */
-	NULL, /* Sh */ 
-	NULL, /* Ss */ 
-	NULL, /* Pp */ 
-	NULL, /* D1 */
-	NULL, /* Dl */
-	NULL, /* Bd */
-	NULL, /* Ed */
-	NULL, /* Bl */ 
-	NULL, /* El */
-	NULL, /* It */
-	NULL, /* Ad */ 
-	pmdoc_An, /* An */ 
-	NULL, /* Ar */
-	pmdoc_Cd, /* Cd */ 
-	NULL, /* Cm */
-	NULL, /* Dv */ 
-	NULL, /* Er */ 
-	NULL, /* Ev */ 
-	NULL, /* Ex */ 
-	NULL, /* Fa */ 
-	pmdoc_Fd, /* Fd */
-	NULL, /* Fl */
-	pmdoc_Fn, /* Fn */ 
-	NULL, /* Ft */ 
-	NULL, /* Ic */ 
-	pmdoc_In, /* In */ 
-	NULL, /* Li */
-	pmdoc_Nd, /* Nd */
-	pmdoc_Nm, /* Nm */
-	NULL, /* Op */
-	NULL, /* Ot */
-	NULL, /* Pa */
-	NULL, /* Rv */
-	pmdoc_St, /* St */ 
-	pmdoc_Vt, /* Va */
-	pmdoc_Vt, /* Vt */ 
-	NULL, /* Xr */ 
-	NULL, /* %A */
-	NULL, /* %B */
-	NULL, /* %D */
-	NULL, /* %I */
-	NULL, /* %J */
-	NULL, /* %N */
-	NULL, /* %O */
-	NULL, /* %P */
-	NULL, /* %R */
-	NULL, /* %T */
-	NULL, /* %V */
-	NULL, /* Ac */
-	NULL, /* Ao */
-	NULL, /* Aq */
-	NULL, /* At */ 
-	NULL, /* Bc */
-	NULL, /* Bf */
-	NULL, /* Bo */
-	NULL, /* Bq */
-	NULL, /* Bsx */
-	NULL, /* Bx */
-	NULL, /* Db */
-	NULL, /* Dc */
-	NULL, /* Do */
-	NULL, /* Dq */
-	NULL, /* Ec */
-	NULL, /* Ef */ 
-	NULL, /* Em */ 
-	NULL, /* Eo */
-	NULL, /* Fx */
-	NULL, /* Ms */ 
-	NULL, /* No */
-	NULL, /* Ns */
-	NULL, /* Nx */
-	NULL, /* Ox */
-	NULL, /* Pc */
-	NULL, /* Pf */
-	NULL, /* Po */
-	NULL, /* Pq */
-	NULL, /* Qc */
-	NULL, /* Ql */
-	NULL, /* Qo */
-	NULL, /* Qq */
-	NULL, /* Re */
-	NULL, /* Rs */
-	NULL, /* Sc */
-	NULL, /* So */
-	NULL, /* Sq */
-	NULL, /* Sm */ 
-	NULL, /* Sx */
-	NULL, /* Sy */
-	NULL, /* Tn */
-	NULL, /* Ux */
-	NULL, /* Xc */
-	NULL, /* Xo */
-	pmdoc_Fo, /* Fo */ 
-	NULL, /* Fc */ 
-	NULL, /* Oo */
-	NULL, /* Oc */
-	NULL, /* Bk */
-	NULL, /* Ek */
-	NULL, /* Bt */
-	NULL, /* Hf */
-	NULL, /* Fr */
-	NULL, /* Ud */
-	NULL, /* Lb */
-	NULL, /* Lp */ 
-	NULL, /* Lk */ 
-	NULL, /* Mt */ 
-	NULL, /* Brq */ 
-	NULL, /* Bro */ 
-	NULL, /* Brc */ 
-	NULL, /* %C */
-	NULL, /* Es */
-	NULL, /* En */
-	NULL, /* Dx */
-	NULL, /* %Q */
-	NULL, /* br */
-	NULL, /* sp */
-	NULL, /* %U */
-	NULL, /* Ta */
-};
-
-int
-main(int argc, char *argv[])
-{
-	struct mparse	*mp; /* parse sequence */
-	struct mdoc	*mdoc; /* resulting mdoc */
-	struct man	*man; /* resulting man */
-	char		*fn; /* current file being parsed */
-	const char	*msec, /* manual section */
-	      	 	*mtitle, /* manual title */
-			*arch, /* manual architecture */
-	      		*dir; /* result dir (default: cwd) */
-	char		 ibuf[MAXPATHLEN], /* index fname */
-			 ibbuf[MAXPATHLEN], /* index backup fname */
-			 fbuf[MAXPATHLEN],  /* btree fname */
-			 fbbuf[MAXPATHLEN]; /* btree backup fname */
-	int		 ch;
-	DB		*idx, /* index database */
-			*db; /* keyword database */
-	DBT		 rkey, rval, /* recno entries */
-			 key, val; /* persistent keyword entries */
-	size_t		 sv,
-			 ksz, rsz; /* entry buffer size */
-	char		 vbuf[8]; /* stringified record number */
-	BTREEINFO	 info; /* btree configuration */
-	recno_t		 rec; /* current record number */
-	extern int	 optind;
-	extern char	*optarg;
-
-	progname = strrchr(argv[0], '/');
-	if (progname == NULL)
-		progname = argv[0];
-	else
-		++progname;
-
-	dir = "";
-
-	while (-1 != (ch = getopt(argc, argv, "d:")))
-		switch (ch) {
-		case ('d'):
-			dir = optarg;
-			break;
-		default:
-			usage();
-			return((int)MANDOCLEVEL_BADARG);
-		}
-
-	argc -= optind;
-	argv += optind;
-
-	/*
-	 * Set up temporary file-names into which we're going to write
-	 * all of our data (both for the index and database).  These
-	 * will be securely renamed to the real file-names after we've
-	 * written all of our data.
-	 */
-
-	ibuf[0] = ibuf[MAXPATHLEN - 2] =
-		ibbuf[0] = ibbuf[MAXPATHLEN - 2] = 
-		fbuf[0] = fbuf[MAXPATHLEN - 2] = 
-		fbbuf[0] = fbbuf[MAXPATHLEN - 2] = '\0';
-
-	strlcat(fbuf, dir, MAXPATHLEN);
-	strlcat(fbuf, MANDOC_DB, MAXPATHLEN);
-
-	strlcat(fbbuf, fbuf, MAXPATHLEN);
-	strlcat(fbbuf, "~", MAXPATHLEN);
-
-	strlcat(ibuf, dir, MAXPATHLEN);
-	strlcat(ibuf, MANDOC_IDX, MAXPATHLEN);
-
-	strlcat(ibbuf, ibuf, MAXPATHLEN);
-	strlcat(ibbuf, "~", MAXPATHLEN);
-
-	if ('\0' != fbuf[MAXPATHLEN - 2] ||
-			'\0' != fbbuf[MAXPATHLEN - 2] ||
-			'\0' != ibuf[MAXPATHLEN - 2] ||
-			'\0' != ibbuf[MAXPATHLEN - 2]) {
-		fprintf(stderr, "%s: Path too long\n", progname);
-		exit((int)MANDOCLEVEL_SYSERR);
-	}
-
-	/*
-	 * For the keyword database, open a BTREE database that allows
-	 * duplicates.  For the index database, use a standard RECNO
-	 * database type.
-	 */
-
-	memset(&info, 0, sizeof(BTREEINFO));
-	info.flags = R_DUP;
-	db = dbopen(fbbuf, MANDOC_FLAGS, 0644, DB_BTREE, &info);
-
-	if (NULL == db) {
-		perror(fbbuf);
-		exit((int)MANDOCLEVEL_SYSERR);
-	}
-
-	idx = dbopen(ibbuf, MANDOC_FLAGS, 0644, DB_RECNO, NULL);
-
-	if (NULL == db) {
-		perror(ibbuf);
-		(*db->close)(db);
-		exit((int)MANDOCLEVEL_SYSERR);
-	}
-
-	/*
-	 * Try parsing the manuals given on the command line.  If we
-	 * totally fail, then just keep on going.  Take resulting trees
-	 * and push them down into the database code.
-	 * Use the auto-parser and don't report any errors.
-	 */
-
-	mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL);
-
-	memset(&key, 0, sizeof(DBT));
-	memset(&val, 0, sizeof(DBT));
-	memset(&rkey, 0, sizeof(DBT));
-	memset(&rval, 0, sizeof(DBT));
-
-	val.size = sizeof(vbuf);
-	val.data = vbuf;
-	rkey.size = sizeof(recno_t);
-
-	rec = 1;
-	ksz = rsz = 0;
-
-	while (NULL != (fn = *argv++)) {
-		mparse_reset(mp);
-
-		/* Parse and get (non-empty) AST. */
-
-		if (mparse_readfd(mp, -1, fn) >= MANDOCLEVEL_FATAL) {
-			fprintf(stderr, "%s: Parse failure\n", fn);
-			continue;
-		}
-		mparse_result(mp, &mdoc, &man);
-		if (NULL == mdoc && NULL == man)
-			continue;
-
-		/* Manual section: can be empty string. */
-
-		msec = NULL != mdoc ? 
-			mdoc_meta(mdoc)->msec :
-			man_meta(man)->msec;
-		mtitle = NULL != mdoc ? 
-			mdoc_meta(mdoc)->title :
-			man_meta(man)->title;
-		arch = NULL != mdoc ? mdoc_meta(mdoc)->arch : NULL;
-
-		assert(msec);
-		assert(mtitle);
-
-		/* 
-		 * The index record value consists of a nil-terminated
-		 * filename, a nil-terminated manual section, and a
-		 * nil-terminated description.  Since the description
-		 * may not be set, we set a sentinel to see if we're
-		 * going to write a nil byte in its place.
-		 */
-
-		dbt_init(&rval, &rsz);
-		dbt_appendb(&rval, &rsz, fn, strlen(fn) + 1);
-		dbt_appendb(&rval, &rsz, msec, strlen(msec) + 1);
-		dbt_appendb(&rval, &rsz, mtitle, strlen(mtitle) + 1);
-		dbt_appendb(&rval, &rsz, arch ? arch : "", 
-				arch ? strlen(arch) + 1 : 1);
-
-		sv = rval.size;
-
-		/* Fix the record number in the btree value. */
-
-		memset(val.data, 0, sizeof(uint32_t));
-		memcpy(val.data + 4, &rec, sizeof(uint32_t));
-
-		if (mdoc)
-			pmdoc(db, fbbuf, &key, &ksz, 
-				&val, &rval, &rsz, mdoc);
-		else 
-			pman(db, fbbuf, &key, &ksz, 
-				&val, &rval, &rsz, man);
-		
-		/*
-		 * Apply this to the index.  If we haven't had a
-		 * description set, put an empty one in now.
-		 */
-
-		if (rval.size == sv)
-			dbt_appendb(&rval, &rsz, "", 1);
-
-		rkey.data = &rec;
-		dbt_put(idx, ibbuf, &rkey, &rval);
-
-		printf("Indexed: %s\n", fn);
-		rec++;
-	}
-
-	(*db->close)(db);
-	(*idx->close)(idx);
-
-	mparse_free(mp);
-
-	free(key.data);
-	free(rval.data);
-
-	/* Atomically replace the file with our temporary one. */
-
-	if (-1 == rename(fbbuf, fbuf))
-		perror(fbuf);
-	if (-1 == rename(ibbuf, ibuf))
-		perror(fbuf);
-
-	return((int)MANDOCLEVEL_OK);
-}
-
-/*
- * Initialise the stored database key whose data buffer is shared
- * between uses (as the key must sometimes be constructed from an array
- * of 
- */
-static void
-dbt_init(DBT *key, size_t *ksz)
-{
-
-	if (0 == *ksz) {
-		assert(0 == key->size);
-		assert(NULL == key->data);
-		key->data = mandoc_malloc(MANDOC_BUFSZ);
-		*ksz = MANDOC_BUFSZ;
-	}
-
-	key->size = 0;
-}
-
-/*
- * Append a binary value to a database entry.  This can be invoked
- * multiple times; the buffer is automatically resized.
- */
-static void
-dbt_appendb(DBT *key, size_t *ksz, const void *cp, size_t sz)
-{
-
-	assert(key->data);
-
-	/* Overshoot by MANDOC_BUFSZ. */
-
-	while (key->size + sz >= *ksz) {
-		*ksz = key->size + sz + MANDOC_BUFSZ;
-		key->data = mandoc_realloc(key->data, *ksz);
-	}
-
-#if 0
-	dstp = key->data + (int)key->size;
-
-	while (NULL != (endp = memchr(cp, '\\', sz))) {
-		ssz = endp - cp;
-		memcpy(dstp, cp, ssz);
-
-		dstp += ssz;
-		key->size += ssz;
-		sz -= ssz;
-
-		cp = endp++;
-		/* FIXME: expects nil-terminated string! */
-		esc = mandoc_escape((const char **)&endp, NULL, NULL);
-
-		switch (esc) {
-		case (ESCAPE_ERROR):
-			/* Nil-terminate this point. */
-			memcpy(dstp, "", 1);
-			key->size++;
-			return;
-		case (ESCAPE_PREDEF):
-			/* FALLTHROUGH */
-		case (ESCAPE_SPECIAL):
-			break;
-		default:
-			sz -= endp - cp;
-			cp = endp;
-			continue;
-		}
-
-		ssz = endp - cp;
-		memcpy(dstp, cp, ssz);
-
-		dstp += ssz;
-		key->size += ssz;
-		sz -= ssz;
-
-		cp = endp;
-	}
-#endif
-
-	memcpy(key->data + (int)key->size, cp, sz);
-	key->size += sz;
-}
-
-/*
- * Append a nil-terminated string to the database entry.  This can be
- * invoked multiple times.  The database entry will be nil-terminated as
- * well; if invoked multiple times, a space is put between strings.
- */
-static void
-dbt_append(DBT *key, size_t *ksz, const char *cp)
-{
-	size_t		 sz;
-
-	if (0 == (sz = strlen(cp)))
-		return;
-
-	assert(key->data);
-
-	if (key->size)
-		((char *)key->data)[(int)key->size - 1] = ' ';
-
-	dbt_appendb(key, ksz, cp, sz + 1);
-}
-
-/* ARGSUSED */
-static void
-pmdoc_An(MDOC_ARGS)
-{
-	uint32_t	 fl;
-	
-	if (SEC_AUTHORS != n->sec)
-		return;
-
-	for (n = n->child; n; n = n->next)
-		if (MDOC_TEXT == n->type)
-			dbt_append(key, ksz, n->string);
-
-	fl = MANDOC_AUTHOR;
-	memcpy(val->data, &fl, 4);
-}
-
-/* ARGSUSED */
-static void
-pmdoc_Fd(MDOC_ARGS)
-{
-	uint32_t	 fl;
-	const char	*start, *end;
-	size_t		 sz;
-	
-	if (SEC_SYNOPSIS != n->sec)
-		return;
-	if (NULL == (n = n->child) || MDOC_TEXT != n->type)
-		return;
-
-	/*
-	 * Only consider those `Fd' macro fields that begin with an
-	 * "inclusion" token (versus, e.g., #define).
-	 */
-	if (strcmp("#include", n->string))
-		return;
-
-	if (NULL == (n = n->next) || MDOC_TEXT != n->type)
-		return;
-
-	/*
-	 * Strip away the enclosing angle brackets and make sure we're
-	 * not zero-length.
-	 */
-
-	start = n->string;
-	if ('<' == *start || '"' == *start)
-		start++;
-
-	if (0 == (sz = strlen(start)))
-		return;
-
-	end = &start[(int)sz - 1];
-	if ('>' == *end || '"' == *end)
-		end--;
-
-	assert(end >= start);
-	dbt_appendb(key, ksz, start, (size_t)(end - start + 1));
-	dbt_appendb(key, ksz, "", 1);
-
-	fl = MANDOC_INCLUDES;
-	memcpy(val->data, &fl, 4);
-}
-
-/* ARGSUSED */
-static void
-pmdoc_Cd(MDOC_ARGS)
-{
-	uint32_t	 fl;
-	
-	if (SEC_SYNOPSIS != n->sec)
-		return;
-
-	for (n = n->child; n; n = n->next)
-		if (MDOC_TEXT == n->type)
-			dbt_append(key, ksz, n->string);
-
-	fl = MANDOC_CONFIG;
-	memcpy(val->data, &fl, 4);
-}
-
-/* ARGSUSED */
-static void
-pmdoc_In(MDOC_ARGS)
-{
-	uint32_t	 fl;
-	
-	if (SEC_SYNOPSIS != n->sec)
-		return;
-	if (NULL == n->child || MDOC_TEXT != n->child->type)
-		return;
-
-	dbt_append(key, ksz, n->child->string);
-	fl = MANDOC_INCLUDES;
-	memcpy(val->data, &fl, 4);
-}
-
-/* ARGSUSED */
-static void
-pmdoc_Fn(MDOC_ARGS)
-{
-	uint32_t	 fl;
-	const char	*cp;
-	
-	if (SEC_SYNOPSIS != n->sec)
-		return;
-	if (NULL == n->child || MDOC_TEXT != n->child->type)
-		return;
-
-	/* .Fn "struct type *arg" "foo" */
-
-	cp = strrchr(n->child->string, ' ');
-	if (NULL == cp)
-		cp = n->child->string;
-
-	/* Strip away pointer symbol. */
-
-	while ('*' == *cp)
-		cp++;
-
-	dbt_append(key, ksz, cp);
-	fl = MANDOC_FUNCTION;
-	memcpy(val->data, &fl, 4);
-}
-
-/* ARGSUSED */
-static void
-pmdoc_St(MDOC_ARGS)
-{
-	uint32_t	 fl;
-	
-	if (SEC_STANDARDS != n->sec)
-		return;
-	if (NULL == n->child || MDOC_TEXT != n->child->type)
-		return;
-
-	dbt_append(key, ksz, n->child->string);
-	fl = MANDOC_STANDARD;
-	memcpy(val->data, &fl, 4);
-}
-
-/* ARGSUSED */
-static void
-pmdoc_Vt(MDOC_ARGS)
-{
-	uint32_t	 fl;
-	const char	*start;
-	size_t		 sz;
-	
-	if (SEC_SYNOPSIS != n->sec)
-		return;
-	if (MDOC_Vt == n->tok && MDOC_BODY != n->type)
-		return;
-	if (NULL == n->last || MDOC_TEXT != n->last->type)
-		return;
-
-	/*
-	 * Strip away leading pointer symbol '*' and trailing ';'.
-	 */
-
-	start = n->last->string;
-
-	while ('*' == *start)
-		start++;
-
-	if (0 == (sz = strlen(start)))
-		return;
-
-	if (';' == start[(int)sz - 1])
-		sz--;
-
-	if (0 == sz)
-		return;
-
-	dbt_appendb(key, ksz, start, sz);
-	dbt_appendb(key, ksz, "", 1);
-
-	fl = MANDOC_VARIABLE;
-	memcpy(val->data, &fl, 4);
-}
-
-/* ARGSUSED */
-static void
-pmdoc_Fo(MDOC_ARGS)
-{
-	uint32_t	 fl;
-	
-	if (SEC_SYNOPSIS != n->sec || MDOC_HEAD != n->type)
-		return;
-	if (NULL == n->child || MDOC_TEXT != n->child->type)
-		return;
-
-	dbt_append(key, ksz, n->child->string);
-	fl = MANDOC_FUNCTION;
-	memcpy(val->data, &fl, 4);
-}
-
-
-/* ARGSUSED */
-static void
-pmdoc_Nd(MDOC_ARGS)
-{
-	int		 first;
-	
-	for (first = 1, n = n->child; n; n = n->next) {
-		if (MDOC_TEXT != n->type)
-			continue;
-		if (first) 
-			dbt_appendb(rval, rsz, n->string, strlen(n->string) + 1);
-		else
-			dbt_append(rval, rsz, n->string);
-		first = 0;
-	}
-}
-
-/* ARGSUSED */
-static void
-pmdoc_Nm(MDOC_ARGS)
-{
-	uint32_t	 fl;
-	
-	if (SEC_NAME == n->sec) {
-		for (n = n->child; n; n = n->next) {
-			if (MDOC_TEXT != n->type)
-				continue;
-			dbt_append(key, ksz, n->string);
-		}
-		fl = MANDOC_NAME;
-		memcpy(val->data, &fl, 4);
-		return;
-	} else if (SEC_SYNOPSIS != n->sec || MDOC_HEAD != n->type)
-		return;
-
-	for (n = n->child; n; n = n->next) {
-		if (MDOC_TEXT != n->type)
-			continue;
-		dbt_append(key, ksz, n->string);
-	}
-
-	fl = MANDOC_UTILITY;
-	memcpy(val->data, &fl, 4);
-}
-
-static void
-dbt_put(DB *db, const char *dbn, DBT *key, DBT *val)
-{
-
-	if (0 == key->size)
-		return;
-
-	assert(key->data);
-	assert(val->size);
-	assert(val->data);
-
-	if (0 == (*db->put)(db, key, val, 0))
-		return;
-	
-	perror(dbn);
-	exit((int)MANDOCLEVEL_SYSERR);
-	/* NOTREACHED */
-}
-
-/*
- * Call out to per-macro handlers after clearing the persistent database
- * key.  If the macro sets the database key, flush it to the database.
- */
-static void
-pmdoc_node(MDOC_ARGS)
-{
-
-	if (NULL == n)
-		return;
-
-	switch (n->type) {
-	case (MDOC_HEAD):
-		/* FALLTHROUGH */
-	case (MDOC_BODY):
-		/* FALLTHROUGH */
-	case (MDOC_TAIL):
-		/* FALLTHROUGH */
-	case (MDOC_BLOCK):
-		/* FALLTHROUGH */
-	case (MDOC_ELEM):
-		if (NULL == mdocs[n->tok])
-			break;
-
-		dbt_init(key, ksz);
-
-		(*mdocs[n->tok])(db, dbn, key, ksz, val, rval, rsz, n);
-		dbt_put(db, dbn, key, val);
-		break;
-	default:
-		break;
-	}
-
-	pmdoc_node(db, dbn, key, ksz, val, rval, rsz, n->child);
-	pmdoc_node(db, dbn, key, ksz, val, rval, rsz, n->next);
-}
-
-static int
-pman_node(MAN_ARGS)
-{
-	const struct man_node *head, *body;
-	const char	*start, *sv;
-	size_t		 sz;
-	uint32_t	 fl;
-
-	if (NULL == n)
-		return(0);
-
-	/*
-	 * We're only searching for one thing: the first text child in
-	 * the BODY of a NAME section.  Since we don't keep track of
-	 * sections in -man, run some hoops to find out whether we're in
-	 * the correct section or not.
-	 */
-
-	if (MAN_BODY == n->type && MAN_SH == n->tok) {
-		body = n;
-		assert(body->parent);
-		if (NULL != (head = body->parent->head) &&
-				1 == head->nchild &&
-				NULL != (head = (head->child)) &&
-				MAN_TEXT == head->type &&
-				0 == strcmp(head->string, "NAME") &&
-				NULL != (body = body->child) &&
-				MAN_TEXT == body->type) {
-
-			fl = MANDOC_NAME;
-			memcpy(val->data, &fl, 4);
-
-			assert(body->string);
-			start = sv = body->string;
-
-			/* 
-			 * Go through a special heuristic dance here.
-			 * This is why -man manuals are great!
-			 * (I'm being sarcastic: my eyes are bleeding.)
-			 * Conventionally, one or more manual names are
-			 * comma-specified prior to a whitespace, then a
-			 * dash, then a description.  Try to puzzle out
-			 * the name parts here.
-			 */
-
-			for ( ;; ) {
-				sz = strcspn(start, " ,");
-				if ('\0' == start[(int)sz])
-					break;
-
-				dbt_init(key, ksz);
-				dbt_appendb(key, ksz, start, sz);
-				dbt_appendb(key, ksz, "", 1);
-
-				dbt_put(db, dbn, key, val);
-
-				if (' ' == start[(int)sz]) {
-					start += (int)sz + 1;
-					break;
-				}
-
-				assert(',' == start[(int)sz]);
-				start += (int)sz + 1;
-				while (' ' == *start)
-					start++;
-			}
-
-			if (sv == start) {
-				dbt_init(key, ksz);
-				dbt_append(key, ksz, start);
-				return(1);
-			}
-
-			while (' ' == *start)
-				start++;
-
-			if (0 == strncmp(start, "-", 1))
-				start += 1;
-			else if (0 == strncmp(start, "\\-", 2))
-				start += 2;
-			else if (0 == strncmp(start, "\\(en", 4))
-				start += 4;
-			else if (0 == strncmp(start, "\\(em", 4))
-				start += 4;
-
-			while (' ' == *start)
-				start++;
-
-			dbt_appendb(rval, rsz, start, strlen(start) + 1);
-		}
-	}
-
-	if (pman_node(db, dbn, key, ksz, val, rval, rsz, n->child))
-		return(1);
-	if (pman_node(db, dbn, key, ksz, val, rval, rsz, n->next))
-		return(1);
-
-	return(0);
-}
-
-static void
-pman(DB *db, const char *dbn, DBT *key, size_t *ksz, 
-		DBT *val, DBT *rval, size_t *rsz, struct man *m)
-{
-
-	pman_node(db, dbn, key, ksz, val, rval, rsz, man_node(m));
-}
-
-
-static void
-pmdoc(DB *db, const char *dbn, DBT *key, size_t *ksz, 
-		DBT *val, DBT *rval, size_t *rsz, struct mdoc *m)
-{
-
-	pmdoc_node(db, dbn, key, ksz, val, rval, rsz, mdoc_node(m));
-}
-
-static void
-usage(void)
-{
-
-	fprintf(stderr, "usage: %s "
-			"[-d path] "
-			"[file...]\n", 
-			progname);
-}
Index: index.sgml
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/index.sgml,v
retrieving revision 1.114
retrieving revision 1.115
diff -Lindex.sgml -Lindex.sgml -u -p -r1.114 -r1.115
--- index.sgml
+++ index.sgml
@@ -49,8 +49,8 @@
 			install</CODE> to install into <I>/usr/local</I>.
 		</P>
 		<P>
-			Note that <A HREF="mandoc-db.1.html">mandoc-db</A> is not yet linked to the build.  You must run <CODE>make
-			mandoc-db</CODE> to build it.
+			Note that <A HREF="makewhatis.1.html">makewhatis</A> is not yet linked to the build.  You must run <CODE>make
+			makewhatis</CODE> to build it.
 		</P>
 
 		<H2>
@@ -158,14 +158,14 @@
 					</TD>
 				</TR>
 				<TR>
-					<TD VALIGN="top"><A HREF="mandoc.1.html">mandoc-db(1)</A></TD>
+					<TD VALIGN="top"><A HREF="mandoc.1.html">makewhatis(1)</A></TD>
 					<TD VALIGN="top">
 						index UNIX manuals
 						<SMALL>
-							(<A HREF="mandoc-db.1.txt">text</A> | 
-							<A HREF="mandoc-db.1.xhtml">xhtml</A> |
-							<A HREF="mandoc-db.1.pdf">pdf</A> |
-							<A HREF="mandoc-db.1.ps">postscript</A>)
+							(<A HREF="makewhatis.1.txt">text</A> | 
+							<A HREF="makewhatis.1.xhtml">xhtml</A> |
+							<A HREF="makewhatis.1.pdf">pdf</A> |
+							<A HREF="makewhatis.1.ps">postscript</A>)
 						</SMALL>
 					</TD>
 				</TR>
@@ -308,6 +308,17 @@
 		<H1>
 			<A NAME="news">NEWS</A>
 		</H1>
+
+		<P CLASS="news">
+			12-05-2011: version 1.11.2
+		</P>
+		<P>
+			Corrected some installation issues in version 1.11.1.
+			Initial public release (this utility is very much under development) of <A HREF="makewhatis.1.html">makewhatis</A>,
+			initially named mandoc-db.
+			This utility produces keyword databases of manual content
+			<A HREF="http://mdocml.bsd.lv/mandoc-cgi/index.html">mandoc-cgi</A>, which features semantic querying of manual content.
+		</P>
 
 		<P CLASS="news">
 			04-04-2011: version 1.11.1
Index: Makefile
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/Makefile,v
retrieving revision 1.335
retrieving revision 1.336
diff -LMakefile -LMakefile -u -p -r1.335 -r1.336
--- Makefile
+++ Makefile
@@ -67,8 +67,8 @@ SRCS		 = Makefile \
 		   mandoc.3 \
 		   mandoc.c \
 		   mandoc.h \
-		   mandoc-db.1 \
-		   mandoc-db.c \
+		   makewhatis.1 \
+		   makewhatis.c \
 		   mandoc_char.7 \
 		   mdoc.h \
 		   mdoc.7 \
@@ -216,10 +216,10 @@ $(MANDOC_OBJS) $(MANDOC_LNS): main.h man
 
 compat.o compat.ln: config.h
 
-MANDOCDB_OBJS	 = mandoc-db.o
-MANDOCDB_LNS	 = mandoc-db.ln
+MAKEWHATIS_OBJS	 = makewhatis.o
+MAKEWHATIS_LNS	 = makewhatis.ln
 
-$(MANDOCDB_OBJS) $(MANDOCDB_LNS): mandoc.h mdoc.h man.h config.h
+$(MAKEWHATIS_OBJS) $(MAKEWHATIS_LNS): mandoc.h mdoc.h man.h config.h
 
 INDEX_MANS	 = mandoc.1.html \
 		   mandoc.1.xhtml \
@@ -278,8 +278,8 @@ lint: llib-llibmandoc.ln llib-lmandoc.ln
 clean:
 	rm -f libmandoc.a $(LIBMANDOC_OBJS)
 	rm -f llib-llibmandoc.ln $(LIBMANDOC_LNS)
-	rm -f mandoc-db $(MANDOCDB_OBJS)
-	rm -f llib-lmandoc-db.ln $(MANDOCDB_LNS)
+	rm -f makewhatis $(MAKEWHATIS_OBJS)
+	rm -f llib-lmakewhatis.ln $(MAKEWHATIS_LNS)
 	rm -f mandoc $(MANDOC_OBJS)
 	rm -f llib-lmandoc.ln $(MANDOC_LNS)
 	rm -f config.h config.log compat.o compat.ln
@@ -322,14 +322,14 @@ mandoc: $(MANDOC_OBJS) libmandoc.a
 	$(CC) -o $@ $(MANDOC_OBJS) libmandoc.a
 
 # You'll need -ldb for Linux.
-mandoc-db: $(MANDOCDB_OBJS) libmandoc.a
-	$(CC) -o $@ $(MANDOCDB_OBJS) libmandoc.a
+makewhatis: $(MAKEWHATIS_OBJS) libmandoc.a
+	$(CC) -o $@ $(MAKEWHATIS_OBJS) libmandoc.a
 
 llib-lmandoc.ln: $(MANDOC_LNS)
 	$(LINT) $(LINTFLAGS) -Cmandoc $(MANDOC_LNS)
 
-llib-lmandoc-db.ln: $(MANDOCDB_LNS)
-	$(LINT) $(LINTFLAGS) -Cmandoc-db $(MANDOCDB_LNS)
+llib-lmakewhatis.ln: $(MAKEWHATIS_LNS)
+	$(LINT) $(LINTFLAGS) -Cmakewhatis $(MAKEWHATIS_LNS)
 
 mdocml.md5: mdocml.tar.gz
 	md5 mdocml.tar.gz >$@
--- /dev/null
+++ makewhatis.1
@@ -0,0 +1,152 @@
+.\"	$Id: makewhatis.1,v 1.1 2011/05/13 00:42:26 kristaps Exp $
+.\"
+.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: May 13 2011 $
+.Dt MANDOC-DB 1
+.Os
+.Sh NAME
+.Nm makewhatis
+.Nd index UNIX manuals
+.Sh SYNOPSIS
+.Nm
+.Op Fl d Ar dir
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility extracts keywords from
+.Ux
+manuals and indexes them for fast retrieval.
+The arguments are as follows:
+.Bl -tag -width Ds
+.It Fl d Ar dir
+The directory into which to write the keyword and index databases.
+.It Ar
+Read input from zero or more files in
+.Xr mdoc 7
+or
+.Xr man 7
+.Ux
+manual format.
+.El
+.Pp
+By default,
+.Nm
+constructs the
+.Sx Index Database
+and
+.Sx Keyword Database
+in the current working directory.
+.Pp
+If fatal parse errors are encountered, the offending file is printed to
+stderr, omitted from the index, and the parse continues with the next
+input file.
+.Ss Index Database
+The index database,
+.Pa mandoc.index ,
+is a
+.Xr recno 3
+database with record values consisting of
+.Pp
+.Bl -enum -compact
+.It
+a nil-terminated filename,
+.It
+a nil-terminated manual section,
+.It
+a nil-terminated manual title,
+.It
+a nil-terminated architecture
+.Pq this is not often available
+.It
+and a nil-terminated description.
+.El
+.Pp
+Both the manual section and description may be zero-length.
+Entries are sequentially-numbered, but the filenames are unordered.
+.Ss Keyword Database
+The keyword database,
+.Pa mandoc.db ,
+is a
+.Xr btree 3
+database of nil-terminated keywords (record length is non-zero string
+length plus one) mapping to a 8-byte binary field consisting of the
+keyword type and source
+.Sx Index Database
+record number.
+The type, an unsigned 32-bit integer in host order, is one of the
+following:
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It Li 0x01
+The name of a manual page as given in the NAME section.
+.It Li 0x02
+A function prototype name as given in the SYNOPSIS section.
+.It Li 0x03
+A utility name as given in the SYNOPSIS section.
+.It Li 0x04
+An include file as given in the SYNOPSIS section.
+.It Li 0x05
+A variable name as given in the SYNOPSIS section.
+.It Li 0x06
+A standard as given in the STANDARDS section.
+.It Li 0x07
+An author as given in the AUTHORS section.
+.It Li 0x08
+A configuration as given in the SYNOPSIS section.
+.El
+.Pp
+If a value is encountered outside of this range, the database is
+corrupt.
+.Pp
+The latter four bytes are a host-ordered record number within the
+.Sx Index Database .
+.Pp
+The
+.Nm
+utility is
+.Ud
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa mandoc.db
+A
+.Xr btree 3
+keyword database mapping keywords to a type and file reference in
+.Pa mandoc.index .
+.It Pa mandoc.db~
+Working copy of
+.Pa mandoc.db .
+.It Pa mandoc.index
+A
+.Xr recno 3
+database of indexed file-names.
+.It Pa mandoc.index~
+Working copy of
+.Pa mandoc.index .
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr mandoc 1
+.Sh AUTHORS
+The
+.Nm
+utility was written by
+.An Kristaps Dzonsons Aq kristaps@bsd.lv .
+.Sh CAVEATS
+Only
+.Xr mdoc 7
+manuals are processed.
--
 To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-05-13  0:42 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-13  0:42 mdocml: Rename mandoc-db to makewhatis kristaps

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).