]> git.cameronkatri.com Git - mandoc.git/blobdiff - mandocdb.c
Improve -Tascii output for Unicode escape sequences: For the first 512
[mandoc.git] / mandocdb.c
index 930133ccfdf55d762227c5817cd72afb257c2458..d0422420ae23d1e9880c37ec0bfcbd56f934423e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mandocdb.c,v 1.152 2014/06/20 02:24:40 schwarze Exp $ */
+/*     $Id: mandocdb.c,v 1.166 2014/10/12 20:32:39 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
+#include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#if HAVE_FTS
 #include <fts.h>
+#else
+#include "compat_fts.h"
+#endif
 #include <getopt.h>
 #include <limits.h>
 #include <stddef.h>
@@ -36,7 +39,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#ifdef HAVE_OHASH
+#if HAVE_OHASH
 #include <ohash.h>
 #else
 #include "compat_ohash.h"
@@ -80,12 +83,6 @@ enum op {
        OP_TEST /* change no databases, report potential problems */
 };
 
-enum   form {
-       FORM_NONE,  /* format is unknown */
-       FORM_SRC,   /* format is -man or -mdoc */
-       FORM_CAT    /* format is cat */
-};
-
 struct str {
        char            *rendered; /* key in UTF-8 or ASCII form */
        const struct mpage *mpage; /* if set, the owning parse */
@@ -101,24 +98,24 @@ struct     inodev {
 struct mpage {
        struct inodev    inodev;  /* used for hashing routine */
        int64_t          pageid;  /* pageid in mpages SQL table */
-       enum form        form;    /* format from file content */
        char            *sec;     /* section from file content */
        char            *arch;    /* architecture from file content */
        char            *title;   /* title from file content */
        char            *desc;    /* description from file content */
        struct mlink    *mlinks;  /* singly linked list */
+       int              form;    /* format from file content */
 };
 
 struct mlink {
        char             file[PATH_MAX]; /* filename rel. to manpath */
-       enum form        dform;   /* format from directory */
-       enum form        fform;   /* format from file name suffix */
        char            *dsec;    /* section from directory */
        char            *arch;    /* architecture from directory */
        char            *name;    /* name from file name (not empty) */
        char            *fsec;    /* section from file name suffix */
        struct mlink    *next;    /* singly linked list */
        struct mpage    *mpage;   /* parent */
+       int              dform;   /* format from directory */
+       int              fform;   /* format from file name suffix */
        int              gzip;    /* filename has a .gz suffix */
 };
 
@@ -172,7 +169,7 @@ static      void     putmdockey(const struct mpage *,
                        const struct mdoc_node *, uint64_t);
 static void     render_key(struct mchars *, struct str *);
 static void     say(const char *, const char *, ...);
-static int      set_basedir(const char *);
+static int      set_basedir(const char *, int);
 static int      treescan(void);
 static size_t   utf8(unsigned int, char [7]);
 
@@ -318,6 +315,7 @@ static      const struct mdoc_handler mdocs[MDOC_MAX] = {
        { NULL, 0 },  /* sp */
        { NULL, 0 },  /* %U */
        { NULL, 0 },  /* Ta */
+       { NULL, 0 },  /* ll */
 };
 
 
@@ -355,7 +353,8 @@ main(int argc, char *argv[])
         */
 #define        CHECKOP(_op, _ch) do \
        if (OP_DEFAULT != (_op)) { \
-               fprintf(stderr, "-%c: Conflicting option\n", (_ch)); \
+               fprintf(stderr, "%s: -%c: Conflicting option\n", \
+                   progname, (_ch)); \
                goto usage; \
        } while (/*CONSTCOND*/0)
 
@@ -391,8 +390,9 @@ main(int argc, char *argv[])
                        break;
                case 'T':
                        if (strcmp(optarg, "utf8")) {
-                               fprintf(stderr, "-T%s: Unsupported "
-                                   "output format\n", optarg);
+                               fprintf(stderr, "%s: -T%s: "
+                                   "Unsupported output format\n",
+                                   progname, optarg);
                                goto usage;
                        }
                        write_utf8 = 1;
@@ -419,7 +419,8 @@ main(int argc, char *argv[])
        argv += optind;
 
        if (OP_CONFFILE == op && argc > 0) {
-               fprintf(stderr, "-C: Too many arguments\n");
+               fprintf(stderr, "%s: -C: Too many arguments\n",
+                   progname);
                goto usage;
        }
 
@@ -436,7 +437,7 @@ main(int argc, char *argv[])
                 * Most of these deal with a specific directory.
                 * Jump into that directory first.
                 */
-               if (OP_TEST != op && 0 == set_basedir(path_arg))
+               if (OP_TEST != op && 0 == set_basedir(path_arg, 1))
                        goto out;
 
                if (dbopen(1)) {
@@ -502,12 +503,12 @@ main(int argc, char *argv[])
                                ohash_init(&mlinks, 6, &mlinks_info);
                        }
 
-                       if (0 == set_basedir(dirs.paths[j]))
-                               goto out;
+                       if (0 == set_basedir(dirs.paths[j], argc > 0))
+                               continue;
                        if (0 == treescan())
-                               goto out;
+                               continue;
                        if (0 == dbopen(0))
-                               goto out;
+                               continue;
 
                        mpages_merge(mc, mp);
                        if (warnings && !nodb &&
@@ -832,6 +833,7 @@ filescan(const char *file)
        }
 
        mlink = mandoc_calloc(1, sizeof(struct mlink));
+       mlink->dform = FORM_NONE;
        if (strlcpy(mlink->file, start, sizeof(mlink->file)) >=
            sizeof(mlink->file)) {
                say(start, "Filename too long");
@@ -1075,7 +1077,6 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
 {
        char                     any[] = "any";
        struct ohash_info        str_info;
-       int                      fd[2];
        struct mpage            *mpage, *mpage_dest;
        struct mlink            *mlink, *mlink_dest;
        struct mdoc             *mdoc;
@@ -1083,7 +1084,7 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
        char                    *sodest;
        char                    *cp;
        pid_t                    child_pid;
-       int                      status;
+       int                      fd;
        unsigned int             pslot;
        enum mandoclevel         lvl;
 
@@ -1111,38 +1112,11 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
                man = NULL;
                sodest = NULL;
                child_pid = 0;
-               fd[0] = -1;
-               fd[1] = -1;
-
-               if (mpage->mlinks->gzip) {
-                       if (-1 == pipe(fd)) {
-                               exitcode = (int)MANDOCLEVEL_SYSERR;
-                               say(mpage->mlinks->file, "&pipe gunzip");
-                               goto nextpage;
-                       }
-                       switch (child_pid = fork()) {
-                       case -1:
-                               exitcode = (int)MANDOCLEVEL_SYSERR;
-                               say(mpage->mlinks->file, "&fork gunzip");
-                               child_pid = 0;
-                               close(fd[1]);
-                               close(fd[0]);
-                               goto nextpage;
-                       case 0:
-                               close(fd[0]);
-                               if (-1 == dup2(fd[1], STDOUT_FILENO)) {
-                                       say(mpage->mlinks->file,
-                                           "&dup gunzip");
-                                       exit(1);
-                               }
-                               execlp("gunzip", "gunzip", "-c",
-                                   mpage->mlinks->file, NULL);
-                               say(mpage->mlinks->file, "&exec gunzip");
-                               exit(1);
-                       default:
-                               close(fd[1]);
-                               break;
-                       }
+
+               mparse_open(mp, &fd, mpage->mlinks->file, &child_pid);
+               if (fd == -1) {
+                       say(mpage->mlinks->file, "&open");
+                       goto nextpage;
                }
 
                /*
@@ -1152,7 +1126,7 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
                 */
                if (FORM_CAT != mpage->mlinks->dform ||
                    FORM_CAT != mpage->mlinks->fform) {
-                       lvl = mparse_readfd(mp, fd[0], mpage->mlinks->file);
+                       lvl = mparse_readfd(mp, fd, mpage->mlinks->file);
                        if (lvl < MANDOCLEVEL_FATAL)
                                mparse_result(mp, &mdoc, &man, &sodest);
                }
@@ -1195,8 +1169,9 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
                        goto nextpage;
                } else if (NULL != mdoc) {
                        mpage->form = FORM_SRC;
-                       mpage->sec =
-                           mandoc_strdup(mdoc_meta(mdoc)->msec);
+                       mpage->sec = mdoc_meta(mdoc)->msec;
+                       mpage->sec = mandoc_strdup(
+                           NULL == mpage->sec ? "" : mpage->sec);
                        mpage->arch = mdoc_meta(mdoc)->arch;
                        mpage->arch = mandoc_strdup(
                            NULL == mpage->arch ? "" : mpage->arch);
@@ -1219,9 +1194,11 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
                        mpage->title =
                            mandoc_strdup(mpage->mlinks->name);
                }
+               if (mpage->mlinks->gzip)
+                       mpage->form |= FORM_GZ;
                putkey(mpage, mpage->sec, TYPE_sec);
-               putkey(mpage, '\0' == *mpage->arch ?
-                   any : mpage->arch, TYPE_arch);
+               if (*mpage->arch != '\0')
+                       putkey(mpage, mpage->arch, TYPE_arch);
 
                for (mlink = mpage->mlinks; mlink; mlink = mlink->next) {
                        if ('\0' != *mlink->dsec)
@@ -1241,7 +1218,7 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
                } else if (NULL != man)
                        parse_man(mpage, man_node(man));
                else
-                       parse_cat(mpage, fd[0]);
+                       parse_cat(mpage, fd);
                if (NULL == mpage->desc)
                        mpage->desc = mandoc_strdup(mpage->mlinks->name);
 
@@ -1253,21 +1230,10 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
                dbadd(mpage, mc);
 
 nextpage:
-               if (child_pid) {
-                       if (-1 == waitpid(child_pid, &status, 0)) {
-                               exitcode = (int)MANDOCLEVEL_SYSERR;
-                               say(mpage->mlinks->file, "&wait gunzip");
-                       } else if (WIFSIGNALED(status)) {
-                               exitcode = (int)MANDOCLEVEL_SYSERR;
-                               say(mpage->mlinks->file,
-                                   "gunzip died from signal %d",
-                                   WTERMSIG(status));
-                       } else if (WEXITSTATUS(status)) {
-                               exitcode = (int)MANDOCLEVEL_SYSERR;
-                               say(mpage->mlinks->file,
-                                   "gunzip failed with code %d",
-                                   WEXITSTATUS(status));
-                       }
+               if (child_pid &&
+                   mparse_wait(mp, child_pid) != MANDOCLEVEL_OK) {
+                       exitcode = (int)MANDOCLEVEL_SYSERR;
+                       say(mpage->mlinks->file, "&wait gunzip");
                }
                ohash_delete(&strings);
                ohash_delete(&names);
@@ -1303,10 +1269,10 @@ names_check(void)
                say("", "%s", sqlite3_errmsg(db));
 
        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);
+               name = (const char *)sqlite3_column_text(stmt, 0);
+               sec  = (const char *)sqlite3_column_text(stmt, 1);
+               arch = (const char *)sqlite3_column_text(stmt, 2);
+               key  = (const char *)sqlite3_column_text(stmt, 3);
                say("", "%s(%s%s%s) lacks mlink \"%s\"", name, sec,
                    '\0' == *arch ? "" : "/",
                    '\0' == *arch ? "" : arch, key);
@@ -1325,6 +1291,8 @@ parse_cat(struct mpage *mpage, int fd)
            fopen(mpage->mlinks->file, "r") :
            fdopen(fd, "r");
        if (NULL == stream) {
+               if (-1 != fd)
+                       close(fd);
                if (warnings)
                        say(mpage->mlinks->file, "&fopen");
                return;
@@ -1768,7 +1736,7 @@ putkeys(const struct mpage *mpage,
                htab = &strings;
                if (debug > 1)
                    for (i = 0; i < mansearch_keymax; i++)
-                       if (1 << i & v)
+                       if ((uint64_t)1 << i & v)
                            say(mpage->mlinks->file,
                                "Adding key %s=%*s",
                                mansearch_keynames[i], sz, cp);
@@ -1975,6 +1943,13 @@ dbadd_mlink(const struct mlink *mlink)
        SQL_BIND_INT64(stmts[STMT_INSERT_LINK], i, mlink->mpage->pageid);
        SQL_STEP(stmts[STMT_INSERT_LINK]);
        sqlite3_reset(stmts[STMT_INSERT_LINK]);
+
+       i = 1;
+       SQL_BIND_INT64(stmts[STMT_INSERT_NAME], i, NAME_FILE);
+       SQL_BIND_TEXT(stmts[STMT_INSERT_NAME], i, mlink->name);
+       SQL_BIND_INT64(stmts[STMT_INSERT_NAME], i, mlink->mpage->pageid);
+       SQL_STEP(stmts[STMT_INSERT_NAME]);
+       sqlite3_reset(stmts[STMT_INSERT_NAME]);
 }
 
 /*
@@ -2041,7 +2016,7 @@ dbadd(struct mpage *mpage, struct mchars *mc)
 
        i = 1;
        SQL_BIND_TEXT(stmts[STMT_INSERT_PAGE], i, key->rendered);
-       SQL_BIND_INT(stmts[STMT_INSERT_PAGE], i, FORM_SRC == mpage->form);
+       SQL_BIND_INT(stmts[STMT_INSERT_PAGE], i, mpage->form);
        SQL_STEP(stmts[STMT_INSERT_PAGE]);
        mpage->pageid = sqlite3_last_insert_rowid(db);
        sqlite3_reset(stmts[STMT_INSERT_PAGE]);
@@ -2338,7 +2313,7 @@ prepare_statements:
            "PRAGMA synchronous = OFF", NULL, NULL, NULL)) {
                exitcode = (int)MANDOCLEVEL_SYSERR;
                say(MANDOC_DB, "PRAGMA synchronous: %s",
-               sqlite3_errmsg(db));
+                   sqlite3_errmsg(db));
                sqlite3_close(db);
                return(0);
        }
@@ -2369,7 +2344,7 @@ hash_free(void *p, void *arg)
 }
 
 static int
-set_basedir(const char *targetdir)
+set_basedir(const char *targetdir, int report_baddir)
 {
        static char      startdir[PATH_MAX];
        static int       getcwd_status;  /* 1 = ok, 2 = failure */
@@ -2422,12 +2397,16 @@ set_basedir(const char *targetdir)
         * we can reliably check whether files are inside.
         */
        if (NULL == realpath(targetdir, basedir)) {
-               exitcode = (int)MANDOCLEVEL_BADARG;
-               say("", "&%s: realpath", targetdir);
+               if (report_baddir || errno != ENOENT) {
+                       exitcode = (int)MANDOCLEVEL_BADARG;
+                       say("", "&%s: realpath", targetdir);
+               }
                return(0);
        } else if (-1 == chdir(basedir)) {
-               exitcode = (int)MANDOCLEVEL_BADARG;
-               say("", "&chdir");
+               if (report_baddir || errno != ENOENT) {
+                       exitcode = (int)MANDOCLEVEL_BADARG;
+                       say("", "&chdir");
+               }
                return(0);
        }
        chdir_status = 1;