-/* $Id: apropos_db.c,v 1.26 2011/12/16 20:06:58 kristaps Exp $ */
+/* $Id: apropos_db.c,v 1.30 2012/03/24 00:31:55 kristaps Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
#include "apropos_db.h"
#include "mandoc.h"
-struct rec {
- struct res res; /* resulting record info */
- /*
- * Maintain a binary tree for checking the uniqueness of `rec'
- * when adding elements to the results array.
- * Since the results array is dynamic, use offset in the array
- * instead of a pointer to the structure.
- */
- int lhs;
- int rhs;
- int matched; /* expression is true */
- int *matches; /* partial truth evaluations */
-};
+#define RESFREE(_x) \
+ do { \
+ free((_x)->file); \
+ free((_x)->cat); \
+ free((_x)->title); \
+ free((_x)->arch); \
+ free((_x)->desc); \
+ free((_x)->matches); \
+ } while (/*CONSTCOND*/0)
struct expr {
int regex; /* is regex? */
};
struct rectree {
- struct rec *node; /* record array for dir tree */
+ struct res *node; /* record array for dir tree */
int len; /* length of record array */
};
static DB *btree_open(void);
static int btree_read(const DBT *, const DBT *,
- const struct mchars *,
- struct db_val *, char **);
+ const struct mchars *,
+ uint64_t *, recno_t *, char **);
static int expreval(const struct expr *, int *);
static void exprexec(const struct expr *,
- const char *, uint64_t, struct rec *);
+ const char *, uint64_t, struct res *);
static int exprmark(const struct expr *,
const char *, uint64_t, int *);
static struct expr *exprexpr(int, char *[], int *, int *, size_t *);
static struct expr *exprterm(char *, int);
static DB *index_open(void);
static int index_read(const DBT *, const DBT *, int,
- const struct mchars *, struct rec *);
+ const struct mchars *, struct res *);
static void norm_string(const char *,
const struct mchars *, char **);
static size_t norm_utf8(unsigned int, char[7]);
-static void recfree(struct rec *);
static int single_search(struct rectree *, const struct opts *,
const struct expr *, size_t terms,
struct mchars *, int);
DB *db;
memset(&info, 0, sizeof(BTREEINFO));
+ info.lorder = 4321;
info.flags = R_DUP;
db = dbopen(MANDOC_DB, O_RDONLY, 0, DB_BTREE, &info);
* Return 0 if the database is insane, else 1.
*/
static int
-btree_read(const DBT *k, const DBT *v,
- const struct mchars *mc,
- struct db_val *dbv, char **buf)
+btree_read(const DBT *k, const DBT *v, const struct mchars *mc,
+ uint64_t *mask, recno_t *rec, char **buf)
{
- const struct db_val *vp;
+ uint64_t vbuf[2];
/* Are our sizes sane? */
- if (k->size < 2 || sizeof(struct db_val) != v->size)
+ if (k->size < 2 || sizeof(vbuf) != v->size)
return(0);
/* Is our string nil-terminated? */
if ('\0' != ((const char *)k->data)[(int)k->size - 1])
return(0);
- vp = v->data;
norm_string((const char *)k->data, mc, buf);
- dbv->rec = betoh32(vp->rec);
- dbv->mask = betoh64(vp->mask);
+ memcpy(vbuf, v->data, v->size);
+ *mask = betoh64(vbuf[0]);
+ *rec = betoh64(vbuf[1]);
return(1);
}
*/
static int
index_read(const DBT *key, const DBT *val, int index,
- const struct mchars *mc, struct rec *rec)
+ const struct mchars *mc, struct res *rec)
{
size_t left;
char *np, *cp;
return(0);
cp = val->data;
- rec->res.rec = *(recno_t *)key->data;
- rec->res.volume = index;
+ assert(sizeof(recno_t) == key->size);
+ memcpy(&rec->rec, key->data, key->size);
+ rec->volume = index;
if ('d' == (type = *cp++))
- rec->res.type = RESTYPE_MDOC;
+ rec->type = RESTYPE_MDOC;
else if ('a' == type)
- rec->res.type = RESTYPE_MAN;
+ rec->type = RESTYPE_MAN;
else if ('c' == type)
- rec->res.type = RESTYPE_CAT;
+ rec->type = RESTYPE_CAT;
else
return(0);
left--;
- INDEX_BREAD(rec->res.file);
- INDEX_BREAD(rec->res.cat);
- INDEX_BREAD(rec->res.title);
- INDEX_BREAD(rec->res.arch);
- INDEX_BREAD(rec->res.desc);
+ INDEX_BREAD(rec->file);
+ INDEX_BREAD(rec->cat);
+ INDEX_BREAD(rec->title);
+ INDEX_BREAD(rec->arch);
+ INDEX_BREAD(rec->desc);
return(1);
}
int
apropos_search(int pathsz, char **paths, const struct opts *opts,
const struct expr *expr, size_t terms, void *arg,
+ size_t *sz, struct res **resp,
void (*res)(struct res *, size_t, void *))
{
struct rectree tree;
struct mchars *mc;
- struct res *ress;
- int i, mlen, rc;
+ int i, rc;
memset(&tree, 0, sizeof(struct rectree));
rc = 0;
mc = mchars_alloc();
+ *sz = 0;
+ *resp = NULL;
/*
* Main loop. Change into the directory containing manpage
for (i = 0; i < pathsz; i++) {
if (chdir(paths[i]))
continue;
- if ( ! single_search(&tree, opts, expr, terms, mc, i))
- goto out;
- }
-
- /*
- * Count matching files, transfer to a "clean" array, then feed
- * them to the output handler.
- */
-
- for (mlen = i = 0; i < tree.len; i++)
- if (tree.node[i].matched)
- mlen++;
-
- ress = mandoc_malloc(mlen * sizeof(struct res));
-
- for (mlen = i = 0; i < tree.len; i++)
- if (tree.node[i].matched)
- memcpy(&ress[mlen++], &tree.node[i].res,
- sizeof(struct res));
-
- (*res)(ress, mlen, arg);
- free(ress);
+ if (single_search(&tree, opts, expr, terms, mc, i))
+ continue;
- rc = 1;
-out:
- for (i = 0; i < tree.len; i++)
- recfree(&tree.node[i]);
+ resfree(tree.node, tree.len);
+ mchars_free(mc);
+ return(0);
+ }
- free(tree.node);
+ (*res)(tree.node, tree.len, arg);
+ *sz = tree.len;
+ *resp = tree.node;
mchars_free(mc);
- return(rc);
+ return(1);
}
static int
DBT key, val;
DB *btree, *idx;
char *buf;
- struct rec *rs;
- struct rec r;
- struct db_val vb;
+ struct res *rs;
+ struct res r;
+ uint64_t mask;
+ recno_t rec;
root = -1;
leaf = -1;
buf = NULL;
rs = tree->node;
- memset(&r, 0, sizeof(struct rec));
+ memset(&r, 0, sizeof(struct res));
if (NULL == (btree = btree_open()))
return(1);
}
while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
- if ( ! btree_read(&key, &val, mc, &vb, &buf))
+ if ( ! btree_read(&key, &val, mc, &mask, &rec, &buf))
break;
/*
* See if this keyword record matches any of the
* expressions we have stored.
*/
- if ( ! exprmark(expr, buf, vb.mask, NULL))
+ if ( ! exprmark(expr, buf, mask, NULL))
continue;
/*
*/
for (leaf = root; leaf >= 0; )
- if (vb.rec > rs[leaf].res.rec &&
+ if (rec > rs[leaf].rec &&
rs[leaf].rhs >= 0)
leaf = rs[leaf].rhs;
- else if (vb.rec < rs[leaf].res.rec &&
+ else if (rec < rs[leaf].rec &&
rs[leaf].lhs >= 0)
leaf = rs[leaf].lhs;
else
* try to evaluate it now and continue anyway.
*/
- if (leaf >= 0 && rs[leaf].res.rec == vb.rec) {
+ if (leaf >= 0 && rs[leaf].rec == rec) {
if (0 == rs[leaf].matched)
- exprexec(expr, buf, vb.mask, &rs[leaf]);
+ exprexec(expr, buf, mask, &rs[leaf]);
continue;
}
* database, then begin partial evaluation.
*/
- key.data = &vb.rec;
+ key.data = &rec;
key.size = sizeof(recno_t);
if (0 != (*idx->get)(idx, &key, &val, 0))
/* XXX: this should be elsewhere, I guess? */
- if (opts->cat && strcasecmp(opts->cat, r.res.cat))
+ if (opts->cat && strcasecmp(opts->cat, r.cat))
continue;
- if (opts->arch && *r.res.arch)
- if (strcasecmp(opts->arch, r.res.arch))
+ if (opts->arch && *r.arch)
+ if (strcasecmp(opts->arch, r.arch))
continue;
tree->node = rs = mandoc_realloc
- (rs, (tree->len + 1) * sizeof(struct rec));
+ (rs, (tree->len + 1) * sizeof(struct res));
- memcpy(&rs[tree->len], &r, sizeof(struct rec));
- memset(&r, 0, sizeof(struct rec));
+ memcpy(&rs[tree->len], &r, sizeof(struct res));
+ memset(&r, 0, sizeof(struct res));
rs[tree->len].matches =
mandoc_calloc(terms, sizeof(int));
- exprexec(expr, buf, vb.mask, &rs[tree->len]);
+ exprexec(expr, buf, mask, &rs[tree->len]);
/* Append to our tree. */
if (leaf >= 0) {
- if (vb.rec > rs[leaf].res.rec)
+ if (rec > rs[leaf].rec)
rs[leaf].rhs = tree->len;
else
rs[leaf].lhs = tree->len;
(*idx->close)(idx);
free(buf);
- recfree(&r);
+ RESFREE(&r);
return(1 == ch);
}
-static void
-recfree(struct rec *rec)
+void
+resfree(struct res *rec, size_t sz)
{
+ size_t i;
- free(rec->res.file);
- free(rec->res.cat);
- free(rec->res.title);
- free(rec->res.arch);
- free(rec->res.desc);
-
- free(rec->matches);
+ for (i = 0; i < sz; i++)
+ RESFREE(&rec[i]);
+ free(rec);
}
/*
*/
static void
exprexec(const struct expr *e, const char *cp,
- uint64_t mask, struct rec *r)
+ uint64_t mask, struct res *r)
{
assert(0 == r->matched);