From 52e32329c935cd5b17f86511fb6d80879b597e60 Mon Sep 17 00:00:00 2001 From: Kristaps Dzonsons Date: Wed, 9 Nov 2011 22:05:56 +0000 Subject: Make apropos's lookup use a find(1)-like expression. I'll write more on this when it completes; this is to keep it in-tree. Right now this uses prefix notation. Ignore it. I'll make this into infix notation real soon. The goal of this (exprcomp and exprexec) is to have arbitrary logical expressions. --- apropos.c | 71 +++++++-------------------------- apropos.h | 13 +++--- cgi.c | 12 +++++- db.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 146 insertions(+), 84 deletions(-) diff --git a/apropos.c b/apropos.c index 8d34cd58..33ff1d2c 100644 --- a/apropos.c +++ b/apropos.c @@ -24,29 +24,6 @@ #include "apropos.h" #include "mandoc.h" -struct type { - int mask; - const char *name; /* command-line type name */ -}; - -static const struct type types[] = { - { TYPE_NAME, "name" }, - { TYPE_FUNCTION, "func" }, - { TYPE_UTILITY, "utility" }, - { TYPE_INCLUDES, "incl" }, - { TYPE_VARIABLE, "var" }, - { TYPE_STANDARD, "stand" }, - { TYPE_AUTHOR, "auth" }, - { TYPE_CONFIG, "conf" }, - { TYPE_DESC, "desc" }, - { TYPE_XREF, "xref" }, - { TYPE_PATH, "path" }, - { TYPE_ENV, "env" }, - { TYPE_ERR, "err" }, - { INT_MAX, "all" }, - { 0, NULL } -}; - static int cmp(const void *, const void *); static void list(struct rec *, size_t, void *); static void usage(void); @@ -56,23 +33,23 @@ static char *progname; int main(int argc, char *argv[]) { - int ch, i; - char *q, *v; + int ch, cs; struct opts opts; + struct expr *e; extern int optind; extern char *optarg; memset(&opts, 0, sizeof(struct opts)); - q = NULL; - progname = strrchr(argv[0], '/'); if (progname == NULL) progname = argv[0]; else ++progname; - while (-1 != (ch = getopt(argc, argv, "S:s:It:"))) + cs = 0; + + while (-1 != (ch = getopt(argc, argv, "S:s:I"))) switch (ch) { case ('S'): opts.arch = optarg; @@ -81,26 +58,8 @@ main(int argc, char *argv[]) opts.cat = optarg; break; case ('I'): - opts.flags |= OPTS_INSENS; + cs = 1; break; - case ('t'): - while (NULL != (v = strsep(&optarg, ","))) { - if ('\0' == *v) - continue; - for (i = 0; types[i].mask; i++) { - if (strcmp(types[i].name, v)) - continue; - break; - } - if (0 == types[i].mask) - break; - opts.types |= types[i].mask; - } - if (NULL == v) - break; - - fprintf(stderr, "%s: Bad type\n", v); - return(EXIT_FAILURE); default: usage(); return(EXIT_FAILURE); @@ -109,14 +68,13 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if (0 == argc || '\0' == **argv) { - usage(); + if (0 == argc) return(EXIT_SUCCESS); - } else - q = *argv; - if (0 == opts.types) - opts.types = TYPE_NAME | TYPE_DESC; + if (NULL == (e = exprcomp(cs, argv, argc))) { + fprintf(stderr, "Bad expression\n"); + return(EXIT_FAILURE); + } /* * Configure databases. @@ -125,7 +83,8 @@ main(int argc, char *argv[]) * The index database is a recno. */ - apropos_search(&opts, q, NULL, list); + apropos_search(&opts, e, NULL, list); + exprfree(e); return(EXIT_SUCCESS); } @@ -161,6 +120,6 @@ usage(void) "[-I] " "[-S arch] " "[-s section] " - "[-t type[,...]] " - "key\n", progname); + "EXPR\n", + progname); } diff --git a/apropos.h b/apropos.h index 0dc26e5f..a2c90239 100644 --- a/apropos.h +++ b/apropos.h @@ -53,15 +53,18 @@ struct rec { struct opts { const char *arch; /* restrict to architecture */ const char *cat; /* restrict to manual section */ - int types; /* only types in bitmask */ - int flags; -#define OPTS_INSENS (0x01) /* case-insensitive match */ }; __BEGIN_DECLS -void apropos_search(const struct opts *, const char *, - void *, void (*)(struct rec *, size_t, void *)); +struct expr; + +void apropos_search(const struct opts *, + const struct expr *, void *, + void (*)(struct rec *, size_t, void *)); + +struct expr *exprcomp(int, char *[], int); +void exprfree(struct expr *); __END_DECLS diff --git a/cgi.c b/cgi.c index c41b7866..09128c77 100644 --- a/cgi.c +++ b/cgi.c @@ -47,13 +47,17 @@ struct req { enum page page; }; +#if 0 static void html_printtext(const char *); +#endif static int kval_decode(char *); static void kval_parse(struct kval **, size_t *, char *); static void kval_free(struct kval *, size_t); static void pg_index(const struct req *, char *); static void pg_search(const struct req *, char *); +#if 0 static void pg_searchres(struct rec *, size_t, void *); +#endif static const char * const pages[PAGE__MAX] = { "index", /* PAGE_INDEX */ @@ -64,6 +68,7 @@ static const char * const medias[MEDIA__MAX] = { "html", /* MEDIA_HTML */ }; +#if 0 static void html_printtext(const char *p) { @@ -88,6 +93,7 @@ html_printtext(const char *p) break; } } +#endif static void kval_free(struct kval *p, size_t sz) @@ -205,6 +211,7 @@ pg_index(const struct req *req, char *path) } +#if 0 static void pg_searchres(struct rec *recs, size_t sz, void *arg) { @@ -223,6 +230,7 @@ pg_searchres(struct rec *recs, size_t sz, void *arg) puts(")"); } } +#endif static void pg_search(const struct req *req, char *path) @@ -238,8 +246,8 @@ pg_search(const struct req *req, char *path) return; memset(&opt, 0, sizeof(struct opts)); - opt.types = TYPE_NAME | TYPE_DESC; - apropos_search(&opt, req->fields[i].val, NULL, pg_searchres); + /*opt.types = TYPE_NAME | TYPE_DESC; + apropos_search(&opt, req->fields[i].val, NULL, pg_searchres);*/ } int diff --git a/db.c b/db.c index de2c515e..e482243d 100644 --- a/db.c +++ b/db.c @@ -30,8 +30,46 @@ #include "apropos.h" #include "mandoc.h" +enum match { + MATCH_REGEX, + MATCH_REGEXCASE, + MATCH_STR, + MATCH_STRCASE +}; + +struct expr { + enum match match; + int mask; + char *v; + regex_t re; +}; + +struct type { + int mask; + const char *name; +}; + +static const struct type types[] = { + { TYPE_NAME, "name" }, + { TYPE_FUNCTION, "func" }, + { TYPE_UTILITY, "utility" }, + { TYPE_INCLUDES, "incl" }, + { TYPE_VARIABLE, "var" }, + { TYPE_STANDARD, "stand" }, + { TYPE_AUTHOR, "auth" }, + { TYPE_CONFIG, "conf" }, + { TYPE_DESC, "desc" }, + { TYPE_XREF, "xref" }, + { TYPE_PATH, "path" }, + { TYPE_ENV, "env" }, + { TYPE_ERR, "err" }, + { INT_MAX, "all" }, + { 0, NULL } +}; + static DB *btree_open(void); static int btree_read(const DBT *, const struct mchars *, char **); +static int exprexec(const struct expr *, char *); static DB *index_open(void); static int index_read(const DBT *, const DBT *, const struct mchars *, struct rec *); @@ -277,16 +315,15 @@ index_read(const DBT *key, const DBT *val, } /* - * Search the mandocdb database for the regular expression "q". + * Search the mandocdb database for the expression "expr". * Filter out by "opts". * Call "res" with the results, which may be zero. */ void -apropos_search(const struct opts *opts, const char *q, void *arg, - void (*res)(struct rec *, size_t, void *)) +apropos_search(const struct opts *opts, const struct expr *expr, + void *arg, void (*res)(struct rec *, size_t, void *)) { int i, len, root, leaf; - regex_t reg; DBT key, val; DB *btree, *idx; struct mchars *mc; @@ -307,19 +344,8 @@ apropos_search(const struct opts *opts, const char *q, void *arg, memset(&srec, 0, sizeof(struct rec)); - if (NULL != q && '\0' == *q) - q = NULL; - - ch = REG_EXTENDED | REG_NOSUB | - (OPTS_INSENS & opts->flags ? REG_ICASE : 0); - /* XXX: error out with bad regexp? */ - if (NULL == q || regcomp(®, q, ch)) { - (*res)(NULL, 0, arg); - return; - } - mc = mchars_alloc(); /* XXX: return fact that we've errored? */ @@ -337,13 +363,10 @@ apropos_search(const struct opts *opts, const char *q, void *arg, */ if (key.size < 2 || 8 != val.size) break; - - if ( ! (*(int32_t *)val.data & opts->types)) - continue; - if ( ! btree_read(&key, mc, &buf)) break; - if (regexec(®, buf, 0, NULL, 0)) + + if ( ! exprexec(expr, buf)) continue; memcpy(&rec, val.data + 4, sizeof(recno_t)); @@ -432,5 +455,74 @@ out: free(buf); free(recs); - regfree(®); +} + +struct expr * +exprcomp(int cs, char *argv[], int argc) +{ + struct expr *p; + struct expr e; + int i, ch; + + if (3 != argc) + return(NULL); + + if (0 == strcmp("-eq", argv[0])) + e.match = cs ? MATCH_STRCASE : MATCH_STR; + else if (0 == strcmp("-ieq", argv[0])) + e.match = MATCH_STRCASE; + else if (0 == strcmp("-re", argv[0])) + e.match = cs ? MATCH_REGEXCASE : MATCH_REGEX; + else if (0 == strcmp("-ire", argv[0])) + e.match = MATCH_REGEXCASE; + else + return(NULL); + + for (i = 0; 0 != types[i].mask; i++) + if (0 == strcmp(types[i].name, argv[1])) + break; + + if (0 == (e.mask = types[i].mask)) + return(NULL); + + e.v = mandoc_strdup(argv[2]); + + 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)); + memcpy(p, &e, sizeof(struct expr)); + return(p); +} + +void +exprfree(struct expr *p) +{ + + if (NULL == p) + return; + + if (MATCH_REGEX == p->match) + regfree(&p->re); + + free(p->v); + free(p); +} + +static int +exprexec(const struct expr *p, char *cp) +{ + + if (MATCH_STR == p->match) + return(0 == strcmp(p->v, cp)); + else if (MATCH_STRCASE == p->match) + return(0 == strcasecmp(p->v, cp)); + + assert(MATCH_REGEX == p->match); + return(0 == regexec(&p->re, cp, 0, NULL, 0)); } -- cgit