Print this page
9718 update mandoc to 1.14.4

@@ -1,9 +1,9 @@
-/*      $Id: main.c,v 1.301 2017/07/26 10:21:55 schwarze Exp $ */
+/*      $Id: main.c,v 1.306 2018/05/14 14:10:23 schwarze Exp $ */
 /*
  * 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
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.

@@ -17,11 +17,13 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include "config.h"
 
 #include <sys/types.h>
+#include <sys/ioctl.h>
 #include <sys/param.h>  /* MACHINE */
+#include <sys/termios.h>
 #include <sys/wait.h>
 
 #include <assert.h>
 #include <ctype.h>
 #if HAVE_ERR

@@ -118,20 +120,21 @@
 main(int argc, char *argv[])
 {
         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;
         char            *conf_file, *defpaths, *auxpaths;
         char            *oarg;
         unsigned char   *uc;
         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              status, signum;
         int              c;

@@ -314,10 +317,20 @@
         if (outmode == OUTMODE_FLN ||
             outmode == OUTMODE_LST ||
             !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)
                         err((int)MANDOCLEVEL_SYSERR, "pledge");
 #endif

@@ -372,19 +385,38 @@
                 manconf_parse(&conf, conf_file, defpaths, auxpaths);
                 if ( ! mansearch(&search, &conf.manpath,
                     argc, argv, &res, &sz))
                         usage(search.argmode);
 
-                if (sz == 0) {
-                        if (search.argmode == ARG_NAME)
+                if (sz == 0 && search.argmode == ARG_NAME)
                                 fs_search(&search, &conf.manpath,
                                     argc, argv, &res, &sz);
-                        else
-                                warnx("nothing appropriate");
+
+                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 (search.argmode != ARG_NAME)
+                                warnx("nothing appropriate");
                         rc = MANDOCLEVEL_BADARG;
                         goto out;
                 }
 
                 /*

@@ -464,28 +496,59 @@
                 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) {
+
+                /*
+                 * 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) {
                                 tag_files = tag_init();
                                 use_pager = 0;
                         }
 
                         if (resp == NULL)
                                 parse(&curp, fd, *argv);
-                        else if (resp->form == FORM_SRC) {
-                                /* For .so only; ignore failure. */
-                                (void)chdir(conf.manpath.paths[resp->ipath]);
+                        else if (resp->form == FORM_SRC)
                                 parse(&curp, fd, resp->file);
-                        } else
+                        else
                                 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);
                                 terminal_sepline(curp.outdata);
                         }

@@ -500,10 +563,14 @@
                 else
                         argv++;
                 if (--argc)
                         mparse_reset(curp.mp);
         }
+        if (startdir != -1) {
+                (void)fchdir(startdir);
+                close(startdir);
+        }
 
         if (curp.outdata != NULL) {
                 switch (curp.outtype) {
                 case OUTT_HTML:
                         html_free(curp.outdata);

@@ -720,11 +787,12 @@
                                 if (fs_lookup(paths, ipath, sections[isec],
                                     cfg->arch, *argv, res, ressz) &&
                                     cfg->firstmatch)
                                         return 1;
                 }
-                if (res != NULL && *ressz == lastsz)
+                if (res != NULL && *ressz == lastsz &&
+                    strchr(*argv, '/') == NULL)
                         warnx("No entry for %s in the manual.", *argv);
                 lastsz = *ressz;
                 argv++;
                 argc--;
         }

@@ -1171,11 +1239,11 @@
         /* The child process becomes the pager. */
 
         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. */
 
         while (tcgetpgrp(STDOUT_FILENO) != getpid())
                 nanosleep(&timeout, NULL);