version 1.131, 2014/04/04 18:23:30 |
version 1.139, 2014/04/19 02:30:19 |
Line 55 extern const char *const mansearch_keynames[]; |
|
Line 55 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)) |
say("", "%s: %s", (_v), sqlite3_errmsg(db)) |
#define SQL_BIND_TEXT(_s, _i, _v) \ |
#define SQL_BIND_TEXT(_s, _i, _v) \ |
if (SQLITE_OK != sqlite3_bind_text \ |
if (SQLITE_OK != sqlite3_bind_text \ |
((_s), (_i)++, (_v), -1, SQLITE_STATIC)) \ |
((_s), (_i)++, (_v), -1, SQLITE_STATIC)) \ |
fprintf(stderr, "%s\n", sqlite3_errmsg(db)) |
say(mlink->file, "%s", sqlite3_errmsg(db)) |
#define SQL_BIND_INT(_s, _i, _v) \ |
#define SQL_BIND_INT(_s, _i, _v) \ |
if (SQLITE_OK != sqlite3_bind_int \ |
if (SQLITE_OK != sqlite3_bind_int \ |
((_s), (_i)++, (_v))) \ |
((_s), (_i)++, (_v))) \ |
fprintf(stderr, "%s\n", sqlite3_errmsg(db)) |
say(mlink->file, "%s", sqlite3_errmsg(db)) |
#define SQL_BIND_INT64(_s, _i, _v) \ |
#define SQL_BIND_INT64(_s, _i, _v) \ |
if (SQLITE_OK != sqlite3_bind_int64 \ |
if (SQLITE_OK != sqlite3_bind_int64 \ |
((_s), (_i)++, (_v))) \ |
((_s), (_i)++, (_v))) \ |
fprintf(stderr, "%s\n", sqlite3_errmsg(db)) |
say(mlink->file, "%s", sqlite3_errmsg(db)) |
#define SQL_STEP(_s) \ |
#define SQL_STEP(_s) \ |
if (SQLITE_DONE != sqlite3_step((_s))) \ |
if (SQLITE_DONE != sqlite3_step((_s))) \ |
fprintf(stderr, "%s\n", sqlite3_errmsg(db)) |
say(mlink->file, "%s", sqlite3_errmsg(db)) |
|
|
enum op { |
enum op { |
OP_DEFAULT = 0, /* new dbs from dir list or default config */ |
OP_DEFAULT = 0, /* new dbs from dir list or default config */ |
|
|
|
|
struct mpage { |
struct mpage { |
struct inodev inodev; /* used for hashing routine */ |
struct inodev inodev; /* used for hashing routine */ |
int64_t recno; /* id in mpages SQL table */ |
int64_t pageid; /* pageid in mpages SQL table */ |
enum form form; /* format from file content */ |
enum form form; /* format from file content */ |
char *sec; /* section from file content */ |
char *sec; /* section from file content */ |
char *arch; /* architecture from file content */ |
char *arch; /* architecture from file content */ |
|
|
STMT_DELETE_PAGE = 0, /* delete mpage */ |
STMT_DELETE_PAGE = 0, /* delete mpage */ |
STMT_INSERT_PAGE, /* insert mpage */ |
STMT_INSERT_PAGE, /* insert mpage */ |
STMT_INSERT_LINK, /* insert mlink */ |
STMT_INSERT_LINK, /* insert mlink */ |
|
STMT_INSERT_NAME, /* insert name */ |
STMT_INSERT_KEY, /* insert parsed key */ |
STMT_INSERT_KEY, /* insert parsed key */ |
STMT__MAX |
STMT__MAX |
}; |
}; |
Line 188 static enum op op; /* operational mode */ |
|
Line 189 static enum op op; /* operational mode */ |
|
static char basedir[PATH_MAX]; /* current base directory */ |
static char basedir[PATH_MAX]; /* current base directory */ |
static struct ohash mpages; /* table of distinct manual pages */ |
static struct ohash mpages; /* table of distinct manual pages */ |
static struct ohash mlinks; /* table of directory entries */ |
static struct ohash mlinks; /* table of directory entries */ |
|
static struct ohash names; /* table of all names */ |
static struct ohash strings; /* table of all strings */ |
static struct ohash strings; /* table of all strings */ |
static sqlite3 *db = NULL; /* current database */ |
static sqlite3 *db = NULL; /* current database */ |
static sqlite3_stmt *stmts[STMT__MAX]; /* current statements */ |
static sqlite3_stmt *stmts[STMT__MAX]; /* current statements */ |
|
static uint64_t name_mask; |
|
|
static const struct mdoc_handler mdocs[MDOC_MAX] = { |
static const struct mdoc_handler mdocs[MDOC_MAX] = { |
{ NULL, 0 }, /* Ap */ |
{ NULL, 0 }, /* Ap */ |
Line 224 static const struct mdoc_handler mdocs[MDOC_MAX] = { |
|
Line 227 static const struct mdoc_handler mdocs[MDOC_MAX] = { |
|
{ NULL, TYPE_Ic }, /* Ic */ |
{ NULL, TYPE_Ic }, /* Ic */ |
{ NULL, TYPE_In }, /* In */ |
{ NULL, TYPE_In }, /* In */ |
{ NULL, TYPE_Li }, /* Li */ |
{ NULL, TYPE_Li }, /* Li */ |
{ parse_mdoc_Nd, TYPE_Nd }, /* Nd */ |
{ parse_mdoc_Nd, 0 }, /* Nd */ |
{ parse_mdoc_Nm, 0 }, /* Nm */ |
{ parse_mdoc_Nm, 0 }, /* Nm */ |
{ NULL, 0 }, /* Op */ |
{ NULL, 0 }, /* Op */ |
{ NULL, 0 }, /* Ot */ |
{ NULL, 0 }, /* Ot */ |
Line 439 main(int argc, char *argv[]) |
|
Line 442 main(int argc, char *argv[]) |
|
*/ |
*/ |
if (0 == set_basedir(path_arg)) |
if (0 == set_basedir(path_arg)) |
goto out; |
goto out; |
for (i = 0; i < argc; i++) |
if (dbopen(1)) { |
filescan(argv[i]); |
for (i = 0; i < argc; i++) |
if (0 == dbopen(1)) |
filescan(argv[i]); |
goto out; |
if (OP_TEST != op) |
if (OP_TEST != op) |
dbprune(); |
dbprune(); |
} else { |
|
/* |
|
* Database missing or corrupt. |
|
* Recreate from scratch. |
|
*/ |
|
op = OP_DEFAULT; |
|
if (0 == treescan()) |
|
goto out; |
|
if (0 == dbopen(0)) |
|
goto out; |
|
} |
if (OP_DELETE != op) |
if (OP_DELETE != op) |
mpages_merge(mc, mp); |
mpages_merge(mc, mp); |
dbclose(1); |
dbclose(OP_DEFAULT == op ? 0 : 1); |
} else { |
} else { |
/* |
/* |
* If we have arguments, use them as our manpaths. |
* If we have arguments, use them as our manpaths. |
|
|
static int |
static int |
treescan(void) |
treescan(void) |
{ |
{ |
|
char buf[PATH_MAX]; |
FTS *f; |
FTS *f; |
FTSENT *ff; |
FTSENT *ff; |
struct mlink *mlink; |
struct mlink *mlink; |
|
|
argv[0] = "."; |
argv[0] = "."; |
argv[1] = (char *)NULL; |
argv[1] = (char *)NULL; |
|
|
/* |
f = fts_open((char * const *)argv, |
* Walk through all components under the directory, using the |
FTS_PHYSICAL | FTS_NOCHDIR, NULL); |
* logical descent of files. |
|
*/ |
|
f = fts_open((char * const *)argv, FTS_LOGICAL, NULL); |
|
if (NULL == f) { |
if (NULL == f) { |
exitcode = (int)MANDOCLEVEL_SYSERR; |
exitcode = (int)MANDOCLEVEL_SYSERR; |
say("", "&fts_open"); |
say("", "&fts_open"); |
|
|
|
|
while (NULL != (ff = fts_read(f))) { |
while (NULL != (ff = fts_read(f))) { |
path = ff->fts_path + 2; |
path = ff->fts_path + 2; |
|
switch (ff->fts_info) { |
|
|
/* |
/* |
|
* Symbolic links require various sanity checks, |
|
* then get handled just like regular files. |
|
*/ |
|
case (FTS_SL): |
|
if (NULL == realpath(path, buf)) { |
|
if (warnings) |
|
say(path, "&realpath"); |
|
continue; |
|
} |
|
if (strstr(buf, basedir) != buf) { |
|
if (warnings) say("", |
|
"%s: outside base directory", buf); |
|
continue; |
|
} |
|
/* Use logical inode to avoid mpages dupe. */ |
|
if (-1 == stat(path, ff->fts_statp)) { |
|
if (warnings) |
|
say(path, "&stat"); |
|
continue; |
|
} |
|
/* FALLTHROUGH */ |
|
|
|
/* |
* If we're a regular file, add an mlink by using the |
* If we're a regular file, add an mlink by using the |
* stored directory data and handling the filename. |
* stored directory data and handling the filename. |
*/ |
*/ |
if (FTS_F == ff->fts_info) { |
case (FTS_F): |
if (0 == strcmp(path, MANDOC_DB)) |
if (0 == strcmp(path, MANDOC_DB)) |
continue; |
continue; |
if ( ! use_all && ff->fts_level < 2) { |
if ( ! use_all && ff->fts_level < 2) { |
|
|
mlink->gzip = gzip; |
mlink->gzip = gzip; |
mlink_add(mlink, ff->fts_statp); |
mlink_add(mlink, ff->fts_statp); |
continue; |
continue; |
} else if (FTS_D != ff->fts_info && |
|
FTS_DP != ff->fts_info) { |
case (FTS_D): |
|
/* FALLTHROUGH */ |
|
case (FTS_DP): |
|
break; |
|
|
|
default: |
if (warnings) |
if (warnings) |
say(path, "Not a regular file"); |
say(path, "Not a regular file"); |
continue; |
continue; |
Line 723 filescan(const char *file) |
|
Line 764 filescan(const char *file) |
|
if (0 == strncmp(file, "./", 2)) |
if (0 == strncmp(file, "./", 2)) |
file += 2; |
file += 2; |
|
|
|
/* |
|
* We have to do lstat(2) before realpath(3) loses |
|
* the information whether this is a symbolic link. |
|
* We need to know that because for symbolic links, |
|
* we want to use the orginal file name, while for |
|
* regular files, we want to use the real path. |
|
*/ |
|
if (-1 == lstat(file, &st)) { |
|
exitcode = (int)MANDOCLEVEL_BADARG; |
|
say(file, "&lstat"); |
|
return; |
|
} else if (0 == ((S_IFREG | S_IFLNK) & st.st_mode)) { |
|
exitcode = (int)MANDOCLEVEL_BADARG; |
|
say(file, "Not a regular file"); |
|
return; |
|
} |
|
|
|
/* |
|
* We have to resolve the file name to the real path |
|
* in any case for the base directory check. |
|
*/ |
if (NULL == realpath(file, buf)) { |
if (NULL == realpath(file, buf)) { |
exitcode = (int)MANDOCLEVEL_BADARG; |
exitcode = (int)MANDOCLEVEL_BADARG; |
say(file, "&realpath"); |
say(file, "&realpath"); |
Line 739 filescan(const char *file) |
|
Line 801 filescan(const char *file) |
|
return; |
return; |
} |
} |
|
|
if (-1 == stat(buf, &st)) { |
/* |
exitcode = (int)MANDOCLEVEL_BADARG; |
* Now we are sure the file is inside our tree. |
say(file, "&stat"); |
* If it is a symbolic link, ignore the real path |
return; |
* and use the original name. |
} else if ( ! (S_IFREG & st.st_mode)) { |
* This implies passing stuff like "cat1/../man1/foo.1" |
exitcode = (int)MANDOCLEVEL_BADARG; |
* on the command line won't work. So don't do that. |
say(file, "Not a regular file"); |
* Note the stat(2) can still fail if the link target |
return; |
* doesn't exist. |
|
*/ |
|
if (S_IFLNK & st.st_mode) { |
|
if (-1 == stat(buf, &st)) { |
|
exitcode = (int)MANDOCLEVEL_BADARG; |
|
say(file, "&stat"); |
|
return; |
|
} |
|
strlcpy(buf, file, sizeof(buf)); |
|
start = strstr(buf, basedir) == buf ? |
|
buf + strlen(basedir) + 1 : buf; |
} |
} |
|
|
mlink = mandoc_calloc(1, sizeof(struct mlink)); |
mlink = mandoc_calloc(1, sizeof(struct mlink)); |
Line 963 mlink_check(struct mpage *mpage, struct mlink *mlink) |
|
Line 1035 mlink_check(struct mpage *mpage, struct mlink *mlink) |
|
|
|
/* |
/* |
* XXX |
* XXX |
* parse_cat() doesn't set TYPE_Nm and TYPE_NAME yet. |
* parse_cat() doesn't set NAME_TITLE yet. |
*/ |
*/ |
|
|
if (FORM_CAT == mpage->form) |
if (FORM_CAT == mpage->form) |
Line 974 mlink_check(struct mpage *mpage, struct mlink *mlink) |
|
Line 1046 mlink_check(struct mpage *mpage, struct mlink *mlink) |
|
* appears as a name in the NAME section. |
* appears as a name in the NAME section. |
*/ |
*/ |
|
|
slot = ohash_qlookup(&strings, mlink->name); |
slot = ohash_qlookup(&names, mlink->name); |
str = ohash_find(&strings, slot); |
str = ohash_find(&names, slot); |
assert(NULL != str); |
assert(NULL != str); |
if ( ! (TYPE_NAME & str->mask)) |
if ( ! (NAME_TITLE & str->mask)) |
say(mlink->file, "Name missing in NAME section"); |
say(mlink->file, "Name missing in NAME section"); |
} |
} |
|
|
Line 1021 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
Line 1093 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
continue; |
continue; |
} |
} |
|
|
|
name_mask = NAME_MASK; |
|
ohash_init(&names, 4, &str_info); |
ohash_init(&strings, 6, &str_info); |
ohash_init(&strings, 6, &str_info); |
mparse_reset(mp); |
mparse_reset(mp); |
mdoc = NULL; |
mdoc = NULL; |
Line 1094 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
Line 1168 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
* to the target. |
* to the target. |
*/ |
*/ |
|
|
if (mpage_dest->recno) |
if (mpage_dest->pageid) |
dbadd_mlink(mlink); |
dbadd_mlink(mlink); |
|
|
if (NULL == mlink->next) |
if (NULL == mlink->next) |
Line 1146 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
Line 1220 mpages_merge(struct mchars *mc, struct mparse *mp) |
|
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, NAME_FILE); |
} |
} |
|
|
|
assert(NULL == mpage->desc); |
if (NULL != mdoc) { |
if (NULL != mdoc) { |
if (NULL != (cp = mdoc_meta(mdoc)->name)) |
if (NULL != (cp = mdoc_meta(mdoc)->name)) |
putkey(mpage, cp, TYPE_Nm); |
putkey(mpage, cp, NAME_HEAD); |
assert(NULL == mpage->desc); |
|
parse_mdoc(mpage, mdoc_node(mdoc)); |
parse_mdoc(mpage, mdoc_node(mdoc)); |
putkey(mpage, NULL != mpage->desc ? |
|
mpage->desc : mpage->mlinks->name, TYPE_Nd); |
|
} else if (NULL != man) |
} else if (NULL != man) |
parse_man(mpage, man_node(man)); |
parse_man(mpage, man_node(man)); |
else |
else |
parse_cat(mpage, fd[0]); |
parse_cat(mpage, fd[0]); |
|
if (NULL == mpage->desc) |
|
mpage->desc = mandoc_strdup(mpage->mlinks->name); |
|
|
if (warnings && !use_all) |
if (warnings && !use_all) |
for (mlink = mpage->mlinks; mlink; |
for (mlink = mpage->mlinks; mlink; |
|
|
} |
} |
} |
} |
ohash_delete(&strings); |
ohash_delete(&strings); |
|
ohash_delete(&names); |
mpage = ohash_next(&mpages, &pslot); |
mpage = ohash_next(&mpages, &pslot); |
} |
} |
|
|
Line 1198 names_check(void) |
|
Line 1273 names_check(void) |
|
{ |
{ |
sqlite3_stmt *stmt; |
sqlite3_stmt *stmt; |
const char *name, *sec, *arch, *key; |
const char *name, *sec, *arch, *key; |
size_t i; |
|
int irc; |
int irc; |
|
|
sqlite3_prepare_v2(db, |
sqlite3_prepare_v2(db, |
"SELECT name, sec, arch, key FROM (" |
"SELECT name, sec, arch, key FROM (" |
"SELECT key, pageid FROM keys " |
"SELECT name AS key, pageid FROM names " |
"WHERE bits & ? AND NOT EXISTS (" |
"WHERE bits & ? AND NOT EXISTS (" |
"SELECT pageid FROM mlinks " |
"SELECT pageid FROM mlinks " |
"WHERE mlinks.pageid == keys.pageid " |
"WHERE mlinks.pageid == names.pageid " |
"AND mlinks.name == keys.key" |
"AND mlinks.name == names.name" |
")" |
")" |
") JOIN (" |
") JOIN (" |
"SELECT * FROM mlinks GROUP BY pageid" |
"SELECT * FROM mlinks GROUP BY pageid" |
") USING (pageid);", |
") USING (pageid);", |
-1, &stmt, NULL); |
-1, &stmt, NULL); |
|
|
i = 1; |
if (SQLITE_OK != sqlite3_bind_int64(stmt, 1, NAME_TITLE)) |
SQL_BIND_INT64(stmt, i, TYPE_NAME); |
say("", "%s", sqlite3_errmsg(db)); |
|
|
while (SQLITE_ROW == (irc = sqlite3_step(stmt))) { |
while (SQLITE_ROW == (irc = sqlite3_step(stmt))) { |
name = sqlite3_column_text(stmt, 0); |
name = sqlite3_column_text(stmt, 0); |
Line 1296 parse_cat(struct mpage *mpage, int fd) |
|
Line 1370 parse_cat(struct mpage *mpage, int fd) |
|
if (warnings) |
if (warnings) |
say(mpage->mlinks->file, |
say(mpage->mlinks->file, |
"Cannot find NAME section"); |
"Cannot find NAME section"); |
assert(NULL == mpage->desc); |
|
mpage->desc = mandoc_strdup(mpage->mlinks->name); |
|
putkey(mpage, mpage->mlinks->name, TYPE_Nd); |
|
fclose(stream); |
fclose(stream); |
free(title); |
free(title); |
return; |
return; |
Line 1337 parse_cat(struct mpage *mpage, int fd) |
|
Line 1408 parse_cat(struct mpage *mpage, int fd) |
|
plen -= 2; |
plen -= 2; |
} |
} |
|
|
assert(NULL == mpage->desc); |
|
mpage->desc = mandoc_strdup(p); |
mpage->desc = mandoc_strdup(p); |
putkey(mpage, mpage->desc, TYPE_Nd); |
|
fclose(stream); |
fclose(stream); |
free(title); |
free(title); |
} |
} |
Line 1442 parse_man(struct mpage *mpage, const struct man_node * |
|
Line 1511 parse_man(struct mpage *mpage, const struct man_node * |
|
('\\' == start[0] && '-' == start[1])) |
('\\' == start[0] && '-' == start[1])) |
break; |
break; |
|
|
putkey(mpage, start, TYPE_NAME | TYPE_Nm); |
putkey(mpage, start, NAME_TITLE); |
|
|
if (' ' == byte) { |
if (' ' == byte) { |
start += sz + 1; |
start += sz + 1; |
Line 1456 parse_man(struct mpage *mpage, const struct man_node * |
|
Line 1525 parse_man(struct mpage *mpage, const struct man_node * |
|
} |
} |
|
|
if (start == title) { |
if (start == title) { |
putkey(mpage, start, TYPE_NAME | TYPE_Nm); |
putkey(mpage, start, NAME_TITLE); |
free(title); |
free(title); |
return; |
return; |
} |
} |
Line 1478 parse_man(struct mpage *mpage, const struct man_node * |
|
Line 1547 parse_man(struct mpage *mpage, const struct man_node * |
|
while (' ' == *start) |
while (' ' == *start) |
start++; |
start++; |
|
|
assert(NULL == mpage->desc); |
|
mpage->desc = mandoc_strdup(start); |
mpage->desc = mandoc_strdup(start); |
putkey(mpage, mpage->desc, TYPE_Nd); |
|
free(title); |
free(title); |
return; |
return; |
} |
} |
Line 1634 parse_mdoc_Nm(struct mpage *mpage, const struct mdoc_n |
|
Line 1701 parse_mdoc_Nm(struct mpage *mpage, const struct mdoc_n |
|
{ |
{ |
|
|
if (SEC_NAME == n->sec) |
if (SEC_NAME == n->sec) |
putmdockey(mpage, n->child, TYPE_NAME | TYPE_Nm); |
putmdockey(mpage, n->child, NAME_TITLE); |
else if (SEC_SYNOPSIS == n->sec && MDOC_HEAD == n->type) |
else if (SEC_SYNOPSIS == n->sec && MDOC_HEAD == n->type) |
putmdockey(mpage, n->child, TYPE_Nm); |
putmdockey(mpage, n->child, NAME_SYN); |
return(0); |
return(0); |
} |
} |
|
|
|
|
putkeys(const struct mpage *mpage, |
putkeys(const struct mpage *mpage, |
const char *cp, size_t sz, uint64_t v) |
const char *cp, size_t sz, uint64_t v) |
{ |
{ |
|
struct ohash *htab; |
struct str *s; |
struct str *s; |
const char *end; |
const char *end; |
uint64_t mask; |
|
unsigned int slot; |
unsigned int slot; |
int i; |
int i; |
|
|
if (0 == sz) |
if (0 == sz) |
return; |
return; |
|
|
if (debug > 1) { |
if (TYPE_Nm & v) { |
for (i = 0, mask = 1; |
htab = &names; |
i < mansearch_keymax; |
v &= name_mask; |
i++, mask <<= 1) |
name_mask &= ~NAME_FIRST; |
if (mask & v) |
if (debug > 1) |
break; |
say(mpage->mlinks->file, |
say(mpage->mlinks->file, "Adding key %s=%*s", |
"Adding name %*s", sz, cp); |
mansearch_keynames[i], sz, cp); |
} else { |
|
htab = &strings; |
|
if (debug > 1) |
|
for (i = 0; i < mansearch_keymax; i++) |
|
if (1 << i & v) |
|
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(htab, cp, &end); |
s = ohash_find(&strings, slot); |
s = ohash_find(htab, slot); |
|
|
if (NULL != s && mpage == s->mpage) { |
if (NULL != s && mpage == s->mpage) { |
s->mask |= v; |
s->mask |= v; |
Line 1699 putkeys(const struct mpage *mpage, |
|
Line 1773 putkeys(const struct mpage *mpage, |
|
} else if (NULL == s) { |
} else if (NULL == s) { |
s = mandoc_calloc(sizeof(struct str) + sz + 1, 1); |
s = mandoc_calloc(sizeof(struct str) + sz + 1, 1); |
memcpy(s->key, cp, sz); |
memcpy(s->key, cp, sz); |
ohash_insert(&strings, slot, s); |
ohash_insert(htab, slot, s); |
} |
} |
s->mpage = mpage; |
s->mpage = mpage; |
s->mask = v; |
s->mask = v; |
Line 1887 dbadd_mlink(const struct mlink *mlink) |
|
Line 1961 dbadd_mlink(const struct mlink *mlink) |
|
SQL_BIND_TEXT(stmts[STMT_INSERT_LINK], i, mlink->dsec); |
SQL_BIND_TEXT(stmts[STMT_INSERT_LINK], i, mlink->dsec); |
SQL_BIND_TEXT(stmts[STMT_INSERT_LINK], i, mlink->arch); |
SQL_BIND_TEXT(stmts[STMT_INSERT_LINK], i, mlink->arch); |
SQL_BIND_TEXT(stmts[STMT_INSERT_LINK], i, mlink->name); |
SQL_BIND_TEXT(stmts[STMT_INSERT_LINK], i, mlink->name); |
SQL_BIND_INT64(stmts[STMT_INSERT_LINK], i, mlink->mpage->recno); |
SQL_BIND_INT64(stmts[STMT_INSERT_LINK], i, mlink->mpage->pageid); |
SQL_STEP(stmts[STMT_INSERT_LINK]); |
SQL_STEP(stmts[STMT_INSERT_LINK]); |
sqlite3_reset(stmts[STMT_INSERT_LINK]); |
sqlite3_reset(stmts[STMT_INSERT_LINK]); |
} |
} |
Line 1928 dbadd(struct mpage *mpage, struct mchars *mc) |
|
Line 2002 dbadd(struct mpage *mpage, struct mchars *mc) |
|
if (NULL != mlink) |
if (NULL != mlink) |
fputs(", ", stdout); |
fputs(", ", stdout); |
} |
} |
for (key = ohash_first(&strings, &slot); NULL != key; |
printf(" - %s\n", mpage->desc); |
key = ohash_next(&strings, &slot)) { |
|
if (TYPE_Nd & key->mask) { |
|
if (NULL == key->rendered) |
|
render_key(mc, key); |
|
printf(" - %s", key->rendered); |
|
break; |
|
} |
|
} |
|
putchar('\n'); |
|
return; |
return; |
} |
} |
|
|
Line 1945 dbadd(struct mpage *mpage, struct mchars *mc) |
|
Line 2010 dbadd(struct mpage *mpage, struct mchars *mc) |
|
say(mlink->file, "Adding to database"); |
say(mlink->file, "Adding to database"); |
|
|
i = 1; |
i = 1; |
|
SQL_BIND_TEXT(stmts[STMT_INSERT_PAGE], i, mpage->desc); |
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]); |
mpage->recno = sqlite3_last_insert_rowid(db); |
mpage->pageid = sqlite3_last_insert_rowid(db); |
sqlite3_reset(stmts[STMT_INSERT_PAGE]); |
sqlite3_reset(stmts[STMT_INSERT_PAGE]); |
|
|
while (NULL != mlink) { |
while (NULL != mlink) { |
dbadd_mlink(mlink); |
dbadd_mlink(mlink); |
mlink = mlink->next; |
mlink = mlink->next; |
} |
} |
|
mlink = mpage->mlinks; |
|
|
|
for (key = ohash_first(&names, &slot); NULL != key; |
|
key = ohash_next(&names, &slot)) { |
|
assert(key->mpage == mpage); |
|
if (NULL == key->rendered) |
|
render_key(mc, key); |
|
i = 1; |
|
SQL_BIND_INT64(stmts[STMT_INSERT_NAME], i, key->mask); |
|
SQL_BIND_TEXT(stmts[STMT_INSERT_NAME], i, key->rendered); |
|
SQL_BIND_INT64(stmts[STMT_INSERT_NAME], i, mpage->pageid); |
|
SQL_STEP(stmts[STMT_INSERT_NAME]); |
|
sqlite3_reset(stmts[STMT_INSERT_NAME]); |
|
if (key->rendered != key->key) |
|
free(key->rendered); |
|
free(key); |
|
} |
for (key = ohash_first(&strings, &slot); NULL != key; |
for (key = ohash_first(&strings, &slot); NULL != key; |
key = ohash_next(&strings, &slot)) { |
key = ohash_next(&strings, &slot)) { |
assert(key->mpage == mpage); |
assert(key->mpage == mpage); |
Line 1963 dbadd(struct mpage *mpage, struct mchars *mc) |
|
Line 2045 dbadd(struct mpage *mpage, struct mchars *mc) |
|
i = 1; |
i = 1; |
SQL_BIND_INT64(stmts[STMT_INSERT_KEY], i, key->mask); |
SQL_BIND_INT64(stmts[STMT_INSERT_KEY], i, key->mask); |
SQL_BIND_TEXT(stmts[STMT_INSERT_KEY], i, key->rendered); |
SQL_BIND_TEXT(stmts[STMT_INSERT_KEY], i, key->rendered); |
SQL_BIND_INT64(stmts[STMT_INSERT_KEY], i, mpage->recno); |
SQL_BIND_INT64(stmts[STMT_INSERT_KEY], i, mpage->pageid); |
SQL_STEP(stmts[STMT_INSERT_KEY]); |
SQL_STEP(stmts[STMT_INSERT_KEY]); |
sqlite3_reset(stmts[STMT_INSERT_KEY]); |
sqlite3_reset(stmts[STMT_INSERT_KEY]); |
if (key->rendered != key->key) |
if (key->rendered != key->key) |
Line 2157 dbopen(int real) |
|
Line 2239 dbopen(int real) |
|
|
|
create_tables: |
create_tables: |
sql = "CREATE TABLE \"mpages\" (\n" |
sql = "CREATE TABLE \"mpages\" (\n" |
|
" \"desc\" TEXT NOT NULL,\n" |
" \"form\" INTEGER NOT NULL,\n" |
" \"form\" INTEGER NOT NULL,\n" |
" \"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL\n" |
" \"pageid\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL\n" |
");\n" |
");\n" |
"\n" |
"\n" |
"CREATE TABLE \"mlinks\" (\n" |
"CREATE TABLE \"mlinks\" (\n" |
" \"sec\" TEXT NOT NULL,\n" |
" \"sec\" TEXT NOT NULL,\n" |
" \"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(pageid) " |
"ON DELETE CASCADE\n" |
"ON DELETE CASCADE\n" |
");\n" |
");\n" |
|
"CREATE INDEX mlinks_pageid_idx ON mlinks (pageid);\n" |
"\n" |
"\n" |
|
"CREATE TABLE \"names\" (\n" |
|
" \"bits\" INTEGER NOT NULL,\n" |
|
" \"name\" TEXT NOT NULL,\n" |
|
" \"pageid\" INTEGER NOT NULL REFERENCES mpages(pageid) " |
|
"ON DELETE CASCADE\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(pageid) " |
"ON DELETE CASCADE\n" |
"ON DELETE CASCADE\n" |
");\n"; |
");\n" |
|
"CREATE INDEX keys_pageid_idx ON keys (pageid);\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; |
|
|
|
|
prepare_statements: |
prepare_statements: |
SQL_EXEC("PRAGMA foreign_keys = ON"); |
SQL_EXEC("PRAGMA foreign_keys = ON"); |
sql = "DELETE FROM mpages WHERE id IN " |
sql = "DELETE FROM mpages WHERE pageid IN " |
"(SELECT pageid FROM mlinks WHERE " |
"(SELECT pageid FROM mlinks WHERE " |
"sec=? AND arch=? AND name=?)"; |
"sec=? AND arch=? AND name=?)"; |
sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_DELETE_PAGE], NULL); |
sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_DELETE_PAGE], NULL); |
sql = "INSERT INTO mpages " |
sql = "INSERT INTO mpages " |
"(form) VALUES (?)"; |
"(desc,form) VALUES (?,?)"; |
sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_PAGE], NULL); |
sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_PAGE], NULL); |
sql = "INSERT INTO mlinks " |
sql = "INSERT INTO mlinks " |
"(sec,arch,name,pageid) VALUES (?,?,?,?)"; |
"(sec,arch,name,pageid) VALUES (?,?,?,?)"; |
sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_LINK], NULL); |
sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_LINK], NULL); |
|
sql = "INSERT INTO names " |
|
"(bits,name,pageid) VALUES (?,?,?)"; |
|
sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_NAME], NULL); |
sql = "INSERT INTO keys " |
sql = "INSERT INTO keys " |
"(bits,key,pageid) VALUES (?,?,?)"; |
"(bits,key,pageid) VALUES (?,?,?)"; |
sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_KEY], NULL); |
sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_KEY], NULL); |