-/* $Id: apropos_db.c,v 1.6 2011/11/20 12:39:08 kristaps Exp $ */
+/* $Id: apropos_db.c,v 1.10 2011/11/20 16:29:50 kristaps Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#ifdef __linux__
# include <db_185.h>
const char *name;
};
+struct rectree {
+ struct rec *node; /* record array for dir tree */
+ int len; /* length of record array */
+};
+
static const struct type types[] = {
- { TYPE_An, "An" },
- { TYPE_Ar, "Ar" },
- { TYPE_At, "At" },
- { TYPE_Bsx, "Bsx" },
- { TYPE_Bx, "Bx" },
- { TYPE_Cd, "Cd" },
- { TYPE_Cm, "Cm" },
- { TYPE_Dv, "Dv" },
- { TYPE_Dx, "Dx" },
- { TYPE_Em, "Em" },
- { TYPE_Er, "Er" },
- { TYPE_Ev, "Ev" },
- { TYPE_Fa, "Fa" },
- { TYPE_Fl, "Fl" },
- { TYPE_Fn, "Fn" },
- { TYPE_Fn, "Fo" },
- { TYPE_Ft, "Ft" },
- { TYPE_Fx, "Fx" },
- { TYPE_Ic, "Ic" },
- { TYPE_In, "In" },
- { TYPE_Lb, "Lb" },
- { TYPE_Li, "Li" },
- { TYPE_Lk, "Lk" },
- { TYPE_Ms, "Ms" },
- { TYPE_Mt, "Mt" },
- { TYPE_Nd, "Nd" },
- { TYPE_Nm, "Nm" },
- { TYPE_Nx, "Nx" },
- { TYPE_Ox, "Ox" },
- { TYPE_Pa, "Pa" },
- { TYPE_Rs, "Rs" },
- { TYPE_Sh, "Sh" },
- { TYPE_Ss, "Ss" },
- { TYPE_St, "St" },
- { TYPE_Sy, "Sy" },
- { TYPE_Tn, "Tn" },
- { TYPE_Va, "Va" },
- { TYPE_Va, "Vt" },
- { TYPE_Xr, "Xr" },
+ { TYPE_An, "An" },
+ { TYPE_Ar, "Ar" },
+ { TYPE_At, "At" },
+ { TYPE_Bsx, "Bsx" },
+ { TYPE_Bx, "Bx" },
+ { TYPE_Cd, "Cd" },
+ { TYPE_Cm, "Cm" },
+ { TYPE_Dv, "Dv" },
+ { TYPE_Dx, "Dx" },
+ { TYPE_Em, "Em" },
+ { TYPE_Er, "Er" },
+ { TYPE_Ev, "Ev" },
+ { TYPE_Fa, "Fa" },
+ { TYPE_Fl, "Fl" },
+ { TYPE_Fn, "Fn" },
+ { TYPE_Fn, "Fo" },
+ { TYPE_Ft, "Ft" },
+ { TYPE_Fx, "Fx" },
+ { TYPE_Ic, "Ic" },
+ { TYPE_In, "In" },
+ { TYPE_Lb, "Lb" },
+ { TYPE_Li, "Li" },
+ { TYPE_Lk, "Lk" },
+ { TYPE_Ms, "Ms" },
+ { TYPE_Mt, "Mt" },
+ { TYPE_Nd, "Nd" },
+ { TYPE_Nm, "Nm" },
+ { TYPE_Nx, "Nx" },
+ { TYPE_Ox, "Ox" },
+ { TYPE_Pa, "Pa" },
+ { TYPE_Rs, "Rs" },
+ { TYPE_Sh, "Sh" },
+ { TYPE_Ss, "Ss" },
+ { TYPE_St, "St" },
+ { TYPE_Sy, "Sy" },
+ { TYPE_Tn, "Tn" },
+ { TYPE_Va, "Va" },
+ { TYPE_Va, "Vt" },
+ { TYPE_Xr, "Xr" },
{ INT_MAX, "any" },
{ 0, NULL }
};
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 *);
/*
* Open the keyword mandoc-db database.
}
/*
- * Search the mandocdb database for the expression "expr".
+ * Search mandocdb databases in paths for expression "expr".
* Filter out by "opts".
* Call "res" with the results, which may be zero.
* Return 0 if there was a database error, else return 1.
*/
int
-apropos_search(const struct opts *opts, const struct expr *expr,
- size_t terms, void *arg,
+apropos_search(int pathsz, char **paths, const struct opts *opts,
+ const struct expr *expr, size_t terms, void *arg,
void (*res)(struct res *, size_t, void *))
{
- int i, rsz, root, leaf, mlen, rc, ch;
+ struct rectree tree;
+ struct mchars *mc;
+ struct res *ress;
+ int i, mlen, rc;
+
+ memset(&tree, 0, sizeof(struct rectree));
+
+ rc = 0;
+ mc = mchars_alloc();
+
+ /*
+ * Main loop. Change into the directory containing manpage
+ * databases. Run our expession over each database in the set.
+ */
+
+ for (i = 0; i < pathsz; i++) {
+ if (chdir(paths[i]))
+ continue;
+ if ( ! single_search(&tree, opts, expr, terms, mc))
+ 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);
+
+ rc = 1;
+out:
+ for (i = 0; i < tree.len; i++)
+ recfree(&tree.node[i]);
+
+ free(tree.node);
+ mchars_free(mc);
+ return(rc);
+}
+
+static int
+single_search(struct rectree *tree, const struct opts *opts,
+ const struct expr *expr, size_t terms,
+ struct mchars *mc)
+{
+ int root, leaf, ch;
uint64_t mask;
DBT key, val;
DB *btree, *idx;
- struct mchars *mc;
char *buf;
recno_t rec;
struct rec *rs;
- struct res *ress;
struct rec r;
struct db_val *vbuf;
- rc = 0;
root = -1;
leaf = -1;
btree = NULL;
idx = NULL;
- mc = NULL;
buf = NULL;
- rs = NULL;
- rsz = 0;
+ rs = tree->node;
memset(&r, 0, sizeof(struct rec));
- mc = mchars_alloc();
-
if (NULL == (btree = btree_open()))
- goto out;
- if (NULL == (idx = index_open()))
- goto out;
+ return(1);
+
+ if (NULL == (idx = index_open())) {
+ (*btree->close)(btree);
+ return(1);
+ }
while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) {
if (key.size < 2 || sizeof(struct db_val) != val.size)
if (opts->arch && strcasecmp(opts->arch, r.res.arch))
continue;
- rs = mandoc_realloc
- (rs, (rsz + 1) * sizeof(struct rec));
+ tree->node = rs = mandoc_realloc
+ (rs, (tree->len + 1) * sizeof(struct rec));
- memcpy(&rs[rsz], &r, sizeof(struct rec));
- rs[rsz].matches = mandoc_calloc(terms, sizeof(int));
+ memcpy(&rs[tree->len], &r, sizeof(struct rec));
+ rs[tree->len].matches =
+ mandoc_calloc(terms, sizeof(int));
- exprexec(expr, buf, mask, &rs[rsz]);
+ exprexec(expr, buf, mask, &rs[tree->len]);
/* Append to our tree. */
if (leaf >= 0) {
if (rec > rs[leaf].res.rec)
- rs[leaf].rhs = rsz;
+ rs[leaf].rhs = tree->len;
else
- rs[leaf].lhs = rsz;
+ rs[leaf].lhs = tree->len;
} else
- root = rsz;
+ root = tree->len;
memset(&r, 0, sizeof(struct rec));
- rsz++;
+ tree->len++;
}
- /*
- * If we haven't encountered any database errors, then construct
- * an array of results and push them to the caller.
- */
-
- if (1 == ch) {
- for (mlen = i = 0; i < rsz; i++)
- if (rs[i].matched)
- mlen++;
- ress = mandoc_malloc(mlen * sizeof(struct res));
- for (mlen = i = 0; i < rsz; i++)
- if (rs[i].matched)
- memcpy(&ress[mlen++], &rs[i].res,
- sizeof(struct res));
- (*res)(ress, mlen, arg);
- free(ress);
- rc = 1;
- }
-
-out:
- for (i = 0; i < rsz; i++)
- recfree(&rs[i]);
-
- recfree(&r);
-
- if (mc)
- mchars_free(mc);
- if (btree)
- (*btree->close)(btree);
- if (idx)
- (*idx->close)(idx);
+ (*btree->close)(btree);
+ (*idx->close)(idx);
free(buf);
- free(rs);
- return(rc);
+ return(1 == ch);
}
static void