version 1.4, 2011/11/16 13:23:27 |
version 1.5, 2011/11/17 14:52:32 |
|
|
#include <stdarg.h> |
#include <stdarg.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
|
#include <unistd.h> |
|
|
#ifdef __linux__ |
#ifdef __linux__ |
# include <db_185.h> |
# include <db_185.h> |
|
|
#include "apropos_db.h" |
#include "apropos_db.h" |
#include "mandoc.h" |
#include "mandoc.h" |
|
|
|
struct rectree { |
|
struct rec *node; |
|
int len; |
|
}; |
|
|
struct expr { |
struct expr { |
int regex; |
int regex; |
int index; |
int index; |
|
|
const struct mchars *, char **); |
const struct mchars *, char **); |
static size_t norm_utf8(unsigned int, char[7]); |
static size_t norm_utf8(unsigned int, char[7]); |
static void recfree(struct rec *); |
static void recfree(struct rec *); |
|
static void single_search(struct rectree *, const struct opts *, |
|
const struct expr *, size_t terms, |
|
struct mchars *); |
|
|
/* |
/* |
* Open the keyword mandoc-db database. |
* Open the keyword mandoc-db database. |
|
|
* Call "res" with the results, which may be zero. |
* Call "res" with the results, which may be zero. |
*/ |
*/ |
void |
void |
apropos_search(const struct opts *opts, const struct expr *expr, |
apropos_search(int argc, char *argv[], const struct opts *opts, |
size_t terms, void *arg, |
const struct expr *expr, size_t terms, void *arg, |
void (*res)(struct rec *, size_t, void *)) |
void (*res)(struct rec *, size_t, void *)) |
{ |
{ |
int i, len, root, leaf, mask, mlen; |
struct rectree tree; |
|
struct mchars *mc; |
|
struct rec *recs; |
|
int i, mlen; |
|
|
|
memset(&tree, 0, sizeof(struct rectree)); |
|
|
|
/* XXX: error out with bad regexp? */ |
|
|
|
mc = mchars_alloc(); |
|
|
|
for (i = 0; i < argc; i++) { |
|
if (chdir(argv[i])) |
|
continue; |
|
single_search(&tree, opts, expr, terms, mc); |
|
} |
|
|
|
/* |
|
* Count the matching files |
|
* and feed them to the output handler. |
|
*/ |
|
|
|
for (mlen = i = 0; i < tree.len; i++) |
|
if (tree.node[i].matches[0]) |
|
mlen++; |
|
recs = mandoc_malloc(mlen * sizeof(struct rec)); |
|
for (mlen = i = 0; i < tree.len; i++) |
|
if (tree.node[i].matches[0]) |
|
memcpy(&recs[mlen++], &tree.node[i], |
|
sizeof(struct rec)); |
|
(*res)(recs, mlen, arg); |
|
free(recs); |
|
|
|
for (i = 0; i < tree.len; i++) |
|
recfree(&tree.node[i]); |
|
|
|
if (mc) |
|
mchars_free(mc); |
|
} |
|
|
|
static void |
|
single_search(struct rectree *tree, const struct opts *opts, |
|
const struct expr *expr, size_t terms, |
|
struct mchars *mc) |
|
{ |
|
int root, leaf, mask; |
DBT key, val; |
DBT key, val; |
DB *btree, *idx; |
DB *btree, *idx; |
struct mchars *mc; |
|
int ch; |
int ch; |
char *buf; |
char *buf; |
recno_t rec; |
recno_t rec; |
struct rec *recs, *rrecs; |
struct rec *recs; |
struct rec srec; |
struct rec srec; |
|
|
root = -1; |
root = -1; |
leaf = -1; |
leaf = -1; |
btree = NULL; |
btree = NULL; |
idx = NULL; |
idx = NULL; |
mc = NULL; |
|
buf = NULL; |
buf = NULL; |
recs = NULL; |
recs = tree->node; |
len = 0; |
|
|
|
memset(&srec, 0, sizeof(struct rec)); |
memset(&srec, 0, sizeof(struct rec)); |
|
|
/* XXX: error out with bad regexp? */ |
|
|
|
mc = mchars_alloc(); |
|
|
|
/* XXX: return fact that we've errored? */ |
/* XXX: return fact that we've errored? */ |
|
|
if (NULL == (btree = btree_open())) |
if (NULL == (btree = btree_open())) |
|
|
if (opts->arch && strcasecmp(opts->arch, srec.arch)) |
if (opts->arch && strcasecmp(opts->arch, srec.arch)) |
continue; |
continue; |
|
|
recs = mandoc_realloc |
tree->node = recs = mandoc_realloc |
(recs, (len + 1) * sizeof(struct rec)); |
(recs, (tree->len + 1) * sizeof(struct rec)); |
|
|
memcpy(&recs[len], &srec, sizeof(struct rec)); |
memcpy(&recs[tree->len], &srec, sizeof(struct rec)); |
recs[len].matches = |
recs[tree->len].matches = |
mandoc_calloc(terms + 1, sizeof(int)); |
mandoc_calloc(terms + 1, sizeof(int)); |
|
|
exprexecpost |
exprexecpost |
(expr, buf, mask, |
(expr, buf, mask, |
recs[len].matches, terms); |
recs[tree->len].matches, terms); |
|
|
/* Append to our tree. */ |
/* Append to our tree. */ |
|
|
if (leaf >= 0) { |
if (leaf >= 0) { |
if (rec > recs[leaf].rec) |
if (rec > recs[leaf].rec) |
recs[leaf].rhs = len; |
recs[leaf].rhs = tree->len; |
else |
else |
recs[leaf].lhs = len; |
recs[leaf].lhs = tree->len; |
} else |
} else |
root = len; |
root = tree->len; |
|
|
memset(&srec, 0, sizeof(struct rec)); |
memset(&srec, 0, sizeof(struct rec)); |
len++; |
tree->len++; |
} |
} |
|
|
if (1 == ch) { |
/* XXX handle database errors? */ |
for (mlen = i = 0; i < len; i++) |
|
if (recs[i].matches[0]) |
|
mlen++; |
|
rrecs = mandoc_malloc(mlen * sizeof(struct rec)); |
|
for (mlen = i = 0; i < len; i++) |
|
if (recs[i].matches[0]) |
|
memcpy(&rrecs[mlen++], &recs[i], |
|
sizeof(struct rec)); |
|
(*res)(rrecs, mlen, arg); |
|
free(rrecs); |
|
} |
|
|
|
/* XXX: else? corrupt database error? */ |
|
out: |
out: |
for (i = 0; i < len; i++) |
|
recfree(&recs[i]); |
|
|
|
recfree(&srec); |
recfree(&srec); |
|
|
if (mc) |
|
mchars_free(mc); |
|
if (btree) |
if (btree) |
(*btree->close)(btree); |
(*btree->close)(btree); |
if (idx) |
if (idx) |
(*idx->close)(idx); |
(*idx->close)(idx); |
|
|
free(buf); |
free(buf); |
free(recs); |
|
} |
} |
|
|
static void |
static void |