version 1.12, 2011/11/26 22:38:11 |
version 1.17, 2011/12/01 23:46:26 |
|
|
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
|
#include <arpa/inet.h> |
|
|
#ifdef __linux__ |
#ifdef __linux__ |
# include <db_185.h> |
# include <db_185.h> |
#else |
#else |
|
|
int regex; /* is regex? */ |
int regex; /* is regex? */ |
int index; /* index in match array */ |
int index; /* index in match array */ |
uint64_t mask; /* type-mask */ |
uint64_t mask; /* type-mask */ |
int cs; /* is case-sensitive? */ |
|
int and; /* is rhs of logical AND? */ |
int and; /* is rhs of logical AND? */ |
char *v; /* search value */ |
char *v; /* search value */ |
regex_t re; /* compiled re, if regex */ |
regex_t re; /* compiled re, if regex */ |
Line 115 static const struct type types[] = { |
|
Line 116 static const struct type types[] = { |
|
}; |
}; |
|
|
static DB *btree_open(void); |
static DB *btree_open(void); |
static int btree_read(const DBT *, |
static int btree_read(const DBT *, const DBT *, |
const struct mchars *, char **); |
const struct mchars *, |
|
struct db_val *, 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 rec *); |
Line 159 btree_open(void) |
|
Line 161 btree_open(void) |
|
* Return 0 if the database is insane, else 1. |
* Return 0 if the database is insane, else 1. |
*/ |
*/ |
static int |
static int |
btree_read(const DBT *v, const struct mchars *mc, char **buf) |
btree_read(const DBT *k, const DBT *v, |
|
const struct mchars *mc, |
|
struct db_val *dbv, char **buf) |
{ |
{ |
|
const struct db_val *vp; |
|
|
/* Sanity: are we nil-terminated? */ |
/* Are our sizes sane? */ |
|
if (k->size < 2 || sizeof(struct db_val) != v->size) |
|
return(0); |
|
|
assert(v->size > 0); |
/* Is our string nil-terminated? */ |
|
if ('\0' != ((const char *)k->data)[(int)k->size - 1]) |
if ('\0' != ((char *)v->data)[(int)v->size - 1]) |
|
return(0); |
return(0); |
|
|
norm_string((char *)v->data, mc, buf); |
vp = v->data; |
|
norm_string((const char *)k->data, mc, buf); |
|
dbv->rec = ntohl(vp->rec); |
|
dbv->mask = vp->mask; |
return(1); |
return(1); |
} |
} |
|
|
Line 366 index_read(const DBT *key, const DBT *val, int index, |
|
Line 375 index_read(const DBT *key, const DBT *val, int index, |
|
rec->res.rec = *(recno_t *)key->data; |
rec->res.rec = *(recno_t *)key->data; |
rec->res.volume = index; |
rec->res.volume = index; |
|
|
|
INDEX_BREAD(rec->res.type); |
INDEX_BREAD(rec->res.file); |
INDEX_BREAD(rec->res.file); |
INDEX_BREAD(rec->res.cat); |
INDEX_BREAD(rec->res.cat); |
INDEX_BREAD(rec->res.title); |
INDEX_BREAD(rec->res.title); |
Line 442 single_search(struct rectree *tree, const struct opts |
|
Line 452 single_search(struct rectree *tree, const struct opts |
|
struct mchars *mc, int vol) |
struct mchars *mc, int vol) |
{ |
{ |
int root, leaf, ch; |
int root, leaf, ch; |
uint64_t mask; |
|
DBT key, val; |
DBT key, val; |
DB *btree, *idx; |
DB *btree, *idx; |
char *buf; |
char *buf; |
recno_t rec; |
|
struct rec *rs; |
struct rec *rs; |
struct rec r; |
struct rec r; |
struct db_val *vbuf; |
struct db_val vb; |
|
|
root = -1; |
root = -1; |
leaf = -1; |
leaf = -1; |
Line 469 single_search(struct rectree *tree, const struct opts |
|
Line 477 single_search(struct rectree *tree, const struct opts |
|
} |
} |
|
|
while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) { |
while (0 == (ch = (*btree->seq)(btree, &key, &val, R_NEXT))) { |
if (key.size < 2 || sizeof(struct db_val) != val.size) |
if ( ! btree_read(&key, &val, mc, &vb, &buf)) |
break; |
break; |
if ( ! btree_read(&key, mc, &buf)) |
|
break; |
|
|
|
vbuf = val.data; |
|
rec = vbuf->rec; |
|
mask = vbuf->mask; |
|
|
|
/* |
/* |
* See if this keyword record matches any of the |
* See if this keyword record matches any of the |
* expressions we have stored. |
* expressions we have stored. |
*/ |
*/ |
if ( ! exprmark(expr, buf, mask, NULL)) |
if ( ! exprmark(expr, buf, vb.mask, NULL)) |
continue; |
continue; |
|
|
/* |
/* |
Line 492 single_search(struct rectree *tree, const struct opts |
|
Line 494 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 (vb.rec > rs[leaf].res.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 (vb.rec < rs[leaf].res.rec && |
rs[leaf].lhs >= 0) |
rs[leaf].lhs >= 0) |
leaf = rs[leaf].lhs; |
leaf = rs[leaf].lhs; |
else |
else |
Line 507 single_search(struct rectree *tree, const struct opts |
|
Line 509 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].res.rec == vb.rec) { |
if (0 == rs[leaf].matched) |
if (0 == rs[leaf].matched) |
exprexec(expr, buf, mask, &rs[leaf]); |
exprexec(expr, buf, vb.mask, &rs[leaf]); |
continue; |
continue; |
} |
} |
|
|
Line 519 single_search(struct rectree *tree, const struct opts |
|
Line 521 single_search(struct rectree *tree, const struct opts |
|
* database, then begin partial evaluation. |
* database, then begin partial evaluation. |
*/ |
*/ |
|
|
key.data = &rec; |
key.data = &vb.rec; |
key.size = sizeof(recno_t); |
key.size = sizeof(recno_t); |
|
|
if (0 != (*idx->get)(idx, &key, &val, 0)) |
if (0 != (*idx->get)(idx, &key, &val, 0)) |
Line 543 single_search(struct rectree *tree, const struct opts |
|
Line 545 single_search(struct rectree *tree, const struct opts |
|
rs[tree->len].matches = |
rs[tree->len].matches = |
mandoc_calloc(terms, sizeof(int)); |
mandoc_calloc(terms, sizeof(int)); |
|
|
exprexec(expr, buf, mask, &rs[tree->len]); |
exprexec(expr, buf, vb.mask, &rs[tree->len]); |
|
|
/* Append to our tree. */ |
/* Append to our tree. */ |
|
|
if (leaf >= 0) { |
if (leaf >= 0) { |
if (rec > rs[leaf].res.rec) |
if (vb.rec > rs[leaf].res.rec) |
rs[leaf].rhs = tree->len; |
rs[leaf].rhs = tree->len; |
else |
else |
rs[leaf].lhs = tree->len; |
rs[leaf].lhs = tree->len; |
|
|
recfree(struct rec *rec) |
recfree(struct rec *rec) |
{ |
{ |
|
|
|
free(rec->res.type); |
free(rec->res.file); |
free(rec->res.file); |
free(rec->res.cat); |
free(rec->res.cat); |
free(rec->res.title); |
free(rec->res.title); |
Line 579 recfree(struct rec *rec) |
|
Line 582 recfree(struct rec *rec) |
|
free(rec->matches); |
free(rec->matches); |
} |
} |
|
|
|
/* |
|
* Compile a list of straight-up terms. |
|
* The arguments are re-written into ~[[:<:]]term[[:>:]], or "term" |
|
* surrounded by word boundaries, then pumped through exprterm(). |
|
* Terms are case-insensitive. |
|
* This emulates whatis(1) behaviour. |
|
*/ |
struct expr * |
struct expr * |
|
termcomp(int argc, char *argv[], size_t *tt) |
|
{ |
|
char *buf; |
|
int pos; |
|
struct expr *e, *next; |
|
size_t sz; |
|
|
|
buf = NULL; |
|
e = NULL; |
|
*tt = 0; |
|
|
|
for (pos = argc - 1; pos >= 0; pos--) { |
|
sz = strlen(argv[pos]) + 18; |
|
buf = mandoc_realloc(buf, sz); |
|
strlcpy(buf, "Nm~[[:<:]]", sz); |
|
strlcat(buf, argv[pos], sz); |
|
strlcat(buf, "[[:>:]]", sz); |
|
if (NULL == (next = exprterm(buf, 0))) { |
|
free(buf); |
|
exprfree(e); |
|
return(NULL); |
|
} |
|
next->next = e; |
|
e = next; |
|
(*tt)++; |
|
} |
|
|
|
free(buf); |
|
return(e); |
|
} |
|
|
|
/* |
|
* Compile a sequence of logical expressions. |
|
* See apropos.1 for a grammar of this sequence. |
|
*/ |
|
struct expr * |
exprcomp(int argc, char *argv[], size_t *tt) |
exprcomp(int argc, char *argv[], size_t *tt) |
{ |
{ |
int pos, lvl; |
int pos, lvl; |
Line 650 exprexpr(int argc, char *argv[], int *pos, int *lvl, s |
|
Line 696 exprexpr(int argc, char *argv[], int *pos, int *lvl, s |
|
++(*pos); |
++(*pos); |
++(*lvl); |
++(*lvl); |
next = mandoc_calloc(1, sizeof(struct expr)); |
next = mandoc_calloc(1, sizeof(struct expr)); |
next->cs = 1; |
|
next->subexpr = exprexpr(argc, argv, pos, lvl, tt); |
next->subexpr = exprexpr(argc, argv, pos, lvl, tt); |
if (NULL == next->subexpr) { |
if (NULL == next->subexpr) { |
free(next); |
free(next); |
Line 701 exprterm(char *buf, int cs) |
|
Line 746 exprterm(char *buf, int cs) |
|
|
|
memset(&e, 0, sizeof(struct expr)); |
memset(&e, 0, sizeof(struct expr)); |
|
|
e.cs = cs; |
|
|
|
/* Choose regex or substring match. */ |
/* Choose regex or substring match. */ |
|
|
if (NULL == (e.v = strpbrk(buf, "=~"))) { |
if (NULL == (e.v = strpbrk(buf, "=~"))) { |
Line 729 exprterm(char *buf, int cs) |
|
Line 772 exprterm(char *buf, int cs) |
|
e.mask = TYPE_Nm | TYPE_Nd; |
e.mask = TYPE_Nm | TYPE_Nd; |
|
|
if (e.regex) { |
if (e.regex) { |
i = REG_EXTENDED | REG_NOSUB | cs ? 0 : REG_ICASE; |
i = REG_EXTENDED | REG_NOSUB | (cs ? 0 : REG_ICASE); |
if (regcomp(&e.re, e.v, i)) |
if (regcomp(&e.re, e.v, i)) |
return(NULL); |
return(NULL); |
} |
} |
Line 774 exprmark(const struct expr *p, const char *cp, |
|
Line 817 exprmark(const struct expr *p, const char *cp, |
|
if (p->regex) { |
if (p->regex) { |
if (regexec(&p->re, cp, 0, NULL, 0)) |
if (regexec(&p->re, cp, 0, NULL, 0)) |
continue; |
continue; |
} else if (p->cs) { |
} else if (NULL == strcasestr(cp, p->v)) |
if (NULL == strstr(cp, p->v)) |
continue; |
continue; |
|
} else { |
|
if (NULL == strcasestr(cp, p->v)) |
|
continue; |
|
} |
|
|
|
if (NULL == ms) |
if (NULL == ms) |
return(1); |
return(1); |