=================================================================== RCS file: /cvs/mandoc/Attic/makewhatis.c,v retrieving revision 1.18 retrieving revision 1.21 diff -u -p -r1.18 -r1.21 --- mandoc/Attic/makewhatis.c 2011/07/11 09:36:15 1.18 +++ mandoc/Attic/makewhatis.c 2011/07/12 15:26:35 1.21 @@ -1,4 +1,4 @@ -/* $Id: makewhatis.c,v 1.18 2011/07/11 09:36:15 kristaps Exp $ */ +/* $Id: makewhatis.c,v 1.21 2011/07/12 15:26:35 kristaps Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons * @@ -42,6 +42,7 @@ #define MANDOC_IDX "mandoc.index" #define MANDOC_BUFSZ BUFSIZ #define MANDOC_FLAGS O_CREAT|O_TRUNC|O_RDWR +#define MANDOC_SLOP 1024 /* Bit-fields. See makewhatis.1. */ @@ -67,6 +68,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, \ @@ -238,6 +247,7 @@ main(int argc, char *argv[]) struct mparse *mp; /* parse sequence */ struct mdoc *mdoc; /* resulting mdoc */ struct man *man; /* resulting man */ + enum op op; /* current operation */ char *fn; /* current file being parsed */ const char *msec, /* manual section */ *mtitle, /* manual title */ @@ -246,15 +256,19 @@ 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, sseq, verb, i; DB *idx, /* index database */ *db, /* keyword database */ *hash; /* temporary keyword hashtable */ DBT key, val; - enum mandocerr ec; + enum mandoclevel ec; /* exit status */ size_t sv; BTREEINFO info; /* btree configuration */ - recno_t rec; /* current record number */ + recno_t rec, + maxrec; /* supremum of all records */ + recno_t *recs; /* buffer of empty records */ + size_t recsz, /* buffer size of recs */ + reccur; /* valid number of recs */ struct buf buf, /* keyword buffer */ dbuf; /* description buffer */ extern int optind; @@ -271,16 +285,26 @@ main(int argc, char *argv[]) db = idx = NULL; mp = NULL; hash = NULL; + recs = NULL; + recsz = reccur = 0; + maxrec = 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 +335,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 +358,86 @@ main(int argc, char *argv[]) } /* + * If we're going to delete or update a database, remove the + * entries now (both the index and all keywords pointing to it). + * This doesn't actually remove them: it only sets their record + * value lengths to zero. + * While doing so, add the empty records to a list we'll access + * later in re-adding entries to the database. + */ + + if (OP_DELETE == op || OP_UPDATE == op) { + seq = R_FIRST; + while (0 == (ch = (*idx->seq)(idx, &key, &val, seq))) { + seq = R_NEXT; + maxrec = *(recno_t *)key.data; + if (0 == val.size && OP_UPDATE == op) { + if (reccur >= recsz) { + recsz += MANDOC_SLOP; + recs = mandoc_realloc + (recs, recsz * sizeof(recno_t)); + } + recs[(int)reccur] = maxrec; + reccur++; + continue; + } + + fn = (char *)val.data; + for (i = 0; i < argc; i++) + if (0 == strcmp(fn, argv[i])) + break; + + if (i == argc) + continue; + + sseq = R_FIRST; + while (0 == (ch = (*db->seq)(db, &key, &val, sseq))) { + sseq = R_NEXT; + assert(8 == val.size); + if (maxrec != *(recno_t *)(val.data + 4)) + continue; + if (verb > 1) + printf("%s: Deleted keyword: %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); + } + + if (verb) + printf("%s: Deleted index\n", fn); + + val.size = 0; + ch = (*idx->put)(idx, &key, &val, R_CURSOR); + if (ch < 0) { + perror(ibuf); + exit((int)MANDOCLEVEL_SYSERR); + } + + if (OP_UPDATE == op) { + if (reccur >= recsz) { + recsz += MANDOC_SLOP; + recs = mandoc_realloc + (recs, recsz * sizeof(recno_t)); + } + recs[(int)reccur] = maxrec; + reccur++; + } + } + maxrec++; + } + + if (OP_DELETE == op) { + ec = MANDOCLEVEL_OK; + goto out; + } + + /* + * 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 +450,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 (reccur > 0) { + --reccur; + rec = recs[(int)reccur]; + } else if (maxrec > 0) { + rec = maxrec; + maxrec = 0; + } else + rec++; + } else + rec++; - while (NULL != (fn = *argv++)) { mparse_reset(mp); hash_reset(&hash); @@ -359,9 +480,11 @@ 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 * filename, a nil-terminated manual section, and a @@ -403,12 +526,10 @@ main(int argc, char *argv[]) val.data = vbuf; if (verb > 1) - printf("%s: Keyword %s: 0x%x\n", + printf("%s: Added keyword: %s, 0x%x\n", fn, (char *)key.data, *(int *)val.data); - dbt_put(db, fbuf, &key, &val); - } if (ch < 0) { perror("hash"); @@ -430,14 +551,12 @@ main(int argc, char *argv[]) val.size = dbuf.len; if (verb > 0) - printf("%s: Indexed\n", fn); + printf("%s: Added index\n", fn); dbt_put(idx, ibuf, &key, &val); - rec++; } ec = MANDOCLEVEL_OK; - out: if (db) (*db->close)(db); @@ -450,6 +569,7 @@ out: free(buf.cp); free(dbuf.cp); + free(recs); return((int)ec); } @@ -980,6 +1100,6 @@ static void usage(void) { - fprintf(stderr, "usage: %s [-v] [-d path] [file...]\n", + fprintf(stderr, "usage: %s [-ruv] [-d path] [file...]\n", progname); }