version 1.1, 2011/11/13 10:12:05 |
version 1.3, 2011/11/13 11:10:27 |
|
|
/* $Id$ */ |
/* $Id$ */ |
/* |
/* |
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> |
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> |
|
* Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
|
# include <db.h> |
# include <db.h> |
#endif |
#endif |
|
|
|
#include "mandocdb.h" |
#include "apropos_db.h" |
#include "apropos_db.h" |
#include "mandoc.h" |
#include "mandoc.h" |
|
|
enum match { |
|
MATCH_REGEX, |
|
MATCH_REGEXCASE, |
|
MATCH_STR, |
|
MATCH_STRCASE |
|
}; |
|
|
|
struct expr { |
struct expr { |
enum match match; |
int regex; |
int mask; |
int mask; |
char *v; |
char *v; |
regex_t re; |
regex_t re; |
|
|
}; |
}; |
|
|
static const struct type types[] = { |
static const struct type types[] = { |
{ TYPE_NAME, "name" }, |
{ TYPE_An, "An" }, |
{ TYPE_FUNCTION, "func" }, |
{ TYPE_Cd, "Cd" }, |
{ TYPE_UTILITY, "utility" }, |
{ TYPE_Er, "Er" }, |
{ TYPE_INCLUDES, "incl" }, |
{ TYPE_Ev, "Ev" }, |
{ TYPE_VARIABLE, "var" }, |
{ TYPE_Fn, "Fn" }, |
{ TYPE_STANDARD, "stand" }, |
{ TYPE_Fn, "Fo" }, |
{ TYPE_AUTHOR, "auth" }, |
{ TYPE_In, "In" }, |
{ TYPE_CONFIG, "conf" }, |
{ TYPE_Nd, "Nd" }, |
{ TYPE_DESC, "desc" }, |
{ TYPE_Nm, "Nm" }, |
{ TYPE_XREF, "xref" }, |
{ TYPE_Pa, "Pa" }, |
{ TYPE_PATH, "path" }, |
{ TYPE_St, "St" }, |
{ TYPE_ENV, "env" }, |
{ TYPE_Va, "Va" }, |
{ TYPE_ERR, "err" }, |
{ TYPE_Va, "Vt" }, |
{ INT_MAX, "all" }, |
{ TYPE_Xr, "Xr" }, |
|
{ INT_MAX, "any" }, |
{ 0, NULL } |
{ 0, NULL } |
}; |
}; |
|
|
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 exprexec(const struct expr *, char *); |
static int exprexec(const struct expr *, char *, 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 mchars *, struct rec *); |
const struct mchars *, struct rec *); |
|
|
memset(&info, 0, sizeof(BTREEINFO)); |
memset(&info, 0, sizeof(BTREEINFO)); |
info.flags = R_DUP; |
info.flags = R_DUP; |
|
|
db = dbopen("mandoc.db", O_RDONLY, 0, DB_BTREE, &info); |
db = dbopen(MANDOC_DB, O_RDONLY, 0, DB_BTREE, &info); |
if (NULL != db) |
if (NULL != db) |
return(db); |
return(db); |
|
|
Line 274 index_open(void) |
|
Line 270 index_open(void) |
|
{ |
{ |
DB *db; |
DB *db; |
|
|
db = dbopen("mandoc.index", O_RDONLY, 0, DB_RECNO, NULL); |
db = dbopen(MANDOC_IDX, O_RDONLY, 0, DB_RECNO, NULL); |
if (NULL != db) |
if (NULL != db) |
return(db); |
return(db); |
|
|
Line 366 apropos_search(const struct opts *opts, const struct e |
|
Line 362 apropos_search(const struct opts *opts, const struct e |
|
if ( ! btree_read(&key, mc, &buf)) |
if ( ! btree_read(&key, mc, &buf)) |
break; |
break; |
|
|
if ( ! exprexec(expr, buf)) |
if ( ! exprexec(expr, buf, *(int *)val.data)) |
continue; |
continue; |
|
|
memcpy(&rec, val.data + 4, sizeof(recno_t)); |
memcpy(&rec, val.data + 4, sizeof(recno_t)); |
|
|
} |
} |
|
|
struct expr * |
struct expr * |
exprcomp(int cs, char *argv[], int argc) |
exprcomp(int argc, char *argv[]) |
{ |
{ |
struct expr *p; |
struct expr *p; |
struct expr e; |
struct expr e; |
int i, pos, ch; |
char *key; |
|
int i, icase; |
|
|
pos = 0; |
if (0 >= argc) |
|
|
if (pos > argc) |
|
return(NULL); |
return(NULL); |
|
|
for (i = 0; 0 != types[i].mask; i++) |
/* |
if (0 == strcmp(types[i].name, argv[pos])) |
* Choose regex or substring match. |
break; |
*/ |
|
|
if (0 == (e.mask = types[i].mask)) |
if (NULL == (e.v = strpbrk(*argv, "=~"))) { |
return(NULL); |
e.regex = 0; |
|
e.v = *argv; |
|
} else { |
|
e.regex = '~' == *e.v; |
|
*e.v++ = '\0'; |
|
} |
|
|
if (++pos > argc--) |
/* |
return(NULL); |
* Determine the record types to search for. |
|
*/ |
|
|
if ('-' != *argv[pos]) |
icase = 0; |
e.match = cs ? MATCH_STRCASE : MATCH_STR; |
e.mask = 0; |
else if (0 == strcmp("-eq", argv[pos])) |
if (*argv < e.v) { |
e.match = cs ? MATCH_STRCASE : MATCH_STR; |
while (NULL != (key = strsep(argv, ","))) { |
else if (0 == strcmp("-ieq", argv[pos])) |
if ('i' == key[0] && '\0' == key[1]) { |
e.match = MATCH_STRCASE; |
icase = REG_ICASE; |
else if (0 == strcmp("-re", argv[pos])) |
continue; |
e.match = cs ? MATCH_REGEXCASE : MATCH_REGEX; |
} |
else if (0 == strcmp("-ire", argv[pos])) |
i = 0; |
e.match = MATCH_REGEXCASE; |
while (types[i].mask && |
else |
strcmp(types[i].name, key)) |
return(NULL); |
i++; |
|
e.mask |= types[i].mask; |
|
} |
|
} |
|
if (0 == e.mask) |
|
e.mask = TYPE_Nm | TYPE_Nd; |
|
|
if ('-' == *argv[pos]) |
if (e.regex && |
pos++; |
regcomp(&e.re, e.v, REG_EXTENDED | REG_NOSUB | icase)) |
|
|
if (pos > argc--) |
|
return(NULL); |
return(NULL); |
|
|
e.v = mandoc_strdup(argv[pos]); |
e.v = mandoc_strdup(e.v); |
|
|
if (MATCH_REGEX == e.match || MATCH_REGEXCASE == e.match) { |
|
ch = REG_EXTENDED | REG_NOSUB; |
|
if (MATCH_REGEXCASE == e.match) |
|
ch |= REG_ICASE; |
|
if (regcomp(&e.re, e.v, ch)) |
|
return(NULL); |
|
} |
|
|
|
p = mandoc_calloc(1, sizeof(struct expr)); |
p = mandoc_calloc(1, sizeof(struct expr)); |
memcpy(p, &e, sizeof(struct expr)); |
memcpy(p, &e, sizeof(struct expr)); |
return(p); |
return(p); |
Line 520 exprfree(struct expr *p) |
|
Line 516 exprfree(struct expr *p) |
|
if (NULL == p) |
if (NULL == p) |
return; |
return; |
|
|
if (MATCH_REGEX == p->match) |
if (p->regex) |
regfree(&p->re); |
regfree(&p->re); |
|
|
free(p->v); |
free(p->v); |
Line 528 exprfree(struct expr *p) |
|
Line 524 exprfree(struct expr *p) |
|
} |
} |
|
|
static int |
static int |
exprexec(const struct expr *p, char *cp) |
exprexec(const struct expr *p, char *cp, int mask) |
{ |
{ |
|
|
if (MATCH_STR == p->match) |
if ( ! (mask & p->mask)) |
return(0 == strcmp(p->v, cp)); |
return(0); |
else if (MATCH_STRCASE == p->match) |
|
return(0 == strcasecmp(p->v, cp)); |
|
|
|
assert(MATCH_REGEX == p->match); |
if (p->regex) |
return(0 == regexec(&p->re, cp, 0, NULL, 0)); |
return(0 == regexec(&p->re, cp, 0, NULL, 0)); |
|
else |
|
return(NULL != strcasestr(cp, p->v)); |
} |
} |