From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 818 invoked from network); 3 Aug 2020 11:03:35 -0000 Received: from bsd.lv (HELO mandoc.bsd.lv) (66.111.2.12) by inbox.vuxu.org with ESMTPUTF8; 3 Aug 2020 11:03:35 -0000 Received: from fantadrom.bsd.lv (localhost [127.0.0.1]) by mandoc.bsd.lv (OpenSMTPD) with ESMTP id ad55921d for ; Mon, 3 Aug 2020 06:03:30 -0500 (EST) Received: from localhost (mandoc.bsd.lv [local]) by mandoc.bsd.lv (OpenSMTPD) with ESMTPA id 1cf6dbd0 for ; Mon, 3 Aug 2020 06:03:30 -0500 (EST) Date: Mon, 3 Aug 2020 06:03:30 -0500 (EST) X-Mailinglist: mandoc-source Reply-To: source@mandoc.bsd.lv MIME-Version: 1.0 From: schwarze@mandoc.bsd.lv To: source@mandoc.bsd.lv Subject: mandoc: Put the code handling \} into a new function X-Mailer: activitymail 1.26, http://search.cpan.org/dist/activitymail/ Content-Type: text/plain; charset=utf-8 Message-ID: Log Message: ----------- Put the code handling \} into a new function roff_cond_checkend() and call that function not only from both places where copies existed - when processing text lines and when processing request/macro lines in conditional block scope - but also when closing a macro definition request, such that this construction works: .if n \{.de macroname macro content .. \} ignored arguments .macroname This fixes a bug reported by John Gardner . While here, avoid a confusing decrement of the line scope counter in roffnode_cleanscope() for conditional blocks that do not have line scope in the first place (no functional change for this part). Also improve validation of an internal invariant in roff_cblock() and polish some comments. Modified Files: -------------- mandoc: roff.c mandoc/regress/roff/cond: Makefile close.in close.out_ascii close.out_lint Added Files: ----------- mandoc/regress/roff/cond: de.in de.out_ascii de.out_lint Revision Data ------------- Index: roff.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/roff.c,v retrieving revision 1.374 retrieving revision 1.375 diff -Lroff.c -Lroff.c -u -p -r1.374 -r1.375 --- roff.c +++ roff.c @@ -192,6 +192,7 @@ static int roff_cc(ROFF_ARGS); static int roff_ccond(struct roff *, int, int); static int roff_char(ROFF_ARGS); static int roff_cond(ROFF_ARGS); +static int roff_cond_checkend(ROFF_ARGS); static int roff_cond_text(ROFF_ARGS); static int roff_cond_sub(ROFF_ARGS); static int roff_ds(ROFF_ARGS); @@ -2034,14 +2035,13 @@ roff_parse(struct roff *r, char *buf, in /* --- handling of request blocks ----------------------------------------- */ +/* + * Close a macro definition block or an "ignore" block. + */ static int roff_cblock(ROFF_ARGS) { - - /* - * A block-close `..' should only be invoked as a child of an - * ignore macro, otherwise raise a warning and just ignore it. - */ + int rr; if (r->last == NULL) { mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, ".."); @@ -2050,26 +2050,38 @@ roff_cblock(ROFF_ARGS) switch (r->last->tok) { case ROFF_am: - /* ROFF_am1 is remapped to ROFF_am in roff_block(). */ case ROFF_ami: case ROFF_de: - /* ROFF_de1 is remapped to ROFF_de in roff_block(). */ case ROFF_dei: case ROFF_ig: break; + case ROFF_am1: + case ROFF_de1: + /* Remapped in roff_block(). */ + abort(); default: mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, ".."); return ROFF_IGN; } + roffnode_pop(r); + roffnode_cleanscope(r); + + /* + * If a conditional block with braces is still open, + * check for "\}" block end markers. + */ + + if (r->last != NULL && r->last->endspan < 0) { + rr = 1; /* If arguments follow "\}", warn about them. */ + roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr); + } + if (buf->buf[pos] != '\0') mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos, ".. %s", buf->buf + pos); - roffnode_pop(r); - roffnode_cleanscope(r); return ROFF_IGN; - } /* @@ -2082,7 +2094,7 @@ roffnode_cleanscope(struct roff *r) int inloop; inloop = 0; - while (r->last != NULL) { + while (r->last != NULL && r->last->endspan > 0) { if (--r->last->endspan != 0) break; inloop += roffnode_pop(r); @@ -2091,7 +2103,7 @@ roffnode_cleanscope(struct roff *r) } /* - * Handle the closing \} of a conditional block. + * Handle the closing "\}" of a conditional block. * Apart from generating warnings, this only pops nodes. * Return the number of loops ended. */ @@ -2311,13 +2323,20 @@ roff_block_text(ROFF_ARGS) return ROFF_IGN; } +/* + * Check for a closing "\}" and handle it. + * In this function, the final "int *offs" argument is used for + * different purposes than elsewhere: + * Input: *offs == 0: caller wants to discard arguments following \} + * *offs == 1: caller wants to preserve text following \} + * Output: *offs = 0: tell caller to discard input line + * *offs = 1: tell caller to use input line + */ static int -roff_cond_sub(ROFF_ARGS) +roff_cond_checkend(ROFF_ARGS) { - struct roffnode *bl; char *ep; int endloop, irc, rr; - enum roff_tok t; irc = ROFF_IGN; rr = r->last->rule; @@ -2327,23 +2346,26 @@ roff_cond_sub(ROFF_ARGS) irc |= endloop; /* - * If `\}' occurs on a macro line without a preceding macro, - * drop the line completely. + * If "\}" occurs on a macro line without a preceding macro or + * a text line contains nothing else, drop the line completely. */ ep = buf->buf + pos; - if (ep[0] == '\\' && ep[1] == '}') + if (ep[0] == '\\' && ep[1] == '}' && (ep[2] == '\0' || *offs == 0)) rr = 0; /* - * The closing delimiter `\}' rewinds the conditional scope + * The closing delimiter "\}" rewinds the conditional scope * but is otherwise ignored when interpreting the line. */ while ((ep = strchr(ep, '\\')) != NULL) { switch (ep[1]) { case '}': - memmove(ep, ep + 2, strlen(ep + 2) + 1); + if (rr) + ep[1] = '&'; + else + memmove(ep, ep + 2, strlen(ep + 2) + 1); if (roff_ccond(r, ln, ep - buf->buf)) irc |= endloop; break; @@ -2355,7 +2377,22 @@ roff_cond_sub(ROFF_ARGS) break; } } + *offs = rr; + return irc; +} +/* + * Parse and process a request or macro line in conditional scope. + */ +static int +roff_cond_sub(ROFF_ARGS) +{ + struct roffnode *bl; + int irc, rr; + enum roff_tok t; + + rr = 0; /* If arguments follow "\}", skip them. */ + irc = roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr); t = roff_parse(r, buf->buf, &pos, ln, ppos); /* For now, let high level macros abort .ce mode. */ @@ -2392,48 +2429,16 @@ roff_cond_sub(ROFF_ARGS) return irc; } +/* + * Parse and process a text line in conditional scope. + */ static int roff_cond_text(ROFF_ARGS) { - char *ep; - int endloop, irc, rr; - - irc = ROFF_IGN; - rr = r->last->rule; - endloop = tok != ROFF_while ? ROFF_IGN : - rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT; - if (roffnode_cleanscope(r)) - irc |= endloop; - - /* - * If `\}' occurs on a text line with neither preceding - * nor following characters, drop the line completely. - */ - - ep = buf->buf + pos; - if (strcmp(ep, "\\}") == 0) - rr = 0; - - /* - * The closing delimiter `\}' rewinds the conditional scope - * but is otherwise ignored when interpreting the line. - */ + int irc, rr; - while ((ep = strchr(ep, '\\')) != NULL) { - switch (ep[1]) { - case '}': - memmove(ep, ep + 2, strlen(ep + 2) + 1); - if (roff_ccond(r, ln, ep - buf->buf)) - irc |= endloop; - break; - case '\0': - ++ep; - break; - default: - ep += 2; - break; - } - } + rr = 1; /* If arguments follow "\}", preserve them. */ + irc = roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr); if (rr) irc |= ROFF_CONT; return irc; --- /dev/null +++ regress/roff/cond/de.out_lint @@ -0,0 +1,2 @@ +mandoc: de.in:11:4: ERROR: skipping all arguments: .. \&ignored +mandoc: de.in:18:2: ERROR: skipping unknown macro: .m3 Index: close.out_lint =================================================================== RCS file: /home/cvs/mandoc/mandoc/regress/roff/cond/close.out_lint,v retrieving revision 1.7 retrieving revision 1.8 diff -Lregress/roff/cond/close.out_lint -Lregress/roff/cond/close.out_lint -u -p -r1.7 -r1.8 --- regress/roff/cond/close.out_lint +++ regress/roff/cond/close.out_lint @@ -1,2 +1,3 @@ -mandoc: close.in:31:2: ERROR: appending missing end of block: if -mandoc: close.in:31:9: WARNING: skipping paragraph macro: sp after PP +mandoc: close.in:65:1: ERROR: escaped character not allowed in a name: BR\& +mandoc: close.in:68:2: ERROR: appending missing end of block: if +mandoc: close.in:68:9: WARNING: skipping paragraph macro: sp after PP --- /dev/null +++ regress/roff/cond/de.out_ascii @@ -0,0 +1,13 @@ +COND-DE(1) General Commands Manual COND-DE(1) + + + +NNAAMMEE + cond-de - close macro definition and conditional block on the same line + +DDEESSCCRRIIPPTTIIOONN + initial text first content second content final text + + + +OpenBSD August 3, 2020 COND-DE(1) Index: close.in =================================================================== RCS file: /home/cvs/mandoc/mandoc/regress/roff/cond/close.in,v retrieving revision 1.3 retrieving revision 1.4 diff -Lregress/roff/cond/close.in -Lregress/roff/cond/close.in -u -p -r1.3 -r1.4 --- regress/roff/cond/close.in +++ regress/roff/cond/close.in @@ -1,4 +1,4 @@ -.\" $OpenBSD: close.in,v 1.3 2017/07/04 14:53:26 schwarze Exp $ +.\" $OpenBSD: close.in,v 1.5 2020/08/03 10:52:39 schwarze Exp $ .TH COND-CLOSE 1 "November 26, 2018" .SH NAME cond-close \- closing conditional macros @@ -12,6 +12,22 @@ closing after an ignored macro .if t \{text \} closing after plain text .PP +.if t \{text +\} +text line contains closing brace only +.PP +.if t \{text +\} plus something +text line contains closing brace and additional words +.PP +.if t \{text +.\} +request line contains closing brace only +.PP +.if t \{text +.\}with following args +request line contains closing brace and additional args +.PP .if n \{conditional content \} following words with whitespace .PP .if n \{conditional content\}following words without whitespace @@ -27,6 +43,27 @@ preceding words non-standard multi-line style \} following words +.PP +preceding words +.if n \{text line block end +\} with additional words +following words +.PP +.if n \{two +.if n \{closes +on\} the\} same +text line +.PP +preceding words +.if n \{close on request line +.\}with following args +following words +.PP +preceding words +.if n \{two +.if n \{closes +.BR\}on\}the same +macro line .PP .if n \{ still open at the end of the file Index: close.out_ascii =================================================================== RCS file: /home/cvs/mandoc/mandoc/regress/roff/cond/close.out_ascii,v retrieving revision 1.2 retrieving revision 1.3 diff -Lregress/roff/cond/close.out_ascii -Lregress/roff/cond/close.out_ascii -u -p -r1.2 -r1.3 --- regress/roff/cond/close.out_ascii +++ regress/roff/cond/close.out_ascii @@ -12,6 +12,14 @@ DDEESSCCRRIIPPTTIIOONN closing after plain text + text line contains closing brace only + + text line contains closing brace and additional words + + request line contains closing brace only + + request line contains closing brace and additional args + conditional content following words with whitespace conditional contentfollowing words without whitespace @@ -21,6 +29,15 @@ DDEESSCCRRIIPPTTIIOONN preceding words non-standard multi-line style following words + + preceding words text line block end with additional words following + words + + two closes on the same text line + + preceding words close on request line following words + + preceding words two closes oonntthheesame macro line still open at the end of the file Index: Makefile =================================================================== RCS file: /home/cvs/mandoc/mandoc/regress/roff/cond/Makefile,v retrieving revision 1.2 retrieving revision 1.3 diff -Lregress/roff/cond/Makefile -Lregress/roff/cond/Makefile -u -p -r1.2 -r1.3 --- regress/roff/cond/Makefile +++ regress/roff/cond/Makefile @@ -1,6 +1,6 @@ -# $OpenBSD: Makefile,v 1.8 2015/05/31 23:12:17 schwarze Exp $ +# $OpenBSD: Makefile,v 1.10 2020/08/03 10:52:39 schwarze Exp $ -REGRESS_TARGETS = if ie close numeric register strcmp string before-Dd -LINT_TARGETS = if close +REGRESS_TARGETS = if ie close de numeric register strcmp string before-Dd +LINT_TARGETS = if close de .include --- /dev/null +++ regress/roff/cond/de.in @@ -0,0 +1,19 @@ +.\" $OpenBSD: de.in,v 1.1 2020/08/03 10:52:39 schwarze Exp $ +.TH COND-DE 1 "August 3, 2020" +.SH NAME +cond-de \- close macro definition and conditional block on the same line +.SH DESCRIPTION +.if n \{.de m1 +first content +.. \} +.if n \{.de m2 +second content +.. \}ignored +.if t \{.de m3 +does not show up +.. \}ignored +initial text +.m1 +.m2 +.m3 +final text -- To unsubscribe send an email to source+unsubscribe@mandoc.bsd.lv