summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2011-07-11 21:56:06 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2011-07-11 21:56:06 +0000
commitb893dc28f5e041ed6abe50ad792ae5d85f32cd74 (patch)
tree9474d13e611e1ad853b3dc728932db6219879384
parentf37ec6d0eca54e78591941710bf176d838010944 (diff)
downloadmandoc-b893dc28f5e041ed6abe50ad792ae5d85f32cd74.tar.gz
Fairly straightforward patch adding basic update (-u) and remove (-r)
functionality to makewhatis. This is somewhat expensive (requiring the index file to be trawled multiple times), but it's a good start.
-rw-r--r--makewhatis.122
-rw-r--r--makewhatis.c168
2 files changed, 172 insertions, 18 deletions
diff --git a/makewhatis.1 b/makewhatis.1
index 68332858..116a6f51 100644
--- a/makewhatis.1
+++ b/makewhatis.1
@@ -22,7 +22,7 @@
.Nd index UNIX manuals
.Sh SYNOPSIS
.Nm
-.Op Fl v
+.Op Fl ruv
.Op Fl d Ar dir
.Ar
.Sh DESCRIPTION
@@ -42,6 +42,15 @@ or
.Xr man 7
.Ux
manual format.
+.It Fl r
+Remove entries.
+This will remove the index and keyword references.
+If the record is not found, it is ignored.
+.It Fl u
+Update the record.
+This will first remove the record (as in
+.Fl r )
+then re-add it.
.It Fl v
Verbose output.
If specified once, prints the name of each indexed file.
@@ -50,11 +59,12 @@ If twice, prints keywords for each file.
.Pp
By default,
.Nm
-constructs the
+constructs a new
.Sx Index Database
and
.Sx Keyword Database
in the current working directory.
+Existing databases are truncated.
.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
@@ -133,6 +143,14 @@ The
.Nm
utility is
.Ud
+.Sh IMPLEMENTATION NOTES
+The time to construct a new database pair grows linearly with the
+number of keywords in the input.
+However, removing or updating entries with
+.Fl r
+or
+.Fl u ,
+respectively, grows as a multiple of the index length and input size.
.Sh FILES
.Bl -tag -width Ds
.It Pa mandoc.db
diff --git a/makewhatis.c b/makewhatis.c
index 875483a9..a019737f 100644
--- a/makewhatis.c
+++ b/makewhatis.c
@@ -67,6 +67,14 @@ struct buf {
size_t size;
};
+/* Operation we're going to perform. */
+
+enum op {
+ OP_NEW = 0, /* new database */
+ OP_UPDATE, /* update entries in existing database */
+ OP_DELETE /* delete entries from existing database */
+};
+
#define MAN_ARGS DB *hash, \
struct buf *buf, \
struct buf *dbuf, \
@@ -85,6 +93,8 @@ static void buf_appendb(struct buf *,
static void dbt_put(DB *, const char *, DBT *, DBT *);
static void hash_put(DB *, const struct buf *, int);
static void hash_reset(DB **);
+static void op_delete(const char *, int, DB *,
+ const char *, DB *, const char *);
static int pman_node(MAN_ARGS);
static void pmdoc_node(MDOC_ARGS);
static void pmdoc_An(MDOC_ARGS);
@@ -238,6 +248,7 @@ main(int argc, char *argv[])
struct mparse *mp; /* parse sequence */
struct mdoc *mdoc; /* resulting mdoc */
struct man *man; /* resulting man */
+ enum op op;
char *fn; /* current file being parsed */
const char *msec, /* manual section */
*mtitle, /* manual title */
@@ -246,7 +257,7 @@ main(int argc, char *argv[])
char ibuf[MAXPATHLEN], /* index fname */
fbuf[MAXPATHLEN], /* btree fname */
vbuf[8]; /* stringified record number */
- int ch, seq, verb;
+ int ch, seq, verb, i;
DB *idx, /* index database */
*db, /* keyword database */
*hash; /* temporary keyword hashtable */
@@ -254,7 +265,10 @@ main(int argc, char *argv[])
enum mandocerr ec;
size_t sv;
BTREEINFO info; /* btree configuration */
- recno_t rec; /* current record number */
+ recno_t rec, /* current record number */
+ maxrec;
+ recno_t *recs;
+ size_t recsz;
struct buf buf, /* keyword buffer */
dbuf; /* description buffer */
extern int optind;
@@ -271,16 +285,25 @@ main(int argc, char *argv[])
db = idx = NULL;
mp = NULL;
hash = NULL;
+ recs = NULL;
+ recsz = 0;
+ op = OP_NEW;
ec = MANDOCLEVEL_SYSERR;
memset(&buf, 0, sizeof(struct buf));
memset(&dbuf, 0, sizeof(struct buf));
- while (-1 != (ch = getopt(argc, argv, "d:v")))
+ while (-1 != (ch = getopt(argc, argv, "d:ruv")))
switch (ch) {
case ('d'):
dir = optarg;
break;
+ case ('r'):
+ op = OP_DELETE;
+ break;
+ case ('u'):
+ op = OP_UPDATE;
+ break;
case ('v'):
verb++;
break;
@@ -311,13 +334,19 @@ main(int argc, char *argv[])
* For the keyword database, open a BTREE database that allows
* duplicates.
* For the index database, use a standard RECNO database type.
+ * Truncate the database if we're creating a new one.
*/
memset(&info, 0, sizeof(BTREEINFO));
info.flags = R_DUP;
- db = dbopen(fbuf, MANDOC_FLAGS, 0644, DB_BTREE, &info);
- idx = dbopen(ibuf, MANDOC_FLAGS, 0644, DB_RECNO, NULL);
+ if (OP_NEW == op) {
+ db = dbopen(fbuf, MANDOC_FLAGS, 0644, DB_BTREE, &info);
+ idx = dbopen(ibuf, MANDOC_FLAGS, 0644, DB_RECNO, NULL);
+ } else {
+ db = dbopen(fbuf, O_CREAT|O_RDWR, 0644, DB_BTREE, &info);
+ idx = dbopen(ibuf, O_CREAT|O_RDWR, 0644, DB_RECNO, NULL);
+ }
if (NULL == db) {
perror(fbuf);
@@ -328,6 +357,52 @@ main(int argc, char *argv[])
}
/*
+ * If we're going to delete or update a database, remove the
+ * entries now. This doesn't actually remove them; it only sets
+ * their record value lengths to zero.
+ */
+
+ if (OP_DELETE == op || OP_UPDATE == op)
+ for (i = 0; i < argc; i++)
+ op_delete(argv[i], verb, idx, ibuf, db, fbuf);
+
+ if (OP_DELETE == op) {
+ ec = MANDOCLEVEL_OK;
+ goto out;
+ }
+
+ /*
+ * Compile a list of all available "empty" records to use. This
+ * keeps the size of the database small.
+ */
+
+ if (OP_UPDATE == op) {
+ i = 0;
+ seq = R_FIRST;
+ while (0 == (ch = (*idx->seq)(idx, &key, &val, seq))) {
+ seq = R_NEXT;
+ maxrec = *(recno_t *)key.data;
+ if (val.size > 0)
+ continue;
+ if ((size_t)i >= recsz) {
+ recsz += 1024;
+ recs = mandoc_realloc
+ (recs, recsz * sizeof(recno_t));
+ }
+ recs[i++] = maxrec;
+ }
+ if (ch < 0) {
+ perror(ibuf);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ recsz = (size_t)i;
+ maxrec++;
+ assert(recsz < maxrec);
+ } else
+ maxrec = 0;
+
+ /*
+ * Add records to the database.
* Try parsing each manual given on the command line.
* If we fail, then emit an error and keep on going.
* Take resulting trees and push them down into the database code.
@@ -340,9 +415,20 @@ main(int argc, char *argv[])
buf.cp = mandoc_malloc(buf.size);
dbuf.cp = mandoc_malloc(dbuf.size);
- rec = 1;
+ for (rec = 0, i = 0; i < argc; i++) {
+ fn = argv[i];
+ if (OP_UPDATE == op) {
+ if (recsz > 0) {
+ --recsz;
+ rec = recs[(int)recsz];
+ } else if (maxrec > 0) {
+ rec = maxrec;
+ maxrec = 0;
+ } else
+ rec++;
+ } else
+ rec++;
- while (NULL != (fn = *argv++)) {
mparse_reset(mp);
hash_reset(&hash);
@@ -359,8 +445,10 @@ main(int argc, char *argv[])
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 : "";
+ arch = NULL != mdoc ? mdoc_meta(mdoc)->arch : NULL;
+
+ if (NULL == arch)
+ arch = "";
/*
* The index record value consists of a nil-terminated
@@ -403,12 +491,10 @@ main(int argc, char *argv[])
val.data = vbuf;
if (verb > 1)
- printf("%s: Keyword %s: 0x%x\n",
+ printf("Indexed: %s, %s, 0x%x\n",
fn, (char *)key.data,
*(int *)val.data);
-
dbt_put(db, fbuf, &key, &val);
-
}
if (ch < 0) {
perror("hash");
@@ -430,14 +516,12 @@ main(int argc, char *argv[])
val.size = dbuf.len;
if (verb > 0)
- printf("%s: Indexed\n", fn);
+ printf("Indexed: %s\n", fn);
dbt_put(idx, ibuf, &key, &val);
- rec++;
}
ec = MANDOCLEVEL_OK;
-
out:
if (db)
(*db->close)(db);
@@ -450,10 +534,62 @@ out:
free(buf.cp);
free(dbuf.cp);
+ free(recs);
return((int)ec);
}
+static void
+op_delete(const char *fn, int verb, DB *idx,
+ const char *ibuf, DB *db, const char *fbuf)
+{
+ int ch;
+ DBT key, val;
+ recno_t rec;
+ unsigned int seq, sseq;
+
+ seq = R_FIRST;
+ while (0 == (ch = (*idx->seq)(idx, &key, &val, seq))) {
+ seq = R_NEXT;
+ if (0 == val.size)
+ continue;
+ if (strcmp((char *)val.data, fn))
+ continue;
+
+ rec = *(recno_t *)key.data;
+
+ sseq = R_FIRST;
+ while (0 == (ch = (*db->seq)(db, &key, &val, sseq))) {
+ sseq = R_NEXT;
+ assert(8 == val.size);
+ if (rec != *(recno_t *)(val.data + 4))
+ continue;
+ if (verb > 1)
+ printf("Deleted: %s, %s\n",
+ fn, (char *)key.data);
+ ch = (*db->del)(db, &key, R_CURSOR);
+ if (ch < 0)
+ break;
+ }
+ if (ch < 0) {
+ perror(fbuf);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+
+ val.size = 0;
+ if (verb)
+ printf("Deleted: %s\n", fn);
+ ch = (*idx->put)
+ (idx, &key, &val, R_CURSOR);
+ if (ch < 0)
+ break;
+ }
+ if (ch < 0) {
+ perror(ibuf);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+}
+
/*
* Grow the buffer (if necessary) and copy in a binary string.
*/
@@ -980,6 +1116,6 @@ static void
usage(void)
{
- fprintf(stderr, "usage: %s [-v] [-d path] [file...]\n",
+ fprintf(stderr, "usage: %s [-ruv] [-d path] [file...]\n",
progname);
}