]> git.cameronkatri.com Git - mandoc.git/blobdiff - apropos_db.c
Simplify by not pre-filtering the result vector for satisfied matches:
[mandoc.git] / apropos_db.c
index 41d7874245f2cd4470355ae5ee28a3226e59bd4b..50a84230958a06816e3cfd966cb2fa35e3f758f6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: apropos_db.c,v 1.27 2011/12/20 21:41:11 schwarze 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? */
@@ -73,7 +69,7 @@ struct        type {
 };
 
 struct rectree {
-       struct rec      *node; /* record array for dir tree */
+       struct res      *node; /* record array for dir tree */
        int              len; /* length of record array */
 };
 
@@ -123,22 +119,21 @@ static    const struct type types[] = {
 
 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);
@@ -153,6 +148,7 @@ btree_open(void)
        DB              *db;
 
        memset(&info, 0, sizeof(BTREEINFO));
+       info.lorder = 4321;
        info.flags = R_DUP;
 
        db = dbopen(MANDOC_DB, O_RDONLY, 0, DB_BTREE, &info);
@@ -167,14 +163,13 @@ btree_open(void)
  * 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)
 {
-       struct db_val    raw_dbv;
+       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? */
@@ -182,9 +177,9 @@ btree_read(const DBT *k, const DBT *v,
                return(0);
 
        norm_string((const char *)k->data, mc, buf);
-       memcpy(&raw_dbv, v->data, v->size);
-       dbv->rec = betoh32(raw_dbv.rec);
-       dbv->mask = betoh64(raw_dbv.mask);
+       memcpy(vbuf, v->data, v->size);
+       *mask = betoh64(vbuf[0]);
+       *rec  = betoh64(vbuf[1]);
        return(1);
 }
 
@@ -361,7 +356,7 @@ index_open(void)
  */
 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;
@@ -381,24 +376,24 @@ index_read(const DBT *key, const DBT *val, int index,
 
        cp = val->data;
        assert(sizeof(recno_t) == key->size);
-       memcpy(&rec->res.rec, key->data, key->size);
-       rec->res.volume = index;
+       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);
 }
 
@@ -411,17 +406,19 @@ index_read(const DBT *key, const DBT *val, int index,
 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
@@ -431,37 +428,19 @@ apropos_search(int pathsz, char **paths, const struct opts *opts,
        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
@@ -473,9 +452,10 @@ single_search(struct rectree *tree, const struct opts *opts,
        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;
@@ -484,7 +464,7 @@ single_search(struct rectree *tree, const struct opts *opts,
        buf     = NULL;
        rs      = tree->node;
 
-       memset(&r, 0, sizeof(struct rec));
+       memset(&r, 0, sizeof(struct res));
 
        if (NULL == (btree = btree_open()))
                return(1);
@@ -495,14 +475,14 @@ single_search(struct rectree *tree, const struct opts *opts,
        }
 
        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;
 
                /*
@@ -512,10 +492,10 @@ single_search(struct rectree *tree, const struct opts *opts,
                 */
 
                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
@@ -527,9 +507,9 @@ single_search(struct rectree *tree, const struct opts *opts,
                 * 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;
                }
 
@@ -539,7 +519,7 @@ single_search(struct rectree *tree, const struct opts *opts,
                 * 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))
@@ -551,27 +531,27 @@ single_search(struct rectree *tree, const struct opts *opts,
 
                /* 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;
@@ -585,21 +565,18 @@ single_search(struct rectree *tree, const struct opts *opts,
        (*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);
 }
 
 /*
@@ -890,7 +867,7 @@ expreval(const struct expr *p, int *ms)
  */
 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);