=================================================================== RCS file: /cvs/mandoc/mansearch.c,v retrieving revision 1.25 retrieving revision 1.30 diff -u -p -r1.25 -r1.30 --- mandoc/mansearch.c 2014/03/28 19:17:12 1.25 +++ mandoc/mansearch.c 2014/04/15 23:51:39 1.30 @@ -1,4 +1,4 @@ -/* $Id: mansearch.c,v 1.25 2014/03/28 19:17:12 schwarze Exp $ */ +/* $Id: mansearch.c,v 1.30 2014/04/15 23:51:39 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 @@ -74,6 +75,7 @@ struct expr { struct match { uint64_t id; /* identifier in database */ + char *desc; /* manual page description */ int form; /* 0 == catpage */ }; @@ -100,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[], @@ -161,7 +210,7 @@ mansearch(const struct mansearch *search, */ if (NULL == getcwd(buf, PATH_MAX)) { - perror(NULL); + perror("getcwd"); goto out; } else if (-1 == (fd = open(buf, O_RDONLY, 0))) { perror(buf); @@ -220,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)); @@ -235,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)) @@ -245,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); } @@ -279,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); @@ -293,9 +347,12 @@ mansearch(const struct mansearch *search, } rc = 1; out: - exprfree(e); - if (-1 != fd) + if (-1 != fd) { + if (-1 == fchdir(fd)) + perror(buf); close(fd); + } + exprfree(e); free(sql); *sz = cur; return(rc); @@ -493,11 +550,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; @@ -514,8 +582,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; @@ -554,13 +623,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)