version 1.29, 2012/03/23 05:07:35 |
version 1.30, 2012/03/24 00:31:55 |
|
|
#include "apropos_db.h" |
#include "apropos_db.h" |
#include "mandoc.h" |
#include "mandoc.h" |
|
|
struct rec { |
#define RESFREE(_x) \ |
struct res res; /* resulting record info */ |
do { \ |
/* |
free((_x)->file); \ |
* Maintain a binary tree for checking the uniqueness of `rec' |
free((_x)->cat); \ |
* when adding elements to the results array. |
free((_x)->title); \ |
* Since the results array is dynamic, use offset in the array |
free((_x)->arch); \ |
* instead of a pointer to the structure. |
free((_x)->desc); \ |
*/ |
free((_x)->matches); \ |
int lhs; |
} while (/*CONSTCOND*/0) |
int rhs; |
|
int matched; /* expression is true */ |
|
int *matches; /* partial truth evaluations */ |
|
}; |
|
|
|
struct expr { |
struct expr { |
int regex; /* is regex? */ |
int regex; /* is regex? */ |
|
|
}; |
}; |
|
|
struct rectree { |
struct rectree { |
struct rec *node; /* record array for dir tree */ |
struct res *node; /* record array for dir tree */ |
int len; /* length of record array */ |
int len; /* length of record array */ |
}; |
}; |
|
|
Line 127 static int btree_read(const DBT *, const DBT *, |
|
Line 123 static int btree_read(const DBT *, const DBT *, |
|
uint64_t *, recno_t *, char **); |
uint64_t *, recno_t *, char **); |
static int expreval(const struct expr *, int *); |
static int expreval(const struct expr *, int *); |
static void exprexec(const struct expr *, |
static void exprexec(const struct expr *, |
const char *, uint64_t, struct rec *); |
const char *, uint64_t, struct res *); |
static int exprmark(const struct expr *, |
static int exprmark(const struct expr *, |
const char *, uint64_t, int *); |
const char *, uint64_t, int *); |
static struct expr *exprexpr(int, char *[], int *, int *, size_t *); |
static struct expr *exprexpr(int, char *[], int *, int *, size_t *); |
static struct expr *exprterm(char *, int); |
static struct expr *exprterm(char *, int); |
static DB *index_open(void); |
static DB *index_open(void); |
static int index_read(const DBT *, const DBT *, int, |
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 *, |
static void norm_string(const char *, |
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 int single_search(struct rectree *, const struct opts *, |
static int single_search(struct rectree *, const struct opts *, |
const struct expr *, size_t terms, |
const struct expr *, size_t terms, |
struct mchars *, int); |
struct mchars *, int); |
Line 361 index_open(void) |
|
Line 356 index_open(void) |
|
*/ |
*/ |
static int |
static int |
index_read(const DBT *key, const DBT *val, int index, |
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; |
size_t left; |
char *np, *cp; |
char *np, *cp; |
Line 381 index_read(const DBT *key, const DBT *val, int index, |
|
Line 376 index_read(const DBT *key, const DBT *val, int index, |
|
|
|
cp = val->data; |
cp = val->data; |
assert(sizeof(recno_t) == key->size); |
assert(sizeof(recno_t) == key->size); |
memcpy(&rec->res.rec, key->data, key->size); |
memcpy(&rec->rec, key->data, key->size); |
rec->res.volume = index; |
rec->volume = index; |
|
|
if ('d' == (type = *cp++)) |
if ('d' == (type = *cp++)) |
rec->res.type = RESTYPE_MDOC; |
rec->type = RESTYPE_MDOC; |
else if ('a' == type) |
else if ('a' == type) |
rec->res.type = RESTYPE_MAN; |
rec->type = RESTYPE_MAN; |
else if ('c' == type) |
else if ('c' == type) |
rec->res.type = RESTYPE_CAT; |
rec->type = RESTYPE_CAT; |
else |
else |
return(0); |
return(0); |
|
|
left--; |
left--; |
INDEX_BREAD(rec->res.file); |
INDEX_BREAD(rec->file); |
INDEX_BREAD(rec->res.cat); |
INDEX_BREAD(rec->cat); |
INDEX_BREAD(rec->res.title); |
INDEX_BREAD(rec->title); |
INDEX_BREAD(rec->res.arch); |
INDEX_BREAD(rec->arch); |
INDEX_BREAD(rec->res.desc); |
INDEX_BREAD(rec->desc); |
return(1); |
return(1); |
} |
} |
|
|
Line 411 index_read(const DBT *key, const DBT *val, int index, |
|
Line 406 index_read(const DBT *key, const DBT *val, int index, |
|
int |
int |
apropos_search(int pathsz, char **paths, const struct opts *opts, |
apropos_search(int pathsz, char **paths, const struct opts *opts, |
const struct expr *expr, size_t terms, void *arg, |
const struct expr *expr, size_t terms, void *arg, |
|
size_t *sz, struct res **resp, |
void (*res)(struct res *, size_t, void *)) |
void (*res)(struct res *, size_t, void *)) |
{ |
{ |
struct rectree tree; |
struct rectree tree; |
struct mchars *mc; |
struct mchars *mc; |
struct res *ress; |
int i, rc; |
int i, mlen, rc; |
|
|
|
memset(&tree, 0, sizeof(struct rectree)); |
memset(&tree, 0, sizeof(struct rectree)); |
|
|
rc = 0; |
rc = 0; |
mc = mchars_alloc(); |
mc = mchars_alloc(); |
|
*sz = 0; |
|
*resp = NULL; |
|
|
/* |
/* |
* Main loop. Change into the directory containing manpage |
* Main loop. Change into the directory containing manpage |
Line 431 apropos_search(int pathsz, char **paths, const struct |
|
Line 428 apropos_search(int pathsz, char **paths, const struct |
|
for (i = 0; i < pathsz; i++) { |
for (i = 0; i < pathsz; i++) { |
if (chdir(paths[i])) |
if (chdir(paths[i])) |
continue; |
continue; |
if ( ! single_search(&tree, opts, expr, terms, mc, i)) |
if (single_search(&tree, opts, expr, terms, mc, i)) |
goto out; |
continue; |
|
|
|
resfree(tree.node, tree.len); |
|
mchars_free(mc); |
|
return(0); |
} |
} |
|
|
/* |
(*res)(tree.node, tree.len, arg); |
* Count matching files, transfer to a "clean" array, then feed |
*sz = tree.len; |
* them to the output handler. |
*resp = tree.node; |
*/ |
|
|
|
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); |
mchars_free(mc); |
return(rc); |
return(1); |
} |
} |
|
|
static int |
static int |
Line 473 single_search(struct rectree *tree, const struct opts |
|
Line 452 single_search(struct rectree *tree, const struct opts |
|
DBT key, val; |
DBT key, val; |
DB *btree, *idx; |
DB *btree, *idx; |
char *buf; |
char *buf; |
struct rec *rs; |
struct res *rs; |
struct rec r; |
struct res r; |
uint64_t mask; |
uint64_t mask; |
recno_t rec; |
recno_t rec; |
|
|
Line 485 single_search(struct rectree *tree, const struct opts |
|
Line 464 single_search(struct rectree *tree, const struct opts |
|
buf = NULL; |
buf = NULL; |
rs = tree->node; |
rs = tree->node; |
|
|
memset(&r, 0, sizeof(struct rec)); |
memset(&r, 0, sizeof(struct res)); |
|
|
if (NULL == (btree = btree_open())) |
if (NULL == (btree = btree_open())) |
return(1); |
return(1); |
Line 513 single_search(struct rectree *tree, const struct opts |
|
Line 492 single_search(struct rectree *tree, const struct opts |
|
*/ |
*/ |
|
|
for (leaf = root; leaf >= 0; ) |
for (leaf = root; leaf >= 0; ) |
if (rec > rs[leaf].res.rec && |
if (rec > rs[leaf].rec && |
rs[leaf].rhs >= 0) |
rs[leaf].rhs >= 0) |
leaf = rs[leaf].rhs; |
leaf = rs[leaf].rhs; |
else if (rec < rs[leaf].res.rec && |
else if (rec < rs[leaf].rec && |
rs[leaf].lhs >= 0) |
rs[leaf].lhs >= 0) |
leaf = rs[leaf].lhs; |
leaf = rs[leaf].lhs; |
else |
else |
Line 528 single_search(struct rectree *tree, const struct opts |
|
Line 507 single_search(struct rectree *tree, const struct opts |
|
* try to evaluate it now and continue anyway. |
* try to evaluate it now and continue anyway. |
*/ |
*/ |
|
|
if (leaf >= 0 && rs[leaf].res.rec == rec) { |
if (leaf >= 0 && rs[leaf].rec == rec) { |
if (0 == rs[leaf].matched) |
if (0 == rs[leaf].matched) |
exprexec(expr, buf, mask, &rs[leaf]); |
exprexec(expr, buf, mask, &rs[leaf]); |
continue; |
continue; |
Line 552 single_search(struct rectree *tree, const struct opts |
|
Line 531 single_search(struct rectree *tree, const struct opts |
|
|
|
/* XXX: this should be elsewhere, I guess? */ |
/* 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; |
continue; |
|
|
if (opts->arch && *r.res.arch) |
if (opts->arch && *r.arch) |
if (strcasecmp(opts->arch, r.res.arch)) |
if (strcasecmp(opts->arch, r.arch)) |
continue; |
continue; |
|
|
tree->node = rs = mandoc_realloc |
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)); |
memcpy(&rs[tree->len], &r, sizeof(struct res)); |
memset(&r, 0, sizeof(struct rec)); |
memset(&r, 0, sizeof(struct res)); |
rs[tree->len].matches = |
rs[tree->len].matches = |
mandoc_calloc(terms, sizeof(int)); |
mandoc_calloc(terms, sizeof(int)); |
|
|
Line 572 single_search(struct rectree *tree, const struct opts |
|
Line 551 single_search(struct rectree *tree, const struct opts |
|
/* Append to our tree. */ |
/* Append to our tree. */ |
|
|
if (leaf >= 0) { |
if (leaf >= 0) { |
if (rec > rs[leaf].res.rec) |
if (rec > rs[leaf].rec) |
rs[leaf].rhs = tree->len; |
rs[leaf].rhs = tree->len; |
else |
else |
rs[leaf].lhs = tree->len; |
rs[leaf].lhs = tree->len; |
Line 586 single_search(struct rectree *tree, const struct opts |
|
Line 565 single_search(struct rectree *tree, const struct opts |
|
(*idx->close)(idx); |
(*idx->close)(idx); |
|
|
free(buf); |
free(buf); |
recfree(&r); |
RESFREE(&r); |
return(1 == ch); |
return(1 == ch); |
} |
} |
|
|
static void |
void |
recfree(struct rec *rec) |
resfree(struct res *rec, size_t sz) |
{ |
{ |
|
size_t i; |
|
|
free(rec->res.file); |
for (i = 0; i < sz; i++) |
free(rec->res.cat); |
RESFREE(&rec[i]); |
free(rec->res.title); |
free(rec); |
free(rec->res.arch); |
|
free(rec->res.desc); |
|
|
|
free(rec->matches); |
|
} |
} |
|
|
/* |
/* |
Line 891 expreval(const struct expr *p, int *ms) |
|
Line 867 expreval(const struct expr *p, int *ms) |
|
*/ |
*/ |
static void |
static void |
exprexec(const struct expr *e, const char *cp, |
exprexec(const struct expr *e, const char *cp, |
uint64_t mask, struct rec *r) |
uint64_t mask, struct res *r) |
{ |
{ |
|
|
assert(0 == r->matched); |
assert(0 == r->matched); |