version 1.5, 2011/11/17 14:52:32 |
version 1.6, 2011/11/17 15:38:27 |
|
|
#include <fcntl.h> |
#include <fcntl.h> |
#include <regex.h> |
#include <regex.h> |
#include <stdarg.h> |
#include <stdarg.h> |
|
#include <stdint.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
struct expr { |
struct expr { |
int regex; |
int regex; |
int index; |
int index; |
int mask; |
uint64_t mask; |
int and; |
int and; |
char *v; |
char *v; |
regex_t re; |
regex_t re; |
|
|
}; |
}; |
|
|
struct type { |
struct type { |
int mask; |
uint64_t mask; |
const char *name; |
const char *name; |
}; |
}; |
|
|
static const struct type types[] = { |
static const struct type types[] = { |
{ TYPE_An, "An" }, |
{ TYPE_An, "An" }, |
|
{ TYPE_Ar, "Ar" }, |
|
{ TYPE_At, "At" }, |
|
{ TYPE_Bsx, "Bsx" }, |
|
{ TYPE_Bx, "Bx" }, |
{ TYPE_Cd, "Cd" }, |
{ TYPE_Cd, "Cd" }, |
|
{ TYPE_Cm, "Cm" }, |
|
{ TYPE_Dv, "Dv" }, |
|
{ TYPE_Dx, "Dx" }, |
|
{ TYPE_Em, "Em" }, |
{ TYPE_Er, "Er" }, |
{ TYPE_Er, "Er" }, |
{ TYPE_Ev, "Ev" }, |
{ TYPE_Ev, "Ev" }, |
|
{ TYPE_Fa, "Fa" }, |
|
{ TYPE_Fl, "Fl" }, |
{ TYPE_Fn, "Fn" }, |
{ TYPE_Fn, "Fn" }, |
{ TYPE_Fn, "Fo" }, |
{ TYPE_Fn, "Fo" }, |
|
{ TYPE_Ft, "Ft" }, |
|
{ TYPE_Fx, "Fx" }, |
|
{ TYPE_Ic, "Ic" }, |
{ TYPE_In, "In" }, |
{ TYPE_In, "In" }, |
|
{ TYPE_Lb, "Lb" }, |
|
{ TYPE_Li, "Li" }, |
|
{ TYPE_Lk, "Lk" }, |
|
{ TYPE_Ms, "Ms" }, |
|
{ TYPE_Mt, "Mt" }, |
{ TYPE_Nd, "Nd" }, |
{ TYPE_Nd, "Nd" }, |
{ TYPE_Nm, "Nm" }, |
{ TYPE_Nm, "Nm" }, |
|
{ TYPE_Nx, "Nx" }, |
|
{ TYPE_Ox, "Ox" }, |
{ TYPE_Pa, "Pa" }, |
{ TYPE_Pa, "Pa" }, |
|
{ TYPE_Rs, "Rs" }, |
|
{ TYPE_Sh, "Sh" }, |
|
{ TYPE_Ss, "Ss" }, |
{ TYPE_St, "St" }, |
{ TYPE_St, "St" }, |
|
{ TYPE_Sy, "Sy" }, |
|
{ TYPE_Tn, "Tn" }, |
{ TYPE_Va, "Va" }, |
{ TYPE_Va, "Va" }, |
{ TYPE_Va, "Vt" }, |
{ TYPE_Va, "Vt" }, |
{ TYPE_Xr, "Xr" }, |
{ TYPE_Xr, "Xr" }, |
|
|
|
|
static DB *btree_open(void); |
static DB *btree_open(void); |
static int btree_read(const DBT *, const struct mchars *, char **); |
static int btree_read(const DBT *, const struct mchars *, char **); |
static int exprexecpre(const struct expr *, const char *, int); |
static int exprexecpre(const struct expr *, const char *, uint64_t); |
static void exprexecpost(const struct expr *, |
static void exprexecpost(const struct expr *, |
const char *, int, int *, size_t); |
const char *, uint64_t, int *, size_t); |
static struct expr *exprterm(char *, int, int); |
static struct expr *exprterm(char *, int, int); |
static DB *index_open(void); |
static DB *index_open(void); |
static int index_read(const DBT *, const DBT *, |
static int index_read(const DBT *, const DBT *, |
|
|
const struct expr *expr, size_t terms, |
const struct expr *expr, size_t terms, |
struct mchars *mc) |
struct mchars *mc) |
{ |
{ |
int root, leaf, mask; |
int root, leaf; |
DBT key, val; |
DBT key, val; |
DB *btree, *idx; |
DB *btree, *idx; |
int ch; |
int ch; |
|
|
recno_t rec; |
recno_t rec; |
struct rec *recs; |
struct rec *recs; |
struct rec srec; |
struct rec srec; |
|
struct db_val *vbuf; |
|
|
root = -1; |
root = -1; |
leaf = -1; |
leaf = -1; |
|
|
* The key must have something in it, and the value must |
* The key must have something in it, and the value must |
* have the correct tags/recno mix. |
* have the correct tags/recno mix. |
*/ |
*/ |
if (key.size < 2 || 8 != val.size) |
if (key.size < 2 || sizeof(struct db_val) != val.size) |
break; |
break; |
if ( ! btree_read(&key, mc, &buf)) |
if ( ! btree_read(&key, mc, &buf)) |
break; |
break; |
|
|
mask = *(int *)val.data; |
|
|
|
/* |
/* |
* 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 ( ! exprexecpre(expr, buf, mask)) |
vbuf = val.data; |
|
if ( ! exprexecpre(expr, buf, vbuf->mask)) |
continue; |
continue; |
|
rec = vbuf->rec; |
|
|
memcpy(&rec, val.data + 4, sizeof(recno_t)); |
|
|
|
/* |
/* |
* O(log n) scan for prior records. Since a record |
* O(log n) scan for prior records. Since a record |
* number is unbounded, this has decent performance over |
* number is unbounded, this has decent performance over |
|
|
if (leaf >= 0 && recs[leaf].rec == rec) { |
if (leaf >= 0 && recs[leaf].rec == rec) { |
if (0 == recs[leaf].matches[0]) |
if (0 == recs[leaf].matches[0]) |
exprexecpost |
exprexecpost |
(expr, buf, mask, |
(expr, buf, vbuf->mask, |
recs[leaf].matches, terms); |
recs[leaf].matches, terms); |
continue; |
continue; |
} |
} |
|
|
mandoc_calloc(terms + 1, sizeof(int)); |
mandoc_calloc(terms + 1, sizeof(int)); |
|
|
exprexecpost |
exprexecpost |
(expr, buf, mask, |
(expr, buf, vbuf->mask, |
recs[tree->len].matches, terms); |
recs[tree->len].matches, terms); |
|
|
/* Append to our tree. */ |
/* Append to our tree. */ |
|
|
* Return 1 if any expression evaluates to true, else 0. |
* Return 1 if any expression evaluates to true, else 0. |
*/ |
*/ |
static int |
static int |
exprexecpre(const struct expr *p, const char *cp, int mask) |
exprexecpre(const struct expr *p, const char *cp, uint64_t mask) |
{ |
{ |
|
|
for ( ; NULL != p; p = p->next) { |
for ( ; NULL != p; p = p->next) { |
|
|
*/ |
*/ |
static void |
static void |
exprexecpost(const struct expr *e, const char *cp, |
exprexecpost(const struct expr *e, const char *cp, |
int mask, int *matches, size_t matchsz) |
uint64_t mask, int *matches, size_t matchsz) |
{ |
{ |
const struct expr *p; |
const struct expr *p; |
int match; |
int match; |