version 1.106, 2014/01/06 15:32:47 |
version 1.116, 2014/03/19 21:51:20 |
|
|
#endif |
#endif |
|
|
#include <sys/stat.h> |
#include <sys/stat.h> |
|
#include <sys/wait.h> |
|
|
#include <assert.h> |
#include <assert.h> |
#include <ctype.h> |
#include <ctype.h> |
|
|
#include "manpath.h" |
#include "manpath.h" |
#include "mansearch.h" |
#include "mansearch.h" |
|
|
|
extern int mansearch_keymax; |
|
extern const char *const mansearch_keynames[]; |
|
|
#define SQL_EXEC(_v) \ |
#define SQL_EXEC(_v) \ |
if (SQLITE_OK != sqlite3_exec(db, (_v), NULL, NULL, NULL)) \ |
if (SQLITE_OK != sqlite3_exec(db, (_v), NULL, NULL, NULL)) \ |
fprintf(stderr, "%s\n", sqlite3_errmsg(db)) |
fprintf(stderr, "%s\n", sqlite3_errmsg(db)) |
Line 154 static int parse_mdoc_Nd(struct mpage *, const struct |
|
Line 158 static int parse_mdoc_Nd(struct mpage *, const struct |
|
static int parse_mdoc_Nm(struct mpage *, const struct mdoc_node *); |
static int parse_mdoc_Nm(struct mpage *, const struct mdoc_node *); |
static int parse_mdoc_Sh(struct mpage *, const struct mdoc_node *); |
static int parse_mdoc_Sh(struct mpage *, const struct mdoc_node *); |
static int parse_mdoc_Xr(struct mpage *, const struct mdoc_node *); |
static int parse_mdoc_Xr(struct mpage *, const struct mdoc_node *); |
static void putkey(const struct mpage *, |
static void putkey(const struct mpage *, char *, uint64_t); |
const char *, uint64_t); |
|
static void putkeys(const struct mpage *, |
static void putkeys(const struct mpage *, |
const char *, size_t, uint64_t); |
const char *, size_t, uint64_t); |
static void putmdockey(const struct mpage *, |
static void putmdockey(const struct mpage *, |
Line 166 static int set_basedir(const char *); |
|
Line 169 static int set_basedir(const char *); |
|
static int treescan(void); |
static int treescan(void); |
static size_t utf8(unsigned int, char [7]); |
static size_t utf8(unsigned int, char [7]); |
|
|
|
static char tempfilename[32]; |
static char *progname; |
static char *progname; |
static int nodb; /* no database changes */ |
static int nodb; /* no database changes */ |
static int quick; /* abort the parse early */ |
static int mparse_options; /* abort the parse early */ |
static int use_all; /* use all found files */ |
static int use_all; /* use all found files */ |
static int verb; /* print what we're doing */ |
static int verb; /* print what we're doing */ |
static int warnings; /* warn about crap */ |
static int warnings; /* warn about crap */ |
Line 347 main(int argc, char *argv[]) |
|
Line 351 main(int argc, char *argv[]) |
|
|
|
path_arg = NULL; |
path_arg = NULL; |
op = OP_DEFAULT; |
op = OP_DEFAULT; |
|
mparse_options = MPARSE_SO; |
|
|
while (-1 != (ch = getopt(argc, argv, "aC:d:nQT:tu:vW"))) |
while (-1 != (ch = getopt(argc, argv, "aC:d:nQT:tu:vW"))) |
switch (ch) { |
switch (ch) { |
Line 367 main(int argc, char *argv[]) |
|
Line 372 main(int argc, char *argv[]) |
|
nodb = 1; |
nodb = 1; |
break; |
break; |
case ('Q'): |
case ('Q'): |
quick = 1; |
mparse_options |= MPARSE_QUICK; |
break; |
break; |
case ('T'): |
case ('T'): |
if (strcmp(optarg, "utf8")) { |
if (strcmp(optarg, "utf8")) { |
Line 407 main(int argc, char *argv[]) |
|
Line 412 main(int argc, char *argv[]) |
|
} |
} |
|
|
exitcode = (int)MANDOCLEVEL_OK; |
exitcode = (int)MANDOCLEVEL_OK; |
mp = mparse_alloc(MPARSE_AUTO, |
mp = mparse_alloc(mparse_options, MANDOCLEVEL_FATAL, NULL, NULL); |
MANDOCLEVEL_FATAL, NULL, NULL, quick); |
|
mc = mchars_alloc(); |
mc = mchars_alloc(); |
|
|
ohash_init(&mpages, 6, &mpages_info); |
ohash_init(&mpages, 6, &mpages_info); |
Line 954 mlink_check(struct mpage *mpage, struct mlink *mlink) |
|
Line 958 mlink_check(struct mpage *mpage, struct mlink *mlink) |
|
static void |
static void |
mpages_merge(struct mchars *mc, struct mparse *mp) |
mpages_merge(struct mchars *mc, struct mparse *mp) |
{ |
{ |
|
char any[] = "any"; |
struct ohash_info str_info; |
struct ohash_info str_info; |
struct mpage *mpage; |
struct mpage *mpage; |
struct mlink *mlink; |
struct mlink *mlink; |
struct mdoc *mdoc; |
struct mdoc *mdoc; |
struct man *man; |
struct man *man; |
const char *cp; |
char *cp; |
int match; |
int match; |
unsigned int pslot; |
unsigned int pslot; |
enum mandoclevel lvl; |
enum mandoclevel lvl; |
Line 969 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
Line 974 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
str_info.hfree = hash_free; |
str_info.hfree = hash_free; |
str_info.key_offset = offsetof(struct str, key); |
str_info.key_offset = offsetof(struct str, key); |
|
|
|
if (0 == nodb) |
|
SQL_EXEC("BEGIN TRANSACTION"); |
|
|
mpage = ohash_first(&mpages, &pslot); |
mpage = ohash_first(&mpages, &pslot); |
while (NULL != mpage) { |
while (NULL != mpage) { |
mlinks_undupe(mpage); |
mlinks_undupe(mpage); |
Line 1022 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
Line 1030 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
} |
} |
putkey(mpage, mpage->sec, TYPE_sec); |
putkey(mpage, mpage->sec, TYPE_sec); |
putkey(mpage, '\0' == *mpage->arch ? |
putkey(mpage, '\0' == *mpage->arch ? |
"any" : mpage->arch, TYPE_arch); |
any : mpage->arch, TYPE_arch); |
|
|
for (mlink = mpage->mlinks; mlink; mlink = mlink->next) { |
for (mlink = mpage->mlinks; mlink; mlink = mlink->next) { |
if ('\0' != *mlink->dsec) |
if ('\0' != *mlink->dsec) |
Line 1030 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
Line 1038 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
if ('\0' != *mlink->fsec) |
if ('\0' != *mlink->fsec) |
putkey(mpage, mlink->fsec, TYPE_sec); |
putkey(mpage, mlink->fsec, TYPE_sec); |
putkey(mpage, '\0' == *mlink->arch ? |
putkey(mpage, '\0' == *mlink->arch ? |
"any" : mlink->arch, TYPE_arch); |
any : mlink->arch, TYPE_arch); |
putkey(mpage, mlink->name, TYPE_Nm); |
putkey(mpage, mlink->name, TYPE_Nm); |
} |
} |
|
|
Line 1059 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
Line 1067 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
ohash_delete(&strings); |
ohash_delete(&strings); |
mpage = ohash_next(&mpages, &pslot); |
mpage = ohash_next(&mpages, &pslot); |
} |
} |
|
|
|
if (0 == nodb) |
|
SQL_EXEC("END TRANSACTION"); |
} |
} |
|
|
static void |
static void |
Line 1177 parse_cat(struct mpage *mpage) |
|
Line 1188 parse_cat(struct mpage *mpage) |
|
* Put a type/word pair into the word database for this particular file. |
* Put a type/word pair into the word database for this particular file. |
*/ |
*/ |
static void |
static void |
putkey(const struct mpage *mpage, const char *value, uint64_t type) |
putkey(const struct mpage *mpage, char *value, uint64_t type) |
{ |
{ |
|
char *cp; |
|
|
assert(NULL != value); |
assert(NULL != value); |
|
if (TYPE_arch == type) |
|
for (cp = value; *cp; cp++) |
|
if (isupper((unsigned char)*cp)) |
|
*cp = _tolower((unsigned char)*cp); |
putkeys(mpage, value, strlen(value), type); |
putkeys(mpage, value, strlen(value), type); |
} |
} |
|
|
Line 1296 parse_man(struct mpage *mpage, const struct man_node * |
|
Line 1312 parse_man(struct mpage *mpage, const struct man_node * |
|
byte = start[sz]; |
byte = start[sz]; |
start[sz] = '\0'; |
start[sz] = '\0'; |
|
|
|
/* |
|
* Assume a stray trailing comma in the |
|
* name list if a name begins with a dash. |
|
*/ |
|
|
|
if ('-' == start[0] || |
|
('\\' == start[0] && '-' == start[1])) |
|
break; |
|
|
putkey(mpage, start, TYPE_Nm); |
putkey(mpage, start, TYPE_Nm); |
|
|
if (' ' == byte) { |
if (' ' == byte) { |
Line 1425 parse_mdoc_Fd(struct mpage *mpage, const struct mdoc_n |
|
Line 1450 parse_mdoc_Fd(struct mpage *mpage, const struct mdoc_n |
|
static int |
static int |
parse_mdoc_Fn(struct mpage *mpage, const struct mdoc_node *n) |
parse_mdoc_Fn(struct mpage *mpage, const struct mdoc_node *n) |
{ |
{ |
const char *cp; |
char *cp; |
|
|
if (NULL == (n = n->child) || MDOC_TEXT != n->type) |
if (NULL == (n = n->child) || MDOC_TEXT != n->type) |
return(0); |
return(0); |
Line 1547 putkeys(const struct mpage *mpage, |
|
Line 1572 putkeys(const struct mpage *mpage, |
|
const char *cp, size_t sz, uint64_t v) |
const char *cp, size_t sz, uint64_t v) |
{ |
{ |
struct str *s; |
struct str *s; |
unsigned int slot; |
|
const char *end; |
const char *end; |
|
uint64_t mask; |
|
unsigned int slot; |
|
int i; |
|
|
if (0 == sz) |
if (0 == sz) |
return; |
return; |
|
|
|
if (verb > 1) { |
|
for (i = 0, mask = 1; |
|
i < mansearch_keymax; |
|
i++, mask <<= 1) |
|
if (mask & v) |
|
break; |
|
say(mpage->mlinks->file, "Adding key %s=%*s", |
|
mansearch_keynames[i], sz, cp); |
|
} |
|
|
end = cp + sz; |
end = cp + sz; |
slot = ohash_qlookupi(&strings, cp, &end); |
slot = ohash_qlookupi(&strings, cp, &end); |
s = ohash_find(&strings, slot); |
s = ohash_find(&strings, slot); |
|
|
render_key(struct mchars *mc, struct str *key) |
render_key(struct mchars *mc, struct str *key) |
{ |
{ |
size_t sz, bsz, pos; |
size_t sz, bsz, pos; |
char utfbuf[7], res[5]; |
char utfbuf[7], res[6]; |
char *buf; |
char *buf; |
const char *seq, *cpp, *val; |
const char *seq, *cpp, *val; |
int len, u; |
int len, u; |
Line 1641 render_key(struct mchars *mc, struct str *key) |
|
Line 1678 render_key(struct mchars *mc, struct str *key) |
|
res[1] = '\t'; |
res[1] = '\t'; |
res[2] = ASCII_NBRSP; |
res[2] = ASCII_NBRSP; |
res[3] = ASCII_HYPH; |
res[3] = ASCII_HYPH; |
res[4] = '\0'; |
res[4] = ASCII_BREAK; |
|
res[5] = '\0'; |
|
|
val = key->key; |
val = key->key; |
bsz = strlen(val); |
bsz = strlen(val); |
Line 1672 render_key(struct mchars *mc, struct str *key) |
|
Line 1710 render_key(struct mchars *mc, struct str *key) |
|
val += sz; |
val += sz; |
} |
} |
|
|
if (ASCII_HYPH == *val) { |
switch (*val) { |
|
case (ASCII_HYPH): |
buf[pos++] = '-'; |
buf[pos++] = '-'; |
val++; |
val++; |
continue; |
continue; |
} else if ('\t' == *val || ASCII_NBRSP == *val) { |
case ('\t'): |
|
/* FALLTHROUGH */ |
|
case (ASCII_NBRSP): |
buf[pos++] = ' '; |
buf[pos++] = ' '; |
val++; |
val++; |
|
/* FALLTHROUGH */ |
|
case (ASCII_BREAK): |
continue; |
continue; |
} else if ('\\' != *val) |
default: |
break; |
break; |
|
} |
|
if ('\\' != *val) |
|
break; |
|
|
/* Read past the slash. */ |
/* Read past the slash. */ |
|
|
Line 1754 dbadd(const struct mpage *mpage, struct mchars *mc) |
|
Line 1800 dbadd(const struct mpage *mpage, struct mchars *mc) |
|
if (nodb) |
if (nodb) |
return; |
return; |
|
|
SQL_EXEC("BEGIN TRANSACTION"); |
|
|
|
i = 1; |
i = 1; |
SQL_BIND_INT(stmts[STMT_INSERT_PAGE], i, FORM_SRC == mpage->form); |
SQL_BIND_INT(stmts[STMT_INSERT_PAGE], i, FORM_SRC == mpage->form); |
SQL_STEP(stmts[STMT_INSERT_PAGE]); |
SQL_STEP(stmts[STMT_INSERT_PAGE]); |
Line 1787 dbadd(const struct mpage *mpage, struct mchars *mc) |
|
Line 1831 dbadd(const struct mpage *mpage, struct mchars *mc) |
|
free(key->rendered); |
free(key->rendered); |
free(key); |
free(key); |
} |
} |
|
|
SQL_EXEC("END TRANSACTION"); |
|
} |
} |
|
|
static void |
static void |
|
|
dbclose(int real) |
dbclose(int real) |
{ |
{ |
size_t i; |
size_t i; |
|
int status; |
|
pid_t child; |
|
|
if (nodb) |
if (nodb) |
return; |
return; |
Line 1849 dbclose(int real) |
|
Line 1893 dbclose(int real) |
|
if (real) |
if (real) |
return; |
return; |
|
|
if (-1 == rename(MANDOC_DB "~", MANDOC_DB)) { |
if ('\0' == *tempfilename) { |
|
if (-1 == rename(MANDOC_DB "~", MANDOC_DB)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(MANDOC_DB, "%s", strerror(errno)); |
|
} |
|
return; |
|
} |
|
|
|
switch (child = fork()) { |
|
case (-1): |
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say(MANDOC_DB, NULL); |
say("fork cmp", "%s", strerror(errno)); |
|
return; |
|
case (0): |
|
execlp("cmp", "cmp", "-s", |
|
tempfilename, MANDOC_DB, NULL); |
|
say("exec cmp", "%s", strerror(errno)); |
|
exit(0); |
|
default: |
|
break; |
} |
} |
|
if (-1 == waitpid(child, &status, 0)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say("wait cmp", "%s", strerror(errno)); |
|
} else if (WIFSIGNALED(status)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say("cmp", "Died from a signal"); |
|
} else if (WEXITSTATUS(status)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(MANDOC_DB, |
|
"Data changed, but cannot replace database"); |
|
} |
|
|
|
*strrchr(tempfilename, '/') = '\0'; |
|
switch (child = fork()) { |
|
case (-1): |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say("fork rm", "%s", strerror(errno)); |
|
return; |
|
case (0): |
|
execlp("rm", "rm", "-rf", tempfilename, NULL); |
|
say("exec rm", "%s", strerror(errno)); |
|
exit((int)MANDOCLEVEL_SYSERR); |
|
default: |
|
break; |
|
} |
|
if (-1 == waitpid(child, &status, 0)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say("wait rm", "%s", strerror(errno)); |
|
} else if (WIFSIGNALED(status) || WEXITSTATUS(status)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(tempfilename, |
|
"Cannot remove temporary directory"); |
|
} |
} |
} |
|
|
/* |
/* |
Line 1866 dbclose(int real) |
|
Line 1960 dbclose(int real) |
|
static int |
static int |
dbopen(int real) |
dbopen(int real) |
{ |
{ |
const char *file, *sql; |
const char *sql; |
int rc, ofl; |
int rc, ofl; |
|
|
if (nodb) |
if (nodb) |
return(1); |
return(1); |
|
|
|
*tempfilename = '\0'; |
ofl = SQLITE_OPEN_READWRITE; |
ofl = SQLITE_OPEN_READWRITE; |
if (0 == real) { |
|
file = MANDOC_DB "~"; |
if (real) { |
if (-1 == remove(file) && ENOENT != errno) { |
rc = sqlite3_open_v2(MANDOC_DB, &db, ofl, NULL); |
|
if (SQLITE_OK != rc) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say(file, NULL); |
say(MANDOC_DB, "%s", sqlite3_errmsg(db)); |
return(0); |
return(0); |
} |
} |
ofl |= SQLITE_OPEN_EXCLUSIVE; |
goto prepare_statements; |
} else |
} |
file = MANDOC_DB; |
|
|
|
rc = sqlite3_open_v2(file, &db, ofl, NULL); |
ofl |= SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE; |
|
|
|
remove(MANDOC_DB "~"); |
|
rc = sqlite3_open_v2(MANDOC_DB "~", &db, ofl, NULL); |
if (SQLITE_OK == rc) |
if (SQLITE_OK == rc) |
goto prepare_statements; |
goto create_tables; |
if (SQLITE_CANTOPEN != rc) { |
if (MPARSE_QUICK & mparse_options) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say(file, NULL); |
say(MANDOC_DB "~", "%s", sqlite3_errmsg(db)); |
return(0); |
return(0); |
} |
} |
|
|
sqlite3_close(db); |
if (strlcpy(tempfilename, "/tmp/mandocdb.XXXXXX", |
db = NULL; |
sizeof(tempfilename)) >= sizeof(tempfilename)) { |
|
|
if (SQLITE_OK != (rc = sqlite3_open(file, &db))) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say(file, NULL); |
say("/tmp/mandocdb.XXXXXX", "Filename too long"); |
return(0); |
return(0); |
} |
} |
|
if (NULL == mkdtemp(tempfilename)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(tempfilename, "%s", strerror(errno)); |
|
return(0); |
|
} |
|
if (strlcat(tempfilename, "/" MANDOC_DB, |
|
sizeof(tempfilename)) >= sizeof(tempfilename)) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(tempfilename, "Filename too long"); |
|
return(0); |
|
} |
|
rc = sqlite3_open_v2(tempfilename, &db, ofl, NULL); |
|
if (SQLITE_OK != rc) { |
|
exitcode = (int)MANDOCLEVEL_SYSERR; |
|
say(tempfilename, "%s", sqlite3_errmsg(db)); |
|
return(0); |
|
} |
|
|
|
create_tables: |
sql = "CREATE TABLE \"mpages\" (\n" |
sql = "CREATE TABLE \"mpages\" (\n" |
" \"form\" INTEGER NOT NULL,\n" |
" \"form\" INTEGER NOT NULL,\n" |
" \"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL\n" |
" \"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL\n" |
Line 1912 dbopen(int real) |
|
Line 2026 dbopen(int real) |
|
" \"arch\" TEXT NOT NULL,\n" |
" \"arch\" TEXT NOT NULL,\n" |
" \"name\" TEXT NOT NULL,\n" |
" \"name\" TEXT NOT NULL,\n" |
" \"pageid\" INTEGER NOT NULL REFERENCES mpages(id) " |
" \"pageid\" INTEGER NOT NULL REFERENCES mpages(id) " |
"ON DELETE CASCADE,\n" |
"ON DELETE CASCADE\n" |
" \"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL\n" |
|
");\n" |
");\n" |
"\n" |
"\n" |
"CREATE TABLE \"keys\" (\n" |
"CREATE TABLE \"keys\" (\n" |
" \"bits\" INTEGER NOT NULL,\n" |
" \"bits\" INTEGER NOT NULL,\n" |
" \"key\" TEXT NOT NULL,\n" |
" \"key\" TEXT NOT NULL,\n" |
" \"pageid\" INTEGER NOT NULL REFERENCES mpages(id) " |
" \"pageid\" INTEGER NOT NULL REFERENCES mpages(id) " |
"ON DELETE CASCADE,\n" |
"ON DELETE CASCADE\n" |
" \"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL\n" |
");\n"; |
");\n" |
|
"\n" |
|
"CREATE INDEX \"key_index\" ON keys (key);\n"; |
|
|
|
if (SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, NULL)) { |
if (SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, NULL)) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say(file, "%s", sqlite3_errmsg(db)); |
say(MANDOC_DB, "%s", sqlite3_errmsg(db)); |
return(0); |
return(0); |
} |
} |
|
|