source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mandoc: When the last file formatted yielded no tags, the tags file got
@ 2020-04-02 22:13 schwarze
  0 siblings, 0 replies; only message in thread
From: schwarze @ 2020-04-02 22:13 UTC (permalink / raw)
  To: source

Log Message:
-----------
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.

Modified Files:
--------------
    mandoc:
        main.c
        manconf.h
        tag.c
        tag.h
        term_tag.c
        term_tag.h

Revision Data
-------------
Index: term_tag.c
===================================================================
RCS file: /home/cvs/mandoc/mandoc/term_tag.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -Lterm_tag.c -Lterm_tag.c -u -p -r1.1 -r1.2
--- term_tag.c
+++ term_tag.c
@@ -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
 	    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);
@@ -183,10 +183,6 @@ term_tag_unlink(void)
 	if (*tag_files.tfn != '\0') {
 		unlink(tag_files.tfn);
 		*tag_files.tfn = '\0';
-	}
-	if (tag_files.tfs != NULL) {
-		fclose(tag_files.tfs);
-		tag_files.tfs = NULL;
 	}
 }
 
Index: tag.h
===================================================================
RCS file: /home/cvs/mandoc/mandoc/tag.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -Ltag.h -Ltag.h -u -p -r1.11 -r1.12
--- tag.h
+++ tag.h
@@ -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);
Index: tag.c
===================================================================
RCS file: /home/cvs/mandoc/mandoc/tag.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -Ltag.c -Ltag.c -u -p -r1.30 -r1.31
--- tag.c
+++ tag.c
@@ -176,16 +176,8 @@ tag_put(const char *s, int prio, struct 
 	}
 }
 
-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;
 }
Index: manconf.h
===================================================================
RCS file: /home/cvs/mandoc/mandoc/manconf.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -Lmanconf.h -Lmanconf.h -u -p -r1.7 -r1.8
--- manconf.h
+++ manconf.h
@@ -1,6 +1,6 @@
-/*	$Id$ */
+/* $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;
 };
 
Index: main.c
===================================================================
RCS file: /home/cvs/mandoc/mandoc/main.c,v
retrieving revision 1.347
retrieving revision 1.348
diff -Lmain.c -Lmain.c -u -p -r1.347 -r1.348
--- main.c
+++ main.c
@@ -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 *, in
 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, struc
 
 	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 c
 			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
  * 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);
Index: term_tag.h
===================================================================
RCS file: /home/cvs/mandoc/mandoc/term_tag.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -Lterm_tag.h -Lterm_tag.h -u -p -r1.1 -r1.2
--- term_tag.h
+++ term_tag.h
@@ -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);
--
 To unsubscribe send an email to source+unsubscribe@mandoc.bsd.lv


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-04-02 22:13 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-02 22:13 mandoc: When the last file formatted yielded no tags, the tags file got schwarze

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).