]> git.cameronkatri.com Git - mandoc.git/blobdiff - main.c
Support nesting of elements with next-line scope.
[mandoc.git] / main.c
diff --git a/main.c b/main.c
index efee75386a1f84ea05b2b6179844f59074370662..cad227507eaf34302dd3c86e7646d25b69c96097 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,7 +1,7 @@
-/*     $Id: main.c,v 1.295 2017/07/01 12:02:31 schwarze Exp $ */
+/*     $Id: main.c,v 1.308 2018/08/23 19:33:27 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -19,7 +19,9 @@
 #include "config.h"
 
 #include <sys/types.h>
 #include "config.h"
 
 #include <sys/types.h>
+#include <sys/ioctl.h>
 #include <sys/param.h> /* MACHINE */
 #include <sys/param.h> /* MACHINE */
+#include <sys/termios.h>
 #include <sys/wait.h>
 
 #include <assert.h>
 #include <sys/wait.h>
 
 #include <assert.h>
@@ -111,6 +113,7 @@ static      const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
 static char              help_arg[] = "help";
 static char             *help_argv[] = {help_arg, NULL};
 static enum mandoclevel  rc;
 static char              help_arg[] = "help";
 static char             *help_argv[] = {help_arg, NULL};
 static enum mandoclevel  rc;
+static FILE             *mmsg_stream;
 
 
 int
 
 
 int
@@ -119,6 +122,7 @@ main(int argc, char *argv[])
        struct manconf   conf;
        struct mansearch search;
        struct curparse  curp;
        struct manconf   conf;
        struct mansearch search;
        struct curparse  curp;
+       struct winsize   ws;
        struct tag_files *tag_files;
        struct manpage  *res, *resp;
        const char      *progname, *sec, *thisarg;
        struct tag_files *tag_files;
        struct manpage  *res, *resp;
        const char      *progname, *sec, *thisarg;
@@ -128,7 +132,7 @@ main(int argc, char *argv[])
        size_t           i, sz;
        int              prio, best_prio;
        enum outmode     outmode;
        size_t           i, sz;
        int              prio, best_prio;
        enum outmode     outmode;
-       int              fd;
+       int              fd, startdir;
        int              show_usage;
        int              options;
        int              use_pager;
        int              show_usage;
        int              options;
        int              use_pager;
@@ -190,6 +194,7 @@ main(int argc, char *argv[])
        curp.mmin = MANDOCERR_MAX;
        curp.outopts = &conf.output;
        options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
        curp.mmin = MANDOCERR_MAX;
        curp.outopts = &conf.output;
        options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
+       mmsg_stream = stderr;
 
        use_pager = 1;
        tag_files = NULL;
 
        use_pager = 1;
        tag_files = NULL;
@@ -314,6 +319,16 @@ main(int argc, char *argv[])
            !isatty(STDOUT_FILENO))
                use_pager = 0;
 
            !isatty(STDOUT_FILENO))
                use_pager = 0;
 
+       if (use_pager &&
+           (conf.output.width == 0 || conf.output.indent == 0) &&
+           ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 &&
+           ws.ws_col > 1) {
+               if (conf.output.width == 0 && ws.ws_col < 79)
+                       conf.output.width = ws.ws_col - 1;
+               if (conf.output.indent == 0 && ws.ws_col < 66)
+                       conf.output.indent = 3;
+       }
+
 #if HAVE_PLEDGE
        if (!use_pager)
                if (pledge("stdio rpath", NULL) == -1)
 #if HAVE_PLEDGE
        if (!use_pager)
                if (pledge("stdio rpath", NULL) == -1)
@@ -372,15 +387,34 @@ main(int argc, char *argv[])
                    argc, argv, &res, &sz))
                        usage(search.argmode);
 
                    argc, argv, &res, &sz))
                        usage(search.argmode);
 
-               if (sz == 0) {
-                       if (search.argmode == ARG_NAME)
-                               fs_search(&search, &conf.manpath,
-                                   argc, argv, &res, &sz);
-                       else
-                               warnx("nothing appropriate");
+               if (sz == 0 && search.argmode == ARG_NAME)
+                       fs_search(&search, &conf.manpath,
+                           argc, argv, &res, &sz);
+
+               if (search.argmode == ARG_NAME) {
+                       for (c = 0; c < argc; c++) {
+                               if (strchr(argv[c], '/') == NULL)
+                                       continue;
+                               if (access(argv[c], R_OK) == -1) {
+                                       warn("%s", argv[c]);
+                                       continue;
+                               }
+                               res = mandoc_reallocarray(res,
+                                   sz + 1, sizeof(*res));
+                               res[sz].file = mandoc_strdup(argv[c]);
+                               res[sz].names = NULL;
+                               res[sz].output = NULL;
+                               res[sz].ipath = SIZE_MAX;
+                               res[sz].bits = 0;
+                               res[sz].sec = 10;
+                               res[sz].form = FORM_SRC;
+                               sz++;
+                       }
                }
 
                if (sz == 0) {
                }
 
                if (sz == 0) {
+                       if (search.argmode != ARG_NAME)
+                               warnx("nothing appropriate");
                        rc = MANDOCLEVEL_BADARG;
                        goto out;
                }
                        rc = MANDOCLEVEL_BADARG;
                        goto out;
                }
@@ -452,19 +486,35 @@ main(int argc, char *argv[])
        curp.mp = mparse_alloc(options, curp.mmin, mmsg,
            curp.os_e, curp.os_s);
 
        curp.mp = mparse_alloc(options, curp.mmin, mmsg,
            curp.os_e, curp.os_s);
 
-       /*
-        * Conditionally start up the lookaside buffer before parsing.
-        */
-       if (OUTT_MAN == curp.outtype)
-               mparse_keep(curp.mp);
-
        if (argc < 1) {
                if (use_pager)
                        tag_files = tag_init();
                parse(&curp, STDIN_FILENO, "<stdin>");
        }
 
        if (argc < 1) {
                if (use_pager)
                        tag_files = tag_init();
                parse(&curp, STDIN_FILENO, "<stdin>");
        }
 
+       /*
+        * Remember the original working directory, if possible.
+        * This will be needed if some names on the command line
+        * are page names and some are relative file names.
+        * Do not error out if the current directory is not
+        * readable: Maybe it won't be needed after all.
+        */
+       startdir = open(".", O_RDONLY | O_DIRECTORY);
+
        while (argc > 0) {
        while (argc > 0) {
+
+               /*
+                * Changing directories is not needed in ARG_FILE mode.
+                * Do it on a best-effort basis.  Even in case of
+                * failure, some functionality may still work.
+                */
+               if (resp != NULL) {
+                       if (resp->ipath != SIZE_MAX)
+                               (void)chdir(conf.manpath.paths[resp->ipath]);
+                       else if (startdir != -1)
+                               (void)fchdir(startdir);
+               }
+
                fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
                if (fd != -1) {
                        if (use_pager) {
                fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
                if (fd != -1) {
                        if (use_pager) {
@@ -474,14 +524,23 @@ main(int argc, char *argv[])
 
                        if (resp == NULL)
                                parse(&curp, fd, *argv);
 
                        if (resp == NULL)
                                parse(&curp, fd, *argv);
-                       else if (resp->form == FORM_SRC) {
-                               /* For .so only; ignore failure. */
-                               chdir(conf.manpath.paths[resp->ipath]);
+                       else if (resp->form == FORM_SRC)
                                parse(&curp, fd, resp->file);
                                parse(&curp, fd, resp->file);
-                       else
+                       else
                                passthrough(resp->file, fd,
                                    conf.output.synopsisonly);
 
                                passthrough(resp->file, fd,
                                    conf.output.synopsisonly);
 
+                       if (ferror(stdout)) {
+                               if (tag_files != NULL) {
+                                       warn("%s", tag_files->ofn);
+                                       tag_unlink();
+                                       tag_files = NULL;
+                               } else
+                                       warn("stdout");
+                               rc = MANDOCLEVEL_SYSERR;
+                               break;
+                       }
+
                        if (argc > 1 && curp.outtype <= OUTT_UTF8) {
                                if (curp.outdata == NULL)
                                        outdata_alloc(&curp);
                        if (argc > 1 && curp.outtype <= OUTT_UTF8) {
                                if (curp.outdata == NULL)
                                        outdata_alloc(&curp);
@@ -500,6 +559,10 @@ main(int argc, char *argv[])
                if (--argc)
                        mparse_reset(curp.mp);
        }
                if (--argc)
                        mparse_reset(curp.mp);
        }
+       if (startdir != -1) {
+               (void)fchdir(startdir);
+               close(startdir);
+       }
 
        if (curp.outdata != NULL) {
                switch (curp.outtype) {
 
        if (curp.outdata != NULL) {
                switch (curp.outtype) {
@@ -663,14 +726,23 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
        if (globres == 0)
                file = mandoc_strdup(*globinfo.gl_pathv);
        globfree(&globinfo);
        if (globres == 0)
                file = mandoc_strdup(*globinfo.gl_pathv);
        globfree(&globinfo);
-       if (globres != 0)
+       if (globres == 0)
+               goto found;
+       if (res != NULL || ipath + 1 != paths->sz)
                return 0;
 
                return 0;
 
+       mandoc_asprintf(&file, "%s.%s", name, sec);
+       globres = access(file, R_OK);
+       free(file);
+       return globres != -1;
+
 found:
        warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s",
            name, sec, BINM_MAKEWHATIS, paths->paths[ipath]);
 found:
        warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s",
            name, sec, BINM_MAKEWHATIS, paths->paths[ipath]);
-       if (res == NULL)
+       if (res == NULL) {
+               free(file);
                return 1;
                return 1;
+       }
        *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
        page = *res + (*ressz - 1);
        page->file = file;
        *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
        page = *res + (*ressz - 1);
        page->file = file;
@@ -711,8 +783,15 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
                                    cfg->firstmatch)
                                        return 1;
                }
                                    cfg->firstmatch)
                                        return 1;
                }
-               if (res != NULL && *ressz == lastsz)
-                       warnx("No entry for %s in the manual.", *argv);
+               if (res != NULL && *ressz == lastsz &&
+                   strchr(*argv, '/') == NULL) {
+                       if (cfg->sec == NULL)
+                               warnx("No entry for %s in the manual.",
+                                   *argv);
+                       else
+                               warnx("No entry for %s in section %s "
+                                   "of the manual.", *argv, cfg->sec);
+               }
                lastsz = *ressz;
                argv++;
                argc--;
                lastsz = *ressz;
                argv++;
                argc--;
@@ -754,8 +833,7 @@ parse(struct curparse *curp, int fd, const char *file)
 
        if (man == NULL)
                return;
 
        if (man == NULL)
                return;
-       if (curp->mmin < MANDOCERR_STYLE)
-               mandoc_xr_reset();
+       mandoc_xr_reset();
        if (man->macroset == MACROSET_MDOC) {
                if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
                        mdoc_validate(man);
        if (man->macroset == MACROSET_MDOC) {
                if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
                        mdoc_validate(man);
@@ -794,7 +872,7 @@ parse(struct curparse *curp, int fd, const char *file)
                        tree_man(curp->outdata, man);
                        break;
                case OUTT_MAN:
                        tree_man(curp->outdata, man);
                        break;
                case OUTT_MAN:
-                       man_man(curp->outdata, man);
+                       mparse_copy(curp->mp);
                        break;
                case OUTT_PDF:
                case OUTT_ASCII:
                        break;
                case OUTT_PDF:
                case OUTT_ASCII:
@@ -807,7 +885,8 @@ parse(struct curparse *curp, int fd, const char *file)
                        break;
                }
        }
                        break;
                }
        }
-       check_xr(file);
+       if (curp->mmin < MANDOCERR_STYLE)
+               check_xr(file);
        mparse_updaterc(curp->mp, &rc);
 }
 
        mparse_updaterc(curp->mp, &rc);
 }
 
@@ -824,6 +903,8 @@ check_xr(const char *file)
                manpath_base(&paths);
 
        for (xr = mandoc_xr_get(); xr != NULL; xr = xr->next) {
                manpath_base(&paths);
 
        for (xr = mandoc_xr_get(); xr != NULL; xr = xr->next) {
+               if (xr->line == -1)
+                       continue;
                search.arch = NULL;
                search.sec = xr->sec;
                search.outkey = NULL;
                search.arch = NULL;
                search.sec = xr->sec;
                search.outkey = NULL;
@@ -833,7 +914,11 @@ check_xr(const char *file)
                        continue;
                if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz))
                        continue;
                        continue;
                if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz))
                        continue;
-               mandoc_asprintf(&cp, "Xr %s %s", xr->name, xr->sec);
+               if (xr->count == 1)
+                       mandoc_asprintf(&cp, "Xr %s %s", xr->name, xr->sec);
+               else
+                       mandoc_asprintf(&cp, "Xr %s %s (%d times)",
+                           xr->name, xr->sec, xr->count);
                mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE,
                    file, xr->line, xr->pos + 1, cp);
                free(cp);
                mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE,
                    file, xr->line, xr->pos + 1, cp);
                free(cp);
@@ -979,6 +1064,7 @@ toptions(struct curparse *curp, char *arg)
        else if (0 == strcmp(arg, "lint")) {
                curp->outtype = OUTT_LINT;
                curp->mmin = MANDOCERR_BASE;
        else if (0 == strcmp(arg, "lint")) {
                curp->outtype = OUTT_LINT;
                curp->mmin = MANDOCERR_BASE;
+               mmsg_stream = stdout;
        } else if (0 == strcmp(arg, "tree"))
                curp->outtype = OUTT_TREE;
        else if (0 == strcmp(arg, "man"))
        } else if (0 == strcmp(arg, "tree"))
                curp->outtype = OUTT_TREE;
        else if (0 == strcmp(arg, "man"))
@@ -1068,22 +1154,21 @@ mmsg(enum mandocerr t, enum mandoclevel lvl,
 {
        const char      *mparse_msg;
 
 {
        const char      *mparse_msg;
 
-       fprintf(stderr, "%s: %s:", getprogname(),
+       fprintf(mmsg_stream, "%s: %s:", getprogname(),
            file == NULL ? "<stdin>" : file);
 
        if (line)
            file == NULL ? "<stdin>" : file);
 
        if (line)
-               fprintf(stderr, "%d:%d:", line, col + 1);
+               fprintf(mmsg_stream, "%d:%d:", line, col + 1);
 
 
-       fprintf(stderr, " %s",
-           t < MANDOCERR_STYLE ? "BASE" : mparse_strlevel(lvl));
+       fprintf(mmsg_stream, " %s", mparse_strlevel(lvl));
 
        if ((mparse_msg = mparse_strerror(t)) != NULL)
 
        if ((mparse_msg = mparse_strerror(t)) != NULL)
-               fprintf(stderr, ": %s", mparse_msg);
+               fprintf(mmsg_stream, ": %s", mparse_msg);
 
        if (msg)
 
        if (msg)
-               fprintf(stderr, ": %s", msg);
+               fprintf(mmsg_stream, ": %s", msg);
 
 
-       fputc('\n', stderr);
+       fputc('\n', mmsg_stream);
 }
 
 static pid_t
 }
 
 static pid_t
@@ -1156,7 +1241,7 @@ spawn_pager(struct tag_files *tag_files)
        if (dup2(tag_files->ofd, STDOUT_FILENO) == -1)
                err((int)MANDOCLEVEL_SYSERR, "pager stdout");
        close(tag_files->ofd);
        if (dup2(tag_files->ofd, STDOUT_FILENO) == -1)
                err((int)MANDOCLEVEL_SYSERR, "pager stdout");
        close(tag_files->ofd);
-       close(tag_files->tfd);
+       assert(tag_files->tfd == -1);
 
        /* Do not start the pager before controlling the terminal. */
 
 
        /* Do not start the pager before controlling the terminal. */