=================================================================== RCS file: /cvs/mandoc/mansearch.c,v retrieving revision 1.22 retrieving revision 1.28 diff -u -p -r1.22 -r1.28 --- mandoc/mansearch.c 2014/03/17 16:31:44 1.22 +++ mandoc/mansearch.c 2014/04/11 15:46:52 1.28 @@ -1,4 +1,4 @@ -/* $Id: mansearch.c,v 1.22 2014/03/17 16:31:44 schwarze Exp $ */ +/* $Id: mansearch.c,v 1.28 2014/04/11 15:46:52 schwarze Exp $ */ /* * Copyright (c) 2012 Kristaps Dzonsons * Copyright (c) 2013, 2014 Ingo Schwarze @@ -19,6 +19,7 @@ #include "config.h" #endif +#include #include #include #include @@ -39,6 +40,7 @@ #include #include "mandoc.h" +#include "mandoc_aux.h" #include "manpath.h" #include "mansearch.h" @@ -73,6 +75,7 @@ struct expr { struct match { uint64_t id; /* identifier in database */ + char *desc; /* manual page description */ int form; /* 0 == catpage */ }; @@ -99,6 +102,53 @@ static void sql_regexp(sqlite3_context *context, static char *sql_statement(const struct expr *); int +mansearch_setup(int start) +{ + static void *pagecache; + int c; + +#define PC_PAGESIZE 1280 +#define PC_NUMPAGES 256 + + if (start) { + if (NULL != pagecache) { + fprintf(stderr, "pagecache already enabled\n"); + return((int)MANDOCLEVEL_BADARG); + } + + pagecache = mmap(NULL, PC_PAGESIZE * PC_NUMPAGES, + PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); + + if (MAP_FAILED == pagecache) { + perror("mmap"); + pagecache = NULL; + return((int)MANDOCLEVEL_SYSERR); + } + + c = sqlite3_config(SQLITE_CONFIG_PAGECACHE, + pagecache, PC_PAGESIZE, PC_NUMPAGES); + + if (SQLITE_OK == c) + return((int)MANDOCLEVEL_OK); + + fprintf(stderr, "pagecache: %s\n", sqlite3_errstr(c)); + + } else if (NULL == pagecache) { + fprintf(stderr, "pagecache missing\n"); + return((int)MANDOCLEVEL_BADARG); + } + + if (-1 == munmap(pagecache, PC_PAGESIZE * PC_NUMPAGES)) { + perror("munmap"); + pagecache = NULL; + return((int)MANDOCLEVEL_SYSERR); + } + + pagecache = NULL; + return((int)MANDOCLEVEL_OK); +} + +int mansearch(const struct mansearch *search, const struct manpaths *paths, int argc, char *argv[], @@ -219,7 +269,8 @@ mansearch(const struct mansearch *search, SQL_BIND_BLOB(db, s, j, ep->regexp); } else SQL_BIND_TEXT(db, s, j, ep->substr); - SQL_BIND_INT64(db, s, j, ep->bits); + if (0 == ((TYPE_Nd | TYPE_Nm) & ep->bits)) + SQL_BIND_INT64(db, s, j, ep->bits); } memset(&htab, 0, sizeof(struct ohash)); @@ -234,9 +285,9 @@ mansearch(const struct mansearch *search, * distribution of buckets in the table. */ while (SQLITE_ROW == (c = sqlite3_step(s))) { - id = sqlite3_column_int64(s, 1); + id = sqlite3_column_int64(s, 2); idx = ohash_lookup_memory - (&htab, (char *)&id, + (&htab, (char *)&id, sizeof(uint64_t), (uint32_t)id); if (NULL != ohash_find(&htab, idx)) @@ -244,7 +295,10 @@ mansearch(const struct mansearch *search, mp = mandoc_calloc(1, sizeof(struct match)); mp->id = id; - mp->form = sqlite3_column_int(s, 0); + mp->form = sqlite3_column_int(s, 1); + if (TYPE_Nd == outbit) + mp->desc = mandoc_strdup( + sqlite3_column_text(s, 0)); ohash_insert(&htab, idx, mp); } @@ -278,7 +332,8 @@ mansearch(const struct mansearch *search, mpage->form = mp->form; buildnames(mpage, db, s, mp->id, paths->paths[i], mp->form); - mpage->output = outbit ? + mpage->output = TYPE_Nd & outbit ? + mp->desc : outbit ? buildoutput(db, s2, mp->id, outbit) : NULL; free(mp); @@ -309,6 +364,7 @@ buildnames(struct manpage *mpage, sqlite3 *db, sqlite3 size_t i; int c; + mpage->file = NULL; mpage->names = NULL; prevsec = prevarch = NULL; i = 1; @@ -337,11 +393,8 @@ buildnames(struct manpage *mpage, sqlite3 *db, sqlite3 (strcmp(sec, prevsec) || strcmp(arch, prevarch))) { sep2 = '\0' == *prevarch ? "" : "/"; - if (-1 == asprintf(&newnames, "%s(%s%s%s)", - oldnames, prevsec, sep2, prevarch)) { - perror(0); - exit((int)MANDOCLEVEL_SYSERR); - } + mandoc_asprintf(&newnames, "%s(%s%s%s)", + oldnames, prevsec, sep2, prevarch); free(mpage->names); oldnames = mpage->names = newnames; free(prevsec); @@ -358,11 +411,8 @@ buildnames(struct manpage *mpage, sqlite3 *db, sqlite3 /* Append the new name. */ - if (-1 == asprintf(&newnames, "%s%s%s", - oldnames, sep1, name)) { - perror(0); - exit((int)MANDOCLEVEL_SYSERR); - } + mandoc_asprintf(&newnames, "%s%s%s", + oldnames, sep1, name); free(mpage->names); mpage->names = newnames; @@ -379,11 +429,8 @@ buildnames(struct manpage *mpage, sqlite3 *db, sqlite3 fsec = "0"; } sep2 = '\0' == *arch ? "" : "/"; - if (-1 == asprintf(&mpage->file, "%s/%s%s%s%s/%s.%s", - path, sep1, sec, sep2, arch, name, fsec)) { - perror(0); - exit((int)MANDOCLEVEL_SYSERR); - } + mandoc_asprintf(&mpage->file, "%s/%s%s%s%s/%s.%s", + path, sep1, sec, sep2, arch, name, fsec); } if (SQLITE_DONE != c) fprintf(stderr, "%s\n", sqlite3_errmsg(db)); @@ -393,11 +440,8 @@ buildnames(struct manpage *mpage, sqlite3 *db, sqlite3 if (NULL != prevsec) { sep2 = '\0' == *prevarch ? "" : "/"; - if (-1 == asprintf(&newnames, "%s(%s%s%s)", - mpage->names, prevsec, sep2, prevarch)) { - perror(0); - exit((int)MANDOCLEVEL_SYSERR); - } + mandoc_asprintf(&newnames, "%s(%s%s%s)", + mpage->names, prevsec, sep2, prevarch); free(mpage->names); mpage->names = newnames; free(prevsec); @@ -426,11 +470,8 @@ buildoutput(sqlite3 *db, sqlite3_stmt *s, uint64_t id, sep1 = " # "; } data = sqlite3_column_text(s, 1); - if (-1 == asprintf(&newoutput, "%s%s%s", - oldoutput, sep1, data)) { - perror(0); - exit((int)MANDOCLEVEL_SYSERR); - } + mandoc_asprintf(&newoutput, "%s%s%s", + oldoutput, sep1, data); free(output); output = newoutput; } @@ -506,11 +547,22 @@ sql_statement(const struct expr *e) sql_append(&sql, &sz, " OR ", 1); if (e->open) sql_append(&sql, &sz, "(", e->open); - sql_append(&sql, &sz, NULL == e->substr ? - "id IN (SELECT pageid FROM keys " - "WHERE key REGEXP ? AND bits & ?)" : - "id IN (SELECT pageid FROM keys " - "WHERE key MATCH ? AND bits & ?)", 1); + sql_append(&sql, &sz, + TYPE_Nd & e->bits + ? (NULL == e->substr + ? "desc REGEXP ?" + : "desc MATCH ?") + : TYPE_Nm == e->bits + ? (NULL == e->substr + ? "id IN (SELECT pageid FROM names " + "WHERE name REGEXP ?)" + : "id IN (SELECT pageid FROM names " + "WHERE name MATCH ?)") + : (NULL == e->substr + ? "id IN (SELECT pageid FROM keys " + "WHERE key REGEXP ? AND bits & ?)" + : "id IN (SELECT pageid FROM keys " + "WHERE key MATCH ? AND bits & ?)"), 1); if (e->close) sql_append(&sql, &sz, ")", e->close); needop = 1; @@ -527,8 +579,9 @@ sql_statement(const struct expr *e) static struct expr * exprcomp(const struct mansearch *search, int argc, char *argv[]) { + uint64_t mask; int i, toopen, logic, igncase, toclose; - struct expr *first, *next, *cur; + struct expr *first, *prev, *cur, *next; first = cur = NULL; logic = igncase = toclose = 0; @@ -567,13 +620,35 @@ exprcomp(const struct mansearch *search, int argc, cha next = exprterm(search, argv[i], !igncase); if (NULL == next) goto fail; - next->open = toopen; - next->and = (1 == logic); - if (NULL != first) { + if (NULL == first) + first = next; + else cur->next = next; - cur = next; - } else - cur = first = next; + prev = cur = next; + + /* + * Searching for descriptions must be split out + * because they are stored in the mpages table, + * not in the keys table. + */ + + for (mask = TYPE_Nm; mask <= TYPE_Nd; mask <<= 1) { + if (mask & cur->bits && ~mask & cur->bits) { + next = mandoc_calloc(1, + sizeof(struct expr)); + memcpy(next, cur, sizeof(struct expr)); + prev->open = 1; + cur->bits = mask; + cur->next = next; + cur = next; + cur->bits &= ~mask; + } + } + prev->and = (1 == logic); + prev->open += toopen; + if (cur != prev) + cur->close = 1; + toopen = logic = igncase = 0; } if (toopen || logic || igncase || toclose) @@ -602,10 +677,7 @@ exprspec(struct expr *cur, uint64_t key, const char *v if (NULL == value) return(cur); - if (-1 == asprintf(&cp, format, value)) { - perror(0); - exit((int)MANDOCLEVEL_SYSERR); - } + mandoc_asprintf(&cp, format, value); cur->next = mandoc_calloc(1, sizeof(struct expr)); cur = cur->next; cur->and = 1;