discuss@mandoc.bsd.lv
 help / color / mirror / Atom feed
From: Ingo Schwarze <schwarze@usta.de>
To: Jan Stary <hans@stare.cz>
Cc: discuss@mdocml.bsd.lv
Subject: Re: makewhatis stuck on groffer.1
Date: Mon, 22 Apr 2019 01:03:59 +0200	[thread overview]
Message-ID: <20190421230359.GD31325@athene.usta.de> (raw)
In-Reply-To: <20190420182144.GA13786@www.stare.cz>

Hi Jan,

Jan Stary wrote on Sat, Apr 20, 2019 at 08:21:45PM +0200:

> ... and 'man groffer' also never gets to rendering it.

Wow, that ancient version of groffer.1 can barely be called a manual
page.  It is low-level groff all over the place.  More than 600 lines
of low-level groff code (macro definitions) in a single manual page...
That's insane.

Actually, insanity was to be expected, given that it was written
by Bernd Warken.  But i wouldn't have expected it to be *that* bad.

Here is a minimal example of the specific issue you are reporting:

   $ echo '.while n .break' | mandoc -Tlint | head -n 1
  mandoc: <stdin>:1:10: UNSUPP: unsupported roff request: break
   $ echo '.while n .break' | mandoc
  [endless loop]

The commit below fixes the endless loop.

There appear to be a few more issues with that manual page that i'm
currently looking at.

Thanks for the report,
  Ingo


Log Message:
-----------
Implement the roff .break request (break out of a .while loop).
Jan Stary <hans at stare dot cz> found it in an ancient groffer(1)
manual page (version 1.19) on MacOS X Mojave.
Having .break not implemented wasn't a particularly bright idea
because obviously, it tended to cause infinite loops.

Modified Files:
--------------
    mandoc:
        roff.7
        roff.c
    mandoc/regress/roff/while:
        Makefile

Added Files:
-----------
    mandoc/regress/roff/while:
        break.in
        break.out_ascii

Revision Data
-------------
Index: roff.7
===================================================================
RCS file: /home/cvs/mandoc/mandoc/roff.7,v
retrieving revision 1.111
retrieving revision 1.112
diff -Lroff.7 -Lroff.7 -u -p -r1.111 -r1.112
--- roff.7
+++ roff.7
@@ -503,10 +503,9 @@ This is a Heirloom extension and current
 .It Ic \&br
 Break the output line.
 .It Ic \&break
-Break out of a
+Break out of the innermost
 .Ic \&while
 loop.
-Currently unsupported.
 .It Ic \&breakchar Ar char ...
 Optional line break characters.
 This is a Heirloom extension and currently ignored.
Index: roff.c
===================================================================
RCS file: /home/cvs/mandoc/mandoc/roff.c,v
retrieving revision 1.363
retrieving revision 1.364
diff -Lroff.c -Lroff.c -u -p -r1.363 -r1.364
--- roff.c
+++ roff.c
@@ -133,15 +133,18 @@ struct	roff {
 	char		 escape; /* escape character */
 };
 
+/*
+ * A macro definition, condition, or ignored block.
+ */
 struct	roffnode {
 	enum roff_tok	 tok; /* type of node */
 	struct roffnode	*parent; /* up one in stack */
 	int		 line; /* parse line */
 	int		 col; /* parse col */
 	char		*name; /* node name, e.g. macro name */
-	char		*end; /* end-rules: custom token */
-	int		 endspan; /* end-rules: next-line or infty */
-	int		 rule; /* current evaluation rule */
+	char		*end; /* custom end macro of the block */
+	int		 endspan; /* scope to: 1=eol 2=next line -1=\} */
+	int		 rule; /* content is: 1=evaluated 0=skipped */
 };
 
 #define	ROFF_ARGS	 struct roff *r, /* parse ctx */ \
@@ -181,6 +184,7 @@ static	int		 roff_als(ROFF_ARGS);
 static	int		 roff_block(ROFF_ARGS);
 static	int		 roff_block_text(ROFF_ARGS);
 static	int		 roff_block_sub(ROFF_ARGS);
+static	int		 roff_break(ROFF_ARGS);
 static	int		 roff_cblock(ROFF_ARGS);
 static	int		 roff_cc(ROFF_ARGS);
 static	int		 roff_ccond(struct roff *, int, int);
@@ -400,7 +404,7 @@ static	struct roffmac	 roffs[TOKEN_NONE]
 	{ roff_unsupp, NULL, NULL, 0 },  /* boxa */
 	{ roff_line_ignore, NULL, NULL, 0 },  /* bp */
 	{ roff_unsupp, NULL, NULL, 0 },  /* BP */
-	{ roff_unsupp, NULL, NULL, 0 },  /* break */
+	{ roff_break, NULL, NULL, 0 },  /* break */
 	{ roff_line_ignore, NULL, NULL, 0 },  /* breakchar */
 	{ roff_line_ignore, NULL, NULL, 0 },  /* brnl */
 	{ roff_noarg, NULL, NULL, 0 },  /* brp */
@@ -685,7 +689,7 @@ roffhash_find(struct ohash *htab, const 
 
 /*
  * Pop the current node off of the stack of roff instructions currently
- * pending.
+ * pending.  Return 1 if it is a loop or 0 otherwise.
  */
 static int
 roffnode_pop(struct roff *r)
@@ -2002,6 +2006,10 @@ roff_cblock(ROFF_ARGS)
 
 }
 
+/*
+ * Pop all nodes ending at the end of the current input line.
+ * Return the number of loops ended.
+ */
 static int
 roffnode_cleanscope(struct roff *r)
 {
@@ -2016,6 +2024,11 @@ roffnode_cleanscope(struct roff *r)
 	return inloop;
 }
 
+/*
+ * Handle the closing \} of a conditional block.
+ * Apart from generating warnings, this only pops nodes.
+ * Return the number of loops ended.
+ */
 static int
 roff_ccond(struct roff *r, int ln, int ppos)
 {
@@ -2235,6 +2248,7 @@ roff_block_text(ROFF_ARGS)
 static int
 roff_cond_sub(ROFF_ARGS)
 {
+	struct roffnode	*bl;
 	char		*ep;
 	int		 endloop, irc, rr;
 	enum roff_tok	 t;
@@ -2282,9 +2296,21 @@ roff_cond_sub(ROFF_ARGS)
 	 */
 
 	t = roff_parse(r, buf->buf, &pos, ln, ppos);
-	irc |= t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) ?
-	    (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) :
-	    rr ? ROFF_CONT : ROFF_IGN;
+	if (t == ROFF_break) {
+		if (irc & ROFF_LOOPMASK)
+			irc = ROFF_IGN | ROFF_LOOPEXIT;
+		else if (rr) {
+			for (bl = r->last; bl != NULL; bl = bl->parent) {
+				bl->rule = 0;
+				if (bl->tok == ROFF_while)
+					break;
+			}
+		}
+	} else if (t != TOKEN_NONE &&
+	    (rr || roffs[t].flags & ROFFMAC_STRUCT))
+		irc |= (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs);
+	else
+		irc |= rr ? ROFF_CONT : ROFF_IGN;
 	return irc;
 }
 
@@ -3479,6 +3505,17 @@ roff_als(ROFF_ARGS)
 	roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0);
 	roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
 	free(value);
+	return ROFF_IGN;
+}
+
+/*
+ * The .break request only makes sense inside conditionals,
+ * and that case is already handled in roff_cond_sub().
+ */
+static int
+roff_break(ROFF_ARGS)
+{
+	mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, pos, "break");
 	return ROFF_IGN;
 }
 
Index: Makefile
===================================================================
RCS file: /home/cvs/mandoc/mandoc/regress/roff/while/Makefile,v
retrieving revision 1.1
retrieving revision 1.2
diff -Lregress/roff/while/Makefile -Lregress/roff/while/Makefile -u -p -r1.1 -r1.2
--- regress/roff/while/Makefile
+++ regress/roff/while/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.1 2018/08/24 22:56:37 schwarze Exp $
+# $OpenBSD: Makefile,v 1.2 2019/04/21 22:43:00 schwarze Exp $
 
-REGRESS_TARGETS	= basic badargs into nesting outof
+REGRESS_TARGETS	= basic badargs break into nesting outof
 LINT_TARGETS	= badargs into nesting outof
 
 # mandoc defects:
--- /dev/null
+++ regress/roff/while/break.out_ascii
@@ -0,0 +1,9 @@
+WHILE-BREAK(1)              General Commands Manual             WHILE-BREAK(1)
+
+N\bNA\bAM\bME\bE
+     w\bwh\bhi\bil\ble\be-\b-b\bbr\bre\bea\bak\bk - break request inside a while loop
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+     initial text 10 - 9 - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0 final text
+
+OpenBSD                         April 21, 2019                         OpenBSD
--- /dev/null
+++ regress/roff/while/break.in
@@ -0,0 +1,16 @@
+.\" $OpenBSD: break.in,v 1.1 2019/04/21 22:43:00 schwarze Exp $
+.Dd $Mdocdate: April 21 2019 $
+.Dt WHILE-BREAK 1
+.Os
+.Sh NAME
+.Nm while-break
+.Nd break request inside a while loop
+.Sh DESCRIPTION
+initial text
+.nr cnt 11 1
+.while n \{\
+\n-[cnt]
+.if !\n[cnt] .break
+\(en
+.\}
+final text
--
 To unsubscribe send an email to discuss+unsubscribe@mandoc.bsd.lv

  reply	other threads:[~2019-04-21 23:04 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-20 18:16 makewhatis stuck on groff.1 Jan Stary
2019-04-20 18:18 ` makewhatis stuck on groffer.1 Jan Stary
2019-04-20 18:21   ` Jan Stary
2019-04-21 23:03     ` Ingo Schwarze [this message]
2019-04-22  8:32       ` Jan Stary
2019-04-23 12:01         ` Ingo Schwarze

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190421230359.GD31325@athene.usta.de \
    --to=schwarze@usta.de \
    --cc=discuss@mandoc.bsd.lv \
    --cc=discuss@mdocml.bsd.lv \
    --cc=hans@stare.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).