aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2020-04-02 22:12:55 +0000
committerIngo Schwarze <schwarze@openbsd.org>2020-04-02 22:12:55 +0000
commit4f3f1706132956d635c2c2cefb04b0418c6f0f18 (patch)
tree6c68a2e2991f2fd5e47e9443ee208b4f5c769924
parent735c1e543343b638b339077b91a5874260cdf14b (diff)
downloadmandoc-4f3f1706132956d635c2c2cefb04b0418c6f0f18.tar.gz
mandoc-4f3f1706132956d635c2c2cefb04b0418c6f0f18.tar.zst
mandoc-4f3f1706132956d635c2c2cefb04b0418c6f0f18.zip
When the last file formatted yielded no tags, the tags file got
deleted before starting the pager, even when earlier input files had written to it; thanks to weerd@ for reporting that bug. Since we now generate tags for section headers, we almost always generate at least some. Consequently, while fixing the above bug, simplify the code by never deleting the tags file before the pager exits, not even in the rare case that the file happens to be empty. Hence, this patch is -75 +63 LOC even though it fixes two bugs. While deleting the output files belongs after exit from the pager, closing them should be done before it is started. Collect the related code, which was scattered in various places, to where it belongs, in a dedicated function in the term_tag.c module. As a side benefit, never fclose(2) stdout, only dup2(2) to it. Similarly, when the -O tag argument wasn't found in the last file formatted, there was a complaint about "no such tag" even when the argument did occur in earlier files. Fix that by looking for a matching tag after every formatted file rather than just once at the very end. Given that command line arguments aren't properties of the file(s) being formatted, that check is a job for the main program, not for the formatters, so while fixing the check, move it from term_tag.c to main.c.
-rw-r--r--main.c56
-rw-r--r--manconf.h8
-rw-r--r--tag.c16
-rw-r--r--tag.h14
-rw-r--r--term_tag.c54
-rw-r--r--term_tag.h7
6 files changed, 70 insertions, 85 deletions
diff --git a/main.c b/main.c
index 486db0d0..06045b19 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c,v 1.347 2020/03/28 16:18:43 schwarze Exp $ */
+/* $Id: main.c,v 1.348 2020/04/02 22:12:55 schwarze Exp $ */
/*
* Copyright (c) 2010-2012, 2014-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -54,6 +54,7 @@
#include "mdoc.h"
#include "man.h"
#include "mandoc_parse.h"
+#include "tag.h"
#include "term_tag.h"
#include "main.h"
#include "manconf.h"
@@ -107,8 +108,8 @@ static void parse(struct mparse *, int, const char *,
static void passthrough(int, int);
static void process_onefile(struct mparse *, struct manpage *,
int, struct outstate *, struct manconf *);
-static void run_pager(struct tag_files *);
-static pid_t spawn_pager(struct tag_files *);
+static void run_pager(struct tag_files *, char *);
+static pid_t spawn_pager(struct tag_files *, char *);
static void usage(enum argmode) __attribute__((__noreturn__));
static int woptions(char *, enum mandoc_os *, int *);
@@ -609,7 +610,10 @@ main(int argc, char *argv[])
(void)fchdir(startdir);
close(startdir);
}
- term_tag_finish();
+ if (conf.output.tag != NULL && conf.output.tag_found == 0) {
+ mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", conf.output.tag);
+ conf.output.tag = NULL;
+ }
if (outst.outdata != NULL) {
switch (outst.outtype) {
case OUTT_HTML:
@@ -638,8 +642,8 @@ out:
manconf_free(&conf);
if (outst.tag_files != NULL) {
- fclose(stdout);
- run_pager(outst.tag_files);
+ if (term_tag_close() != -1)
+ run_pager(outst.tag_files, conf.output.tag);
term_tag_unlink();
} else if (outst.had_output && outst.outtype != OUTT_LINT)
mandoc_msg_summary();
@@ -833,7 +837,7 @@ process_onefile(struct mparse *mp, struct manpage *resp, int startdir,
if (outst->use_pager) {
outst->use_pager = 0;
- outst->tag_files = term_tag_init(conf->output.tag);
+ outst->tag_files = term_tag_init();
}
if (outst->had_output && outst->outtype <= OUTT_UTF8) {
if (outst->outdata == NULL)
@@ -947,6 +951,9 @@ parse(struct mparse *mp, int fd, const char *file,
break;
}
}
+ if (outconf->tag != NULL && outconf->tag_found == 0 &&
+ tag_exists(outconf->tag))
+ outconf->tag_found = 1;
if (mandoc_msg_getmin() < MANDOCERR_STYLE)
check_xr();
}
@@ -1137,7 +1144,7 @@ woptions(char *arg, enum mandoc_os *os_e, int *wstop)
* then fork the pager and wait for the user to close it.
*/
static void
-run_pager(struct tag_files *tag_files)
+run_pager(struct tag_files *tag_files, char *tag_target)
{
int signum, status;
pid_t man_pgid, tc_pgid;
@@ -1152,10 +1159,10 @@ run_pager(struct tag_files *tag_files)
for (;;) {
/* Stop here until moved to the foreground. */
- tc_pgid = tcgetpgrp(tag_files->ofd);
+ tc_pgid = tcgetpgrp(STDOUT_FILENO);
if (tc_pgid != man_pgid) {
if (tc_pgid == pager_pid) {
- (void)tcsetpgrp(tag_files->ofd, man_pgid);
+ (void)tcsetpgrp(STDOUT_FILENO, man_pgid);
if (signum == SIGTTIN)
continue;
} else
@@ -1167,10 +1174,10 @@ run_pager(struct tag_files *tag_files)
/* Once in the foreground, activate the pager. */
if (pager_pid) {
- (void)tcsetpgrp(tag_files->ofd, pager_pid);
+ (void)tcsetpgrp(STDOUT_FILENO, pager_pid);
kill(pager_pid, SIGCONT);
} else
- pager_pid = spawn_pager(tag_files);
+ pager_pid = spawn_pager(tag_files, tag_target);
/* Wait for the pager to stop or exit. */
@@ -1191,7 +1198,7 @@ run_pager(struct tag_files *tag_files)
}
static pid_t
-spawn_pager(struct tag_files *tag_files)
+spawn_pager(struct tag_files *tag_files, char *tag_target)
{
const struct timespec timeout = { 0, 100000000 }; /* 0.1s */
#define MAX_PAGER_ARGS 16
@@ -1204,6 +1211,9 @@ spawn_pager(struct tag_files *tag_files)
int argc, use_ofn;
pid_t pager_pid;
+ assert(tag_files->ofd == -1);
+ assert(tag_files->tfs == NULL);
+
pager = getenv("MANPAGER");
if (pager == NULL || *pager == '\0')
pager = getenv("PAGER");
@@ -1238,9 +1248,9 @@ spawn_pager(struct tag_files *tag_files)
if (strcmp(cp, "less") == 0) {
argv[argc++] = mandoc_strdup("-T");
argv[argc++] = tag_files->tfn;
- if (tag_files->tagname != NULL) {
+ if (tag_target != NULL) {
argv[argc++] = mandoc_strdup("-t");
- argv[argc++] = tag_files->tagname;
+ argv[argc++] = tag_target;
use_ofn = 0;
}
}
@@ -1258,7 +1268,7 @@ spawn_pager(struct tag_files *tag_files)
break;
default:
(void)setpgid(pager_pid, 0);
- (void)tcsetpgrp(tag_files->ofd, pager_pid);
+ (void)tcsetpgrp(STDOUT_FILENO, pager_pid);
#if HAVE_PLEDGE
if (pledge("stdio rpath tmppath tty proc", NULL) == -1) {
mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
@@ -1270,16 +1280,10 @@ spawn_pager(struct tag_files *tag_files)
return pager_pid;
}
- /* The child process becomes the pager. */
-
- if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) {
- mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
- _exit(mandoc_msg_getrc());
- }
- close(tag_files->ofd);
- assert(tag_files->tfs == NULL);
-
- /* Do not start the pager before controlling the terminal. */
+ /*
+ * The child process becomes the pager.
+ * Do not start it before controlling the terminal.
+ */
while (tcgetpgrp(STDOUT_FILENO) != getpid())
nanosleep(&timeout, NULL);
diff --git a/manconf.h b/manconf.h
index bb376199..34ee6201 100644
--- a/manconf.h
+++ b/manconf.h
@@ -1,6 +1,6 @@
-/* $Id: manconf.h,v 1.7 2018/11/22 11:30:23 schwarze Exp $ */
+/* $OpenBSD: manconf.h,v 1.7 2018/11/22 11:30:15 schwarze Exp $ */
/*
- * Copyright (c) 2011, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -14,6 +14,9 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Public interface to man(1) configuration management.
+ * For use by the main program and by the formatters.
*/
/* List of unique, absolute paths to manual trees. */
@@ -37,6 +40,7 @@ struct manoutput {
int mdoc;
int noval;
int synopsisonly;
+ int tag_found;
int toc;
};
diff --git a/tag.c b/tag.c
index 14327415..6595c9d0 100644
--- a/tag.c
+++ b/tag.c
@@ -1,4 +1,4 @@
-/* $Id: tag.c,v 1.30 2020/03/21 00:17:31 schwarze Exp $ */
+/* $Id: tag.c,v 1.31 2020/04/02 22:12:55 schwarze Exp $ */
/*
* Copyright (c) 2015,2016,2018,2019,2020 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -176,16 +176,8 @@ tag_put(const char *s, int prio, struct roff_node *n)
}
}
-enum tag_result
-tag_check(const char *test_tag)
+int
+tag_exists(const char *tag)
{
- unsigned int slot;
-
- if (ohash_first(&tag_data, &slot) == NULL)
- return TAG_EMPTY;
- else if (test_tag != NULL && ohash_find(&tag_data,
- ohash_qlookup(&tag_data, test_tag)) == NULL)
- return TAG_MISS;
- else
- return TAG_OK;
+ return ohash_find(&tag_data, ohash_qlookup(&tag_data, tag)) != NULL;
}
diff --git a/tag.h b/tag.h
index 0d37a66a..407b7c94 100644
--- a/tag.h
+++ b/tag.h
@@ -1,4 +1,4 @@
-/* $Id: tag.h,v 1.11 2020/03/13 15:32:29 schwarze Exp $ */
+/* $Id: tag.h,v 1.12 2020/04/02 22:12:55 schwarze Exp $ */
/*
* Copyright (c) 2015, 2018, 2019, 2020 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -28,17 +28,7 @@
#define TAG_FALLBACK (INT_MAX - 1) /* Tag only used if unique. */
#define TAG_DELETE (INT_MAX) /* Tag not used at all. */
-/*
- * Return values of tag_check().
- */
-enum tag_result {
- TAG_OK, /* Argument exists as a tag. */
- TAG_MISS, /* Argument not found. */
- TAG_EMPTY /* No tag exists at all. */
-};
-
-
void tag_alloc(void);
+int tag_exists(const char *);
void tag_put(const char *, int, struct roff_node *);
-enum tag_result tag_check(const char *);
void tag_free(void);
diff --git a/term_tag.c b/term_tag.c
index cb9fa16d..f6203a6c 100644
--- a/term_tag.c
+++ b/term_tag.c
@@ -1,4 +1,4 @@
-/* $Id: term_tag.c,v 1.1 2020/03/13 15:32:29 schwarze Exp $ */
+/* $Id: term_tag.c,v 1.2 2020/04/02 22:12:55 schwarze Exp $ */
/*
* Copyright (c) 2015,2016,2018,2019,2020 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -45,7 +45,7 @@ static struct tag_files tag_files;
* but for simplicity, create it anyway.
*/
struct tag_files *
-term_tag_init(char *tagname)
+term_tag_init(void)
{
struct sigaction sa;
int ofd; /* In /tmp/, dup(2)ed to stdout. */
@@ -54,7 +54,6 @@ term_tag_init(char *tagname)
ofd = tfd = -1;
tag_files.tfs = NULL;
tag_files.tcpgid = -1;
- tag_files.tagname = tagname;
/* Clean up when dying from a signal. */
@@ -119,7 +118,6 @@ fail:
close(tag_files.ofd);
tag_files.ofd = -1;
}
- tag_files.tagname = NULL;
return NULL;
}
@@ -141,27 +139,29 @@ term_tag_write(struct roff_node *n, size_t line)
len, cp, tag_files.ofn, line);
}
-void
-term_tag_finish(void)
+/*
+ * Close both output files and restore the original standard output
+ * to the terminal. In the unlikely case that the latter fails,
+ * trying to start a pager would be useless, so report the failure
+ * to the main program.
+ */
+int
+term_tag_close(void)
{
- if (tag_files.tfs == NULL)
- return;
- fclose(tag_files.tfs);
- tag_files.tfs = NULL;
- switch (tag_check(tag_files.tagname)) {
- case TAG_EMPTY:
- unlink(tag_files.tfn);
- *tag_files.tfn = '\0';
- /* FALLTHROUGH */
- case TAG_MISS:
- if (tag_files.tagname == NULL)
- break;
- mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", tag_files.tagname);
- tag_files.tagname = NULL;
- break;
- case TAG_OK:
- break;
+ int irc = 0;
+
+ if (tag_files.tfs != NULL) {
+ fclose(tag_files.tfs);
+ tag_files.tfs = NULL;
+ }
+ if (tag_files.ofd != -1) {
+ fflush(stdout);
+ if ((irc = dup2(tag_files.ofd, STDOUT_FILENO)) == -1)
+ mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
+ close(tag_files.ofd);
+ tag_files.ofd = -1;
}
+ return irc;
}
void
@@ -170,11 +170,11 @@ term_tag_unlink(void)
pid_t tc_pgid;
if (tag_files.tcpgid != -1) {
- tc_pgid = tcgetpgrp(tag_files.ofd);
+ tc_pgid = tcgetpgrp(STDOUT_FILENO);
if (tc_pgid == tag_files.pager_pid ||
tc_pgid == getpgid(0) ||
getpgid(tc_pgid) == -1)
- (void)tcsetpgrp(tag_files.ofd, tag_files.tcpgid);
+ (void)tcsetpgrp(STDOUT_FILENO, tag_files.tcpgid);
}
if (*tag_files.ofn != '\0') {
unlink(tag_files.ofn);
@@ -184,10 +184,6 @@ term_tag_unlink(void)
unlink(tag_files.tfn);
*tag_files.tfn = '\0';
}
- if (tag_files.tfs != NULL) {
- fclose(tag_files.tfs);
- tag_files.tfs = NULL;
- }
}
static void
diff --git a/term_tag.h b/term_tag.h
index 1acde47b..b0a1c158 100644
--- a/term_tag.h
+++ b/term_tag.h
@@ -1,4 +1,4 @@
-/* $Id: term_tag.h,v 1.1 2020/03/13 15:32:29 schwarze Exp $ */
+/* $Id: term_tag.h,v 1.2 2020/04/02 22:12:55 schwarze Exp $ */
/*
* Copyright (c) 2015, 2018, 2019, 2020 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -21,7 +21,6 @@
struct tag_files {
char ofn[20]; /* Output file name. */
char tfn[20]; /* Tag file name. */
- char *tagname; /* Target specified with -O. */
FILE *tfs; /* Tag file object. */
int ofd; /* Original output file descriptor. */
pid_t tcpgid; /* Process group controlling the terminal. */
@@ -29,7 +28,7 @@ struct tag_files {
};
-struct tag_files *term_tag_init(char *);
+struct tag_files *term_tag_init(void);
void term_tag_write(struct roff_node *, size_t);
-void term_tag_finish(void);
+int term_tag_close(void);
void term_tag_unlink(void);