=================================================================== RCS file: /cvs/mandoc/mandocdb.c,v retrieving revision 1.125 retrieving revision 1.132 diff -u -p -r1.125 -r1.132 --- mandoc/mandocdb.c 2014/04/03 15:37:19 1.125 +++ mandoc/mandocdb.c 2014/04/09 21:50:08 1.132 @@ -1,4 +1,4 @@ -/* $Id: mandocdb.c,v 1.125 2014/04/03 15:37:19 schwarze Exp $ */ +/* $Id: mandocdb.c,v 1.132 2014/04/09 21:50:08 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze @@ -147,11 +147,12 @@ static void *hash_alloc(size_t, void *); static void hash_free(void *, size_t, void *); static void *hash_halloc(size_t, void *); static void mlink_add(struct mlink *, const struct stat *); -static int mlink_check(struct mpage *, struct mlink *); +static void mlink_check(struct mpage *, struct mlink *); static void mlink_free(struct mlink *); static void mlinks_undupe(struct mpage *); static void mpages_free(void); static void mpages_merge(struct mchars *, struct mparse *); +static void names_check(void); static void parse_cat(struct mpage *, int); static void parse_man(struct mpage *, const struct man_node *); static void parse_mdoc(struct mpage *, const struct mdoc_node *); @@ -223,8 +224,8 @@ static const struct mdoc_handler mdocs[MDOC_MAX] = { { NULL, TYPE_Ic }, /* Ic */ { NULL, TYPE_In }, /* In */ { NULL, TYPE_Li }, /* Li */ - { parse_mdoc_Nd, TYPE_Nd }, /* Nd */ - { parse_mdoc_Nm, TYPE_Nm }, /* Nm */ + { parse_mdoc_Nd, 0 }, /* Nd */ + { parse_mdoc_Nm, 0 }, /* Nm */ { NULL, 0 }, /* Op */ { NULL, 0 }, /* Ot */ { NULL, TYPE_Pa }, /* Pa */ @@ -357,7 +358,7 @@ main(int argc, char *argv[]) path_arg = NULL; op = OP_DEFAULT; - while (-1 != (ch = getopt(argc, argv, "aC:Dd:nQT:tu:W"))) + while (-1 != (ch = getopt(argc, argv, "aC:Dd:npQT:tu:v"))) switch (ch) { case ('a'): use_all = 1; @@ -378,6 +379,9 @@ main(int argc, char *argv[]) case ('n'): nodb = 1; break; + case ('p'): + warnings = 1; + break; case ('Q'): mparse_options |= MPARSE_QUICK; break; @@ -400,8 +404,8 @@ main(int argc, char *argv[]) path_arg = optarg; op = OP_DELETE; break; - case ('W'): - warnings = 1; + case ('v'): + /* Compatibility with espie@'s makewhatis. */ break; default: goto usage; @@ -459,6 +463,11 @@ main(int argc, char *argv[]) } else manpath_parse(&dirs, path_arg, NULL, NULL); + if (0 == dirs.sz) { + exitcode = (int)MANDOCLEVEL_BADARG; + say("", "Empty manpath"); + } + /* * First scan the tree rooted at a base directory, then * build a new database and finally move it into place. @@ -487,6 +496,9 @@ main(int argc, char *argv[]) goto out; mpages_merge(mc, mp); + if (warnings && + ! (MPARSE_QUICK & mparse_options)) + names_check(); dbclose(0); if (j + 1 < dirs.sz) { @@ -506,10 +518,10 @@ out: ohash_delete(&mlinks); return(exitcode); usage: - fprintf(stderr, "usage: %s [-aDnQW] [-C file] [-Tutf8]\n" - " %s [-aDnQW] [-Tutf8] dir ...\n" - " %s [-DnQW] [-Tutf8] -d dir [file ...]\n" - " %s [-DnW] -u dir [file ...]\n" + fprintf(stderr, "usage: %s [-aDnpQ] [-C file] [-Tutf8]\n" + " %s [-aDnpQ] [-Tutf8] dir ...\n" + " %s [-DnpQ] [-Tutf8] -d dir [file ...]\n" + " %s [-Dnp] -u dir [file ...]\n" " %s [-Q] -t file ...\n", progname, progname, progname, progname, progname); @@ -912,13 +924,12 @@ nextlink: } } -static int +static void mlink_check(struct mpage *mpage, struct mlink *mlink) { - int match; + struct str *str; + unsigned int slot; - match = 1; - /* * Check whether the manual section given in a file * agrees with the directory where the file is located. @@ -929,11 +940,9 @@ mlink_check(struct mpage *mpage, struct mlink *mlink) */ if (FORM_SRC == mpage->form && - strcasecmp(mpage->sec, mlink->dsec)) { - match = 0; + strcasecmp(mpage->sec, mlink->dsec)) say(mlink->file, "Section \"%s\" manual in %s directory", mpage->sec, mlink->dsec); - } /* * Manual page directories exist for each kernel @@ -948,16 +957,28 @@ mlink_check(struct mpage *mpage, struct mlink *mlink) * on amd64, i386, sparc, and sparc64. */ - if (strcasecmp(mpage->arch, mlink->arch)) { - match = 0; + if (strcasecmp(mpage->arch, mlink->arch)) say(mlink->file, "Architecture \"%s\" manual in " "\"%s\" directory", mpage->arch, mlink->arch); - } - if (strcasecmp(mpage->title, mlink->name)) - match = 0; + /* + * XXX + * parse_cat() doesn't set TYPE_Nm and TYPE_NAME yet. + */ - return(match); + if (FORM_CAT == mpage->form) + return; + + /* + * Check whether this mlink + * appears as a name in the NAME section. + */ + + slot = ohash_qlookup(&strings, mlink->name); + str = ohash_find(&strings, slot); + assert(NULL != str); + if ( ! (TYPE_NAME & str->mask)) + say(mlink->file, "Name missing in NAME section"); } /* @@ -980,7 +1001,7 @@ mpages_merge(struct mchars *mc, struct mparse *mp) char *sodest; char *cp; pid_t child_pid; - int match, status; + int status; unsigned int pslot; enum mandoclevel lvl; @@ -1128,27 +1149,24 @@ mpages_merge(struct mchars *mc, struct mparse *mp) putkey(mpage, mlink->name, TYPE_Nm); } - if (warnings && !use_all) { - match = 0; - for (mlink = mpage->mlinks; mlink; - mlink = mlink->next) - if (mlink_check(mpage, mlink)) - match = 1; - } else - match = 1; - if (NULL != mdoc) { if (NULL != (cp = mdoc_meta(mdoc)->name)) putkey(mpage, cp, TYPE_Nm); assert(NULL == mpage->desc); parse_mdoc(mpage, mdoc_node(mdoc)); - putkey(mpage, NULL != mpage->desc ? - mpage->desc : mpage->mlinks->name, TYPE_Nd); + if (NULL == mpage->desc) + mpage->desc = mandoc_strdup( + mpage->mlinks->name); } else if (NULL != man) parse_man(mpage, man_node(man)); else parse_cat(mpage, fd[0]); + if (warnings && !use_all) + for (mlink = mpage->mlinks; mlink; + mlink = mlink->next) + mlink_check(mpage, mlink); + dbadd(mpage, mc); nextpage: @@ -1177,6 +1195,42 @@ nextpage: } static void +names_check(void) +{ + sqlite3_stmt *stmt; + const char *name, *sec, *arch, *key; + size_t i; + int irc; + + sqlite3_prepare_v2(db, + "SELECT name, sec, arch, key FROM (" + "SELECT key, pageid FROM keys " + "WHERE bits & ? AND NOT EXISTS (" + "SELECT pageid FROM mlinks " + "WHERE mlinks.pageid == keys.pageid " + "AND mlinks.name == keys.key" + ")" + ") JOIN (" + "SELECT * FROM mlinks GROUP BY pageid" + ") USING (pageid);", + -1, &stmt, NULL); + + i = 1; + SQL_BIND_INT64(stmt, i, TYPE_NAME); + + while (SQLITE_ROW == (irc = sqlite3_step(stmt))) { + name = sqlite3_column_text(stmt, 0); + sec = sqlite3_column_text(stmt, 1); + arch = sqlite3_column_text(stmt, 2); + key = sqlite3_column_text(stmt, 3); + say("", "%s(%s%s%s) lacks mlink \"%s\"", name, sec, + '\0' == *arch ? "" : "/", + '\0' == *arch ? "" : arch, key); + } + sqlite3_finalize(stmt); +} + +static void parse_cat(struct mpage *mpage, int fd) { FILE *stream; @@ -1245,7 +1299,6 @@ parse_cat(struct mpage *mpage, int fd) "Cannot find NAME section"); assert(NULL == mpage->desc); mpage->desc = mandoc_strdup(mpage->mlinks->name); - putkey(mpage, mpage->mlinks->name, TYPE_Nd); fclose(stream); free(title); return; @@ -1286,7 +1339,6 @@ parse_cat(struct mpage *mpage, int fd) assert(NULL == mpage->desc); mpage->desc = mandoc_strdup(p); - putkey(mpage, mpage->desc, TYPE_Nd); fclose(stream); free(title); } @@ -1389,7 +1441,7 @@ parse_man(struct mpage *mpage, const struct man_node * ('\\' == start[0] && '-' == start[1])) break; - putkey(mpage, start, TYPE_Nm); + putkey(mpage, start, TYPE_NAME | TYPE_Nm); if (' ' == byte) { start += sz + 1; @@ -1403,7 +1455,7 @@ parse_man(struct mpage *mpage, const struct man_node * } if (start == title) { - putkey(mpage, start, TYPE_Nm); + putkey(mpage, start, TYPE_NAME | TYPE_Nm); free(title); return; } @@ -1427,7 +1479,6 @@ parse_man(struct mpage *mpage, const struct man_node * assert(NULL == mpage->desc); mpage->desc = mandoc_strdup(start); - putkey(mpage, mpage->desc, TYPE_Nd); free(title); return; } @@ -1580,8 +1631,11 @@ static int parse_mdoc_Nm(struct mpage *mpage, const struct mdoc_node *n) { - return(SEC_NAME == n->sec || - (SEC_SYNOPSIS == n->sec && MDOC_HEAD == n->type)); + if (SEC_NAME == n->sec) + putmdockey(mpage, n->child, TYPE_NAME | TYPE_Nm); + else if (SEC_SYNOPSIS == n->sec && MDOC_HEAD == n->type) + putmdockey(mpage, n->child, TYPE_Nm); + return(0); } static int @@ -1850,20 +1904,46 @@ dbadd(struct mpage *mpage, struct mchars *mc) size_t i; unsigned int slot; - if (debug) - say(mpage->mlinks->file, "Adding to database"); + mlink = mpage->mlinks; - if (nodb) + if (nodb) { + while (NULL != mlink) { + fputs(mlink->name, stdout); + if (NULL == mlink->next || + strcmp(mlink->dsec, mlink->next->dsec) || + strcmp(mlink->fsec, mlink->next->fsec) || + strcmp(mlink->arch, mlink->next->arch)) { + putchar('('); + if ('\0' == *mlink->dsec) + fputs(mlink->fsec, stdout); + else + fputs(mlink->dsec, stdout); + if ('\0' != *mlink->arch) + printf("/%s", mlink->arch); + putchar(')'); + } + mlink = mlink->next; + if (NULL != mlink) + fputs(", ", stdout); + } + printf(" - %s\n", mpage->desc); return; + } + if (debug) + say(mlink->file, "Adding to database"); + 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_STEP(stmts[STMT_INSERT_PAGE]); mpage->recno = sqlite3_last_insert_rowid(db); sqlite3_reset(stmts[STMT_INSERT_PAGE]); - for (mlink = mpage->mlinks; mlink; mlink = mlink->next) + while (NULL != mlink) { dbadd_mlink(mlink); + mlink = mlink->next; + } for (key = ohash_first(&strings, &slot); NULL != key; key = ohash_next(&strings, &slot)) { @@ -2067,6 +2147,7 @@ dbopen(int real) create_tables: sql = "CREATE TABLE \"mpages\" (\n" + " \"desc\" TEXT NOT NULL,\n" " \"form\" INTEGER NOT NULL,\n" " \"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL\n" ");\n" @@ -2099,7 +2180,7 @@ prepare_statements: "sec=? AND arch=? AND name=?)"; sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_DELETE_PAGE], NULL); sql = "INSERT INTO mpages " - "(form) VALUES (?)"; + "(desc,form) VALUES (?,?)"; sqlite3_prepare_v2(db, sql, -1, &stmts[STMT_INSERT_PAGE], NULL); sql = "INSERT INTO mlinks " "(sec,arch,name,pageid) VALUES (?,?,?,?)";