From b7f92c5facc9c63232c7c76c88de8493b7d1ca0e Mon Sep 17 00:00:00 2001 From: schwarze Date: Fri, 24 Aug 2018 22:56:37 +0000 Subject: [PATCH] Rudimentary implementation of the roff(7) .while request. Needed for example by groff_hdtbl(7). There are two limitations: It does not support nested .while requests yet, and each .while loop must start and end in the same scope. The roff_parseln() return codes are now more flexible and allow OR'ing options. --- regress/usr.bin/mandoc/roff/Makefile | 5 +- regress/usr.bin/mandoc/roff/while/Makefile | 13 + regress/usr.bin/mandoc/roff/while/badargs.in | 14 + .../mandoc/roff/while/badargs.out_ascii | 13 + .../mandoc/roff/while/badargs.out_lint | 3 + regress/usr.bin/mandoc/roff/while/basic.in | 30 ++ .../usr.bin/mandoc/roff/while/basic.out_ascii | 16 ++ regress/usr.bin/mandoc/roff/while/into.in | 20 ++ .../usr.bin/mandoc/roff/while/into.out_ascii | 9 + .../usr.bin/mandoc/roff/while/into.out_lint | 2 + regress/usr.bin/mandoc/roff/while/nesting.in | 19 ++ .../mandoc/roff/while/nesting.out_ascii | 9 + .../mandoc/roff/while/nesting.out_lint | 2 + regress/usr.bin/mandoc/roff/while/outof.in | 18 ++ .../usr.bin/mandoc/roff/while/outof.out_ascii | 9 + .../usr.bin/mandoc/roff/while/outof.out_lint | 2 + share/man/man7/roff.7 | 18 +- usr.bin/mandoc/libmandoc.h | 35 ++- usr.bin/mandoc/mandoc.h | 6 +- usr.bin/mandoc/read.c | 174 +++++++---- usr.bin/mandoc/roff.c | 271 ++++++++++-------- 21 files changed, 484 insertions(+), 204 deletions(-) create mode 100644 regress/usr.bin/mandoc/roff/while/Makefile create mode 100644 regress/usr.bin/mandoc/roff/while/badargs.in create mode 100644 regress/usr.bin/mandoc/roff/while/badargs.out_ascii create mode 100644 regress/usr.bin/mandoc/roff/while/badargs.out_lint create mode 100644 regress/usr.bin/mandoc/roff/while/basic.in create mode 100644 regress/usr.bin/mandoc/roff/while/basic.out_ascii create mode 100644 regress/usr.bin/mandoc/roff/while/into.in create mode 100644 regress/usr.bin/mandoc/roff/while/into.out_ascii create mode 100644 regress/usr.bin/mandoc/roff/while/into.out_lint create mode 100644 regress/usr.bin/mandoc/roff/while/nesting.in create mode 100644 regress/usr.bin/mandoc/roff/while/nesting.out_ascii create mode 100644 regress/usr.bin/mandoc/roff/while/nesting.out_lint create mode 100644 regress/usr.bin/mandoc/roff/while/outof.in create mode 100644 regress/usr.bin/mandoc/roff/while/outof.out_ascii create mode 100644 regress/usr.bin/mandoc/roff/while/outof.out_lint diff --git a/regress/usr.bin/mandoc/roff/Makefile b/regress/usr.bin/mandoc/roff/Makefile index 7c6f5e16dda..f338f83dad3 100644 --- a/regress/usr.bin/mandoc/roff/Makefile +++ b/regress/usr.bin/mandoc/roff/Makefile @@ -1,7 +1,8 @@ -# $OpenBSD: Makefile,v 1.25 2018/08/23 14:16:12 schwarze Exp $ +# $OpenBSD: Makefile,v 1.26 2018/08/24 22:56:37 schwarze Exp $ SUBDIR = args cond esc scale string -SUBDIR += br cc de ds ft ig it ll na nr po ps return rm rn shift sp ta ti tr +SUBDIR += br cc de ds ft ig it ll na nr po ps +SUBDIR += return rm rn shift sp ta ti tr while .include "../Makefile.sub" .include diff --git a/regress/usr.bin/mandoc/roff/while/Makefile b/regress/usr.bin/mandoc/roff/while/Makefile new file mode 100644 index 00000000000..ed970474667 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/Makefile @@ -0,0 +1,13 @@ +# $OpenBSD: Makefile,v 1.1 2018/08/24 22:56:37 schwarze Exp $ + +REGRESS_TARGETS = basic badargs into nesting outof +LINT_TARGETS = badargs into nesting outof + +# mandoc defects: +# - if a while loop extends into a scope, mandoc may close it there +# - mandoc does not support nested .while loops +# - mandoc does not support .while loops extending out of the current scope + +SKIP_GROFF = into nesting outof + +.include diff --git a/regress/usr.bin/mandoc/roff/while/badargs.in b/regress/usr.bin/mandoc/roff/while/badargs.in new file mode 100644 index 00000000000..bbbd7cd056a --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/badargs.in @@ -0,0 +1,14 @@ +.\" $OpenBSD: badargs.in,v 1.1 2018/08/24 22:56:37 schwarze Exp $ +.Dd $Mdocdate: August 24 2018 $ +.Dt WHILE-BADARGS 1 +.Os +.Sh NAME +.Nm while-badargs +.Nd dubious arguments for the while request +.Sh DESCRIPTION +while does not support next line scope: +.nr cnt 2 1 +.while \n-[cnt] +\n[cnt] +.Pp +final text diff --git a/regress/usr.bin/mandoc/roff/while/badargs.out_ascii b/regress/usr.bin/mandoc/roff/while/badargs.out_ascii new file mode 100644 index 00000000000..8878d64ebec --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/badargs.out_ascii @@ -0,0 +1,13 @@ +WHILE-BADARGS(1) General Commands Manual WHILE-BADARGS(1) + +NNAAMMEE + wwhhiillee--bbaaddaarrggss - dubious arguments for the while request + +DDEESSCCRRIIPPTTIIOONN + while does not support next line scope: + + 0 + + final text + +OpenBSD August 25, 2018 OpenBSD diff --git a/regress/usr.bin/mandoc/roff/while/badargs.out_lint b/regress/usr.bin/mandoc/roff/while/badargs.out_lint new file mode 100644 index 00000000000..293ecc0ac52 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/badargs.out_lint @@ -0,0 +1,3 @@ +mandoc: badargs.in:11:2: WARNING: conditional request controls empty scope: while +mandoc: badargs.in:11:9: WARNING: blank line in fill mode, using .sp +mandoc: badargs.in:11:2: WARNING: conditional request controls empty scope: while diff --git a/regress/usr.bin/mandoc/roff/while/basic.in b/regress/usr.bin/mandoc/roff/while/basic.in new file mode 100644 index 00000000000..6bd09e3af4a --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/basic.in @@ -0,0 +1,30 @@ +.\" $OpenBSD: basic.in,v 1.1 2018/08/24 22:56:37 schwarze Exp $ +.Dd $Mdocdate: August 24 2018 $ +.Dt WHILE-BASIC 1 +.Os +.Sh NAME +.Nm while-basic +.Nd the while request +.Sh DESCRIPTION +Loop with single-line scope: +.nr cnt 11 1 +.de mym +\\n-[cnt] +.. +.while \n[cnt] .mym +.Pp +Loop with multi-line scope, text line closure: +.nr cnt 11 +.while \n[cnt] \{\ +.nr cnt -1 +\n[cnt]\}, +boom. +.Pp +Loop with multi-line scope, macro line closure: +.nr cnt 11 +.while \n[cnt] \{\ +.nr cnt -1 +\n[cnt] +.\} +.Pp +final text diff --git a/regress/usr.bin/mandoc/roff/while/basic.out_ascii b/regress/usr.bin/mandoc/roff/while/basic.out_ascii new file mode 100644 index 00000000000..b97abb41bb0 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/basic.out_ascii @@ -0,0 +1,16 @@ +WHILE-BASIC(1) General Commands Manual WHILE-BASIC(1) + +NNAAMMEE + wwhhiillee--bbaassiicc - the while request + +DDEESSCCRRIIPPTTIIOONN + Loop with single-line scope: 10 9 8 7 6 5 4 3 2 1 0 + + Loop with multi-line scope, text line closure: 10, 9, 8, 7, 6, 5, 4, 3, + 2, 1, 0, boom. + + Loop with multi-line scope, macro line closure: 10 9 8 7 6 5 4 3 2 1 0 + + final text + +OpenBSD August 25, 2018 OpenBSD diff --git a/regress/usr.bin/mandoc/roff/while/into.in b/regress/usr.bin/mandoc/roff/while/into.in new file mode 100644 index 00000000000..5a840ab0bc2 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/into.in @@ -0,0 +1,20 @@ +.\" $OpenBSD: into.in,v 1.1 2018/08/24 22:56:37 schwarze Exp $ +.Dd $Mdocdate: August 24 2018 $ +.Dt WHILE-INTO 1 +.Os +.Sh NAME +.Nm while-into +.Nd while request extending into a macro +.Sh DESCRIPTION +.nr cnt 10 +.de closeloop +.nr cnt -1 +.\} +.. +initial text +.while \n[cnt] \{\ +\n[cnt] +.closeloop +after macro +.\} +final text diff --git a/regress/usr.bin/mandoc/roff/while/into.out_ascii b/regress/usr.bin/mandoc/roff/while/into.out_ascii new file mode 100644 index 00000000000..cf8e56146bb --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/into.out_ascii @@ -0,0 +1,9 @@ +WHILE-INTO(1) General Commands Manual WHILE-INTO(1) + +NNAAMMEE + wwhhiillee--iinnttoo - while request extending into a macro + +DDEESSCCRRIIPPTTIIOONN + initial text 10 after macro final text + +OpenBSD August 25, 2018 OpenBSD diff --git a/regress/usr.bin/mandoc/roff/while/into.out_lint b/regress/usr.bin/mandoc/roff/while/into.out_lint new file mode 100644 index 00000000000..04a75220466 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/into.out_lint @@ -0,0 +1,2 @@ +mandoc: into.in:17:5: UNSUPP: end of .while loop in inner scope +mandoc: into.in:20:1: UNSUPP: end of scope with open .while loop diff --git a/regress/usr.bin/mandoc/roff/while/nesting.in b/regress/usr.bin/mandoc/roff/while/nesting.in new file mode 100644 index 00000000000..930b8b7ac75 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/nesting.in @@ -0,0 +1,19 @@ +.\" $OpenBSD: nesting.in,v 1.1 2018/08/24 22:56:37 schwarze Exp $ +.Dd $Mdocdate: August 24 2018 $ +.Dt WHILE-NESTING 1 +.Os +.Sh NAME +.Nm while-nesting +.Nd nested while requests +.Sh DESCRIPTION +initial text +.nr c1 3 +.while \n(c1 \{\ +. nr c2 3 +. while \n(c2 \{\ +. nop \n(c1\n(c2 +. nr c2 -1 +. \} +. nr c1 -1 +.\} +final text diff --git a/regress/usr.bin/mandoc/roff/while/nesting.out_ascii b/regress/usr.bin/mandoc/roff/while/nesting.out_ascii new file mode 100644 index 00000000000..8aae57d75ed --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/nesting.out_ascii @@ -0,0 +1,9 @@ +WHILE-NESTING(1) General Commands Manual WHILE-NESTING(1) + +NNAAMMEE + wwhhiillee--nneessttiinngg - nested while requests + +DDEESSCCRRIIPPTTIIOONN + initial text 33 32 31 final text + +OpenBSD August 25, 2018 OpenBSD diff --git a/regress/usr.bin/mandoc/roff/while/nesting.out_lint b/regress/usr.bin/mandoc/roff/while/nesting.out_lint new file mode 100644 index 00000000000..7ea34bad961 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/nesting.out_lint @@ -0,0 +1,2 @@ +mandoc: nesting.in:14:37: UNSUPP: nested .while loops +mandoc: nesting.in:18:4: UNSUPP: cannot continue this .while loop diff --git a/regress/usr.bin/mandoc/roff/while/outof.in b/regress/usr.bin/mandoc/roff/while/outof.in new file mode 100644 index 00000000000..4da3453c43a --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/outof.in @@ -0,0 +1,18 @@ +.\" $OpenBSD: outof.in,v 1.1 2018/08/24 22:56:37 schwarze Exp $ +.Dd $Mdocdate: August 24 2018 $ +.Dt WHILE-OUTOF 1 +.Os +.Sh NAME +.Nm while-outof +.Nd while request starting in a macro +.Sh DESCRIPTION +.nr cnt 10 +.de mym +. while \\n[cnt] \{\ +. nop \\n[cnt] +.. +initial text +.mym +. nr cnt -1 +.\} +final text diff --git a/regress/usr.bin/mandoc/roff/while/outof.out_ascii b/regress/usr.bin/mandoc/roff/while/outof.out_ascii new file mode 100644 index 00000000000..4a3dbe7fe4e --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/outof.out_ascii @@ -0,0 +1,9 @@ +WHILE-OUTOF(1) General Commands Manual WHILE-OUTOF(1) + +NNAAMMEE + wwhhiillee--oouuttooff - while request starting in a macro + +DDEESSCCRRIIPPTTIIOONN + initial text 10 final text + +OpenBSD August 25, 2018 OpenBSD diff --git a/regress/usr.bin/mandoc/roff/while/outof.out_lint b/regress/usr.bin/mandoc/roff/while/outof.out_lint new file mode 100644 index 00000000000..6ab0c9fde27 --- /dev/null +++ b/regress/usr.bin/mandoc/roff/while/outof.out_lint @@ -0,0 +1,2 @@ +mandoc: outof.in:15:1: UNSUPP: end of scope with open .while loop +mandoc: outof.in:17:4: UNSUPP: cannot continue this .while loop diff --git a/share/man/man7/roff.7 b/share/man/man7/roff.7 index 2914ce486e3..e1bf722f975 100644 --- a/share/man/man7/roff.7 +++ b/share/man/man7/roff.7 @@ -1,4 +1,4 @@ -.\" $OpenBSD: roff.7,v 1.83 2018/08/23 14:16:11 schwarze Exp $ +.\" $OpenBSD: roff.7,v 1.84 2018/08/24 22:56:37 schwarze Exp $ .\" .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons .\" Copyright (c) 2010-2018 Ingo Schwarze @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 23 2018 $ +.Dd $Mdocdate: August 24 2018 $ .Dt ROFF 7 .Os .Sh NAME @@ -1200,7 +1200,7 @@ While evaluating the the unit suffixes described below .Sx Scaling Widths are ignored. -.It Ic \&it Ar expression macro +.It Ic \&itc Ar expression macro Set an input line trap, not counting lines ending with \ec. Currently unsupported. .It Ic \&IX Ar class keystring @@ -1713,8 +1713,12 @@ This is a Heirloom extension and currently ignored. Set a page location trap. Currently unsupported. .It Ic \&while Ar condition body -Repeated execution while a condition is true. -Currently unsupported. +Repeated execution while a +.Ar condition +is true, with syntax similar to +.Ic \&if . +Currently implemented with two restrictions: cannot nest, +and each loop must start and end in the same scope. .It Ic \&write Oo \(dq Oc Ns Ar string Write to an open file. Ignored because insecure. @@ -2147,10 +2151,6 @@ macro control character does not suppress output line breaks. .It Diversions are not implemented, and support for traps is very incomplete. -.It -While recursion is supported, -.Sx \&while -loops are not. .El .Pp The special semantics of the diff --git a/usr.bin/mandoc/libmandoc.h b/usr.bin/mandoc/libmandoc.h index 336614c360a..b5e492e1752 100644 --- a/usr.bin/mandoc/libmandoc.h +++ b/usr.bin/mandoc/libmandoc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: libmandoc.h,v 1.58 2018/08/23 19:32:03 schwarze Exp $ */ +/* $OpenBSD: libmandoc.h,v 1.59 2018/08/24 22:56:37 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze @@ -16,16 +16,27 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -enum rofferr { - ROFF_CONT, /* continue processing line */ - ROFF_RERUN, /* re-run roff interpreter with offset */ - ROFF_APPEND, /* re-run main parser, appending next line */ - ROFF_REPARSE, /* re-run main parser on the result */ - ROFF_USERCALL, /* dto., calling a user-defined macro */ - ROFF_USERRET, /* abort parsing of user-defined macro */ - ROFF_SO, /* include another file */ - ROFF_IGN, /* ignore current line */ -}; +/* + * Return codes passed from the roff parser to the main parser. + */ + +/* Main instruction: what to do with the returned line. */ +#define ROFF_IGN 0x000 /* Don't do anything with it. */ +#define ROFF_CONT 0x001 /* Give it to the high-level parser. */ +#define ROFF_RERUN 0x002 /* Re-run the roff parser with an offset. */ +#define ROFF_REPARSE 0x004 /* Recursively run the main parser on it. */ +#define ROFF_SO 0x008 /* Include the named file. */ +#define ROFF_MASK 0x00f /* Only one of these bits should be set. */ + +/* Options for further parsing, to be OR'ed with the above. */ +#define ROFF_APPEND 0x010 /* Append the next line to this one. */ +#define ROFF_USERCALL 0x020 /* Start execution of a new macro. */ +#define ROFF_USERRET 0x040 /* Abort execution of the current macro. */ +#define ROFF_WHILE 0x100 /* Start a new .while loop. */ +#define ROFF_LOOPCONT 0x200 /* Iterate the current .while loop. */ +#define ROFF_LOOPEXIT 0x400 /* Exit the current .while loop. */ +#define ROFF_LOOPMASK 0xf00 + struct buf { char *buf; @@ -66,7 +77,7 @@ void roff_man_free(struct roff_man *); struct roff_man *roff_man_alloc(struct roff *, struct mparse *, const char *, int); void roff_man_reset(struct roff_man *); -enum rofferr roff_parseln(struct roff *, int, struct buf *, int *); +int roff_parseln(struct roff *, int, struct buf *, int *); void roff_userret(struct roff *); void roff_endparse(struct roff *); void roff_setreg(struct roff *, const char *, int, char sign); diff --git a/usr.bin/mandoc/mandoc.h b/usr.bin/mandoc/mandoc.h index fad9c87e079..6b39fc056ee 100644 --- a/usr.bin/mandoc/mandoc.h +++ b/usr.bin/mandoc/mandoc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mandoc.h,v 1.193 2018/08/23 19:32:03 schwarze Exp $ */ +/* $OpenBSD: mandoc.h,v 1.194 2018/08/24 22:56:37 schwarze Exp $ */ /* * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons * Copyright (c) 2010-2018 Ingo Schwarze @@ -228,6 +228,10 @@ enum mandocerr { MANDOCERR_TOOLARGE, /* input too large */ MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */ MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */ + MANDOCERR_WHILE_NEST, /* nested .while loops */ + MANDOCERR_WHILE_OUTOF, /* end of scope with open .while loop */ + MANDOCERR_WHILE_INTO, /* end of .while loop in inner scope */ + MANDOCERR_WHILE_FAIL, /* cannot continue this .while loop */ MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */ MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */ MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */ diff --git a/usr.bin/mandoc/read.c b/usr.bin/mandoc/read.c index 0041570781e..2ab9dae312e 100644 --- a/usr.bin/mandoc/read.c +++ b/usr.bin/mandoc/read.c @@ -1,4 +1,4 @@ -/* $OpenBSD: read.c,v 1.170 2018/08/23 19:32:03 schwarze Exp $ */ +/* $OpenBSD: read.c,v 1.171 2018/08/24 22:56:37 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010-2018 Ingo Schwarze @@ -47,6 +47,7 @@ struct mparse { const char *file; /* filename of current input file */ struct buf *primary; /* buffer currently being parsed */ struct buf *secondary; /* copy of top level input */ + struct buf *loop; /* open .while request line */ const char *os_s; /* default operating system */ mandocmsg mmsg; /* warning/error message handler */ enum mandoclevel file_status; /* status of current parse */ @@ -61,7 +62,7 @@ struct mparse { static void choose_parser(struct mparse *); static void free_buf_list(struct buf *); static void resize_buf(struct buf *, size_t); -static enum rofferr mparse_buf_r(struct mparse *, struct buf, size_t, int); +static int mparse_buf_r(struct mparse *, struct buf, size_t, int); static int read_whole_file(struct mparse *, const char *, int, struct buf *, int *); static void mparse_end(struct mparse *); @@ -264,6 +265,10 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "input too large", "unsupported control character", "unsupported roff request", + "nested .while loops", + "end of scope with open .while loop", + "end of .while loop in inner scope", + "cannot continue this .while loop", "eqn delim option in tbl", "unsupported tbl layout modifier", "ignoring macro in table", @@ -354,32 +359,31 @@ choose_parser(struct mparse *curp) * macros, inline equations, and input line traps) * and indirectly (for .so file inclusion). */ -static enum rofferr +static int mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) { struct buf ln; - struct buf *firstln, *lastln, *thisln; + struct buf *firstln, *lastln, *thisln, *loop; const char *save_file; char *cp; size_t pos; /* byte number in the ln buffer */ - enum rofferr line_result, result; + int line_result, result; int of; int lnn; /* line number in the real file */ int fd; + int inloop; /* Saw .while on this level. */ unsigned char c; ln.sz = 256; ln.buf = mandoc_malloc(ln.sz); ln.next = NULL; - firstln = NULL; + firstln = loop = NULL; lnn = curp->line; pos = 0; + inloop = 0; result = ROFF_CONT; - while (i < blk.sz) { - if (0 == pos && '\0' == blk.buf[i]) - break; - + while (i < blk.sz && (blk.buf[i] != '\0' || pos != 0)) { if (start) { curp->line = lnn; curp->reparse_count = 0; @@ -488,41 +492,95 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) rerun: line_result = roff_parseln(curp->roff, curp->line, &ln, &of); - switch (line_result) { + /* Process options. */ + + if (line_result & ROFF_APPEND) + assert(line_result == (ROFF_IGN | ROFF_APPEND)); + + if (line_result & ROFF_USERCALL) + assert((line_result & ROFF_MASK) == ROFF_REPARSE); + + if (line_result & ROFF_USERRET) { + assert(line_result == (ROFF_IGN | ROFF_USERRET)); + if (start == 0) { + /* Return from the current macro. */ + result = ROFF_USERRET; + goto out; + } + } + + switch (line_result & ROFF_LOOPMASK) { + case ROFF_IGN: + break; + case ROFF_WHILE: + if (curp->loop != NULL) { + if (loop == curp->loop) + break; + mandoc_msg(MANDOCERR_WHILE_NEST, + curp, curp->line, pos, NULL); + } + curp->loop = thisln; + loop = NULL; + inloop = 1; + break; + case ROFF_LOOPCONT: + case ROFF_LOOPEXIT: + if (curp->loop == NULL) { + mandoc_msg(MANDOCERR_WHILE_FAIL, + curp, curp->line, pos, NULL); + break; + } + if (inloop == 0) { + mandoc_msg(MANDOCERR_WHILE_INTO, + curp, curp->line, pos, NULL); + curp->loop = loop = NULL; + break; + } + if (line_result & ROFF_LOOPCONT) + loop = curp->loop; + else { + curp->loop = loop = NULL; + inloop = 0; + } + break; + default: + abort(); + } + + /* Process the main instruction from the roff parser. */ + + switch (line_result & ROFF_MASK) { + case ROFF_IGN: + break; + case ROFF_CONT: + if (curp->man->macroset == MACROSET_NONE) + choose_parser(curp); + if ((curp->man->macroset == MACROSET_MDOC ? + mdoc_parseln(curp->man, curp->line, ln.buf, of) : + man_parseln(curp->man, curp->line, ln.buf, of) + ) == 2) + goto out; + break; + case ROFF_RERUN: + goto rerun; case ROFF_REPARSE: - case ROFF_USERCALL: if (++curp->reparse_count > REPARSE_LIMIT) { + /* Abort and return to the top level. */ result = ROFF_IGN; mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, pos, NULL); - } else { - result = mparse_buf_r(curp, ln, of, 0); - if (line_result == ROFF_USERCALL) { - if (result == ROFF_USERRET) - result = ROFF_CONT; - roff_userret(curp->roff); - } - if (start || result == ROFF_CONT) { - pos = 0; - continue; - } + goto out; } - goto out; - case ROFF_USERRET: - if (start) { - pos = 0; - continue; + result = mparse_buf_r(curp, ln, of, 0); + if (line_result & ROFF_USERCALL) { + roff_userret(curp->roff); + /* Continue normally. */ + if (result & ROFF_USERRET) + result = ROFF_CONT; } - result = ROFF_USERRET; - goto out; - case ROFF_APPEND: - pos = strlen(ln.buf); - continue; - case ROFF_RERUN: - goto rerun; - case ROFF_IGN: - pos = 0; - continue; + if (start == 0 && result != ROFF_CONT) + goto out; + break; case ROFF_SO: if ( ! (curp->options & MPARSE_SO) && (i >= blk.sz || blk.buf[i] == '\0')) { @@ -547,30 +605,36 @@ rerun: of = 0; mparse_buf_r(curp, ln, of, 0); } - pos = 0; - continue; - default: break; + default: + abort(); } - if (curp->man->macroset == MACROSET_NONE) - choose_parser(curp); - - if ((curp->man->macroset == MACROSET_MDOC ? - mdoc_parseln(curp->man, curp->line, ln.buf, of) : - man_parseln(curp->man, curp->line, ln.buf, of)) == 2) - break; - - /* Temporary buffers typically are not full. */ - - if (0 == start && '\0' == blk.buf[i]) - break; - /* Start the next input line. */ - pos = 0; + if (loop != NULL && + (line_result & ROFF_LOOPMASK) == ROFF_IGN) + loop = loop->next; + + if (loop != NULL) { + if ((line_result & ROFF_APPEND) == 0) + *ln.buf = '\0'; + if (ln.sz < loop->sz) + resize_buf(&ln, loop->sz); + (void)strlcat(ln.buf, loop->buf, ln.sz); + of = 0; + goto rerun; + } + + pos = (line_result & ROFF_APPEND) ? strlen(ln.buf) : 0; } out: + if (inloop) { + if (result != ROFF_USERRET) + mandoc_msg(MANDOCERR_WHILE_OUTOF, curp, + curp->line, pos, NULL); + curp->loop = NULL; + } free(ln.buf); if (firstln != curp->secondary) free_buf_list(firstln); diff --git a/usr.bin/mandoc/roff.c b/usr.bin/mandoc/roff.c index 442196e892f..57ff4a137db 100644 --- a/usr.bin/mandoc/roff.c +++ b/usr.bin/mandoc/roff.c @@ -1,4 +1,4 @@ -/* $OpenBSD: roff.c,v 1.211 2018/08/23 14:16:12 schwarze Exp $ */ +/* $OpenBSD: roff.c,v 1.212 2018/08/24 22:56:37 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze @@ -141,7 +141,7 @@ struct roffnode { int pos, /* current pos in buffer */ \ int *offs /* reset offset of buffer data */ -typedef enum rofferr (*roffproc)(ROFF_ARGS); +typedef int (*roffproc)(ROFF_ARGS); struct roffmac { roffproc proc; /* process new macro */ @@ -161,26 +161,26 @@ struct predef { /* --- function prototypes ------------------------------------------------ */ -static void roffnode_cleanscope(struct roff *); -static void roffnode_pop(struct roff *); +static int roffnode_cleanscope(struct roff *); +static int roffnode_pop(struct roff *); static void roffnode_push(struct roff *, enum roff_tok, const char *, int, int); static void roff_addtbl(struct roff_man *, struct tbl_node *); -static enum rofferr roff_als(ROFF_ARGS); -static enum rofferr roff_block(ROFF_ARGS); -static enum rofferr roff_block_text(ROFF_ARGS); -static enum rofferr roff_block_sub(ROFF_ARGS); -static enum rofferr roff_br(ROFF_ARGS); -static enum rofferr roff_cblock(ROFF_ARGS); -static enum rofferr roff_cc(ROFF_ARGS); -static void roff_ccond(struct roff *, int, int); -static enum rofferr roff_cond(ROFF_ARGS); -static enum rofferr roff_cond_text(ROFF_ARGS); -static enum rofferr roff_cond_sub(ROFF_ARGS); -static enum rofferr roff_ds(ROFF_ARGS); -static enum rofferr roff_ec(ROFF_ARGS); -static enum rofferr roff_eo(ROFF_ARGS); -static enum rofferr roff_eqndelim(struct roff *, struct buf *, int); +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_br(ROFF_ARGS); +static int roff_cblock(ROFF_ARGS); +static int roff_cc(ROFF_ARGS); +static int roff_ccond(struct roff *, int, int); +static int roff_cond(ROFF_ARGS); +static int roff_cond_text(ROFF_ARGS); +static int roff_cond_sub(ROFF_ARGS); +static int roff_ds(ROFF_ARGS); +static int roff_ec(ROFF_ARGS); +static int roff_eo(ROFF_ARGS); +static int roff_eqndelim(struct roff *, struct buf *, int); static int roff_evalcond(struct roff *r, int, char *, int *); static int roff_evalnum(struct roff *, int, const char *, int *, int *, int); @@ -201,42 +201,42 @@ static const char *roff_getstrn(struct roff *, const char *, size_t, int *); static int roff_hasregn(const struct roff *, const char *, size_t); -static enum rofferr roff_insec(ROFF_ARGS); -static enum rofferr roff_it(ROFF_ARGS); -static enum rofferr roff_line_ignore(ROFF_ARGS); +static int roff_insec(ROFF_ARGS); +static int roff_it(ROFF_ARGS); +static int roff_line_ignore(ROFF_ARGS); static void roff_man_alloc1(struct roff_man *); static void roff_man_free1(struct roff_man *); -static enum rofferr roff_manyarg(ROFF_ARGS); -static enum rofferr roff_nop(ROFF_ARGS); -static enum rofferr roff_nr(ROFF_ARGS); -static enum rofferr roff_onearg(ROFF_ARGS); +static int roff_manyarg(ROFF_ARGS); +static int roff_nop(ROFF_ARGS); +static int roff_nr(ROFF_ARGS); +static int roff_onearg(ROFF_ARGS); static enum roff_tok roff_parse(struct roff *, char *, int *, int, int); -static enum rofferr roff_parsetext(struct roff *, struct buf *, +static int roff_parsetext(struct roff *, struct buf *, int, int *); -static enum rofferr roff_renamed(ROFF_ARGS); -static enum rofferr roff_res(struct roff *, struct buf *, int, int); -static enum rofferr roff_return(ROFF_ARGS); -static enum rofferr roff_rm(ROFF_ARGS); -static enum rofferr roff_rn(ROFF_ARGS); -static enum rofferr roff_rr(ROFF_ARGS); +static int roff_renamed(ROFF_ARGS); +static int roff_res(struct roff *, struct buf *, int, int); +static int roff_return(ROFF_ARGS); +static int roff_rm(ROFF_ARGS); +static int roff_rn(ROFF_ARGS); +static int roff_rr(ROFF_ARGS); static void roff_setregn(struct roff *, const char *, size_t, int, char, int); static void roff_setstr(struct roff *, const char *, const char *, int); static void roff_setstrn(struct roffkv **, const char *, size_t, const char *, size_t, int); -static enum rofferr roff_shift(ROFF_ARGS); -static enum rofferr roff_so(ROFF_ARGS); -static enum rofferr roff_tr(ROFF_ARGS); -static enum rofferr roff_Dd(ROFF_ARGS); -static enum rofferr roff_TE(ROFF_ARGS); -static enum rofferr roff_TS(ROFF_ARGS); -static enum rofferr roff_EQ(ROFF_ARGS); -static enum rofferr roff_EN(ROFF_ARGS); -static enum rofferr roff_T_(ROFF_ARGS); -static enum rofferr roff_unsupp(ROFF_ARGS); -static enum rofferr roff_userdef(ROFF_ARGS); +static int roff_shift(ROFF_ARGS); +static int roff_so(ROFF_ARGS); +static int roff_tr(ROFF_ARGS); +static int roff_Dd(ROFF_ARGS); +static int roff_TE(ROFF_ARGS); +static int roff_TS(ROFF_ARGS); +static int roff_EQ(ROFF_ARGS); +static int roff_EN(ROFF_ARGS); +static int roff_T_(ROFF_ARGS); +static int roff_unsupp(ROFF_ARGS); +static int roff_userdef(ROFF_ARGS); /* --- constant data ------------------------------------------------------ */ @@ -588,7 +588,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_line_ignore, NULL, NULL, 0 }, /* watchlength */ { roff_line_ignore, NULL, NULL, 0 }, /* watchn */ { roff_unsupp, NULL, NULL, 0 }, /* wh */ - { roff_unsupp, NULL, NULL, 0 }, /* while */ + { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /*while*/ { roff_insec, NULL, NULL, 0 }, /* write */ { roff_insec, NULL, NULL, 0 }, /* writec */ { roff_insec, NULL, NULL, 0 }, /* writem */ @@ -672,18 +672,19 @@ roffhash_find(struct ohash *htab, const char *name, size_t sz) * Pop the current node off of the stack of roff instructions currently * pending. */ -static void +static int roffnode_pop(struct roff *r) { struct roffnode *p; + int inloop; - assert(r->last); p = r->last; - - r->last = r->last->parent; + inloop = p->tok == ROFF_while; + r->last = p->parent; free(p->name); free(p->end); free(p); + return inloop; } /* @@ -1142,7 +1143,7 @@ deroff(char **dest, const struct roff_node *n) * used in numerical expressions and conditional requests. * Also check the syntax of the remaining escape sequences. */ -static enum rofferr +static int roff_res(struct roff *r, struct buf *buf, int ln, int pos) { struct mctx *ctx; /* current macro call context */ @@ -1234,7 +1235,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) if (stesc[1] == '#') { *stesc = '\0'; - return ROFF_APPEND; + return ROFF_IGN | ROFF_APPEND; } /* Discard normal comments. */ @@ -1292,7 +1293,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) if (done) continue; else - return ROFF_APPEND; + return ROFF_IGN | ROFF_APPEND; } /* Decide whether to expand or to check only. */ @@ -1527,7 +1528,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos) /* * Process text streams. */ -static enum rofferr +static int roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs) { size_t sz; @@ -1593,11 +1594,11 @@ roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs) return ROFF_CONT; } -enum rofferr +int roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) { enum roff_tok t; - enum rofferr e; + int e; int pos; /* parse point */ int spos; /* saved parse point for messages */ int ppos; /* original offset in buf->buf */ @@ -1619,7 +1620,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) /* Expand some escape sequences. */ e = roff_res(r, buf, ln, pos); - if (e == ROFF_IGN || e == ROFF_APPEND) + if ((e & ROFF_MASK) == ROFF_IGN) return e; assert(e == ROFF_CONT); @@ -1636,21 +1637,22 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs) if (r->last != NULL && ! ctl) { t = r->last->tok; e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs); - if (e == ROFF_IGN) + if ((e & ROFF_MASK) == ROFF_IGN) return e; - assert(e == ROFF_CONT); - } + e &= ~ROFF_MASK; + } else + e = ROFF_IGN; if (r->eqn != NULL && strncmp(buf->buf + ppos, ".EN", 3)) { eqn_read(r->eqn, buf->buf + ppos); - return ROFF_IGN; + return e; } if (r->tbl != NULL && (ctl == 0 || buf->buf[pos] == '\0')) { tbl_read(r->tbl, ln, buf->buf, ppos); roff_addtbl(r->man, r->tbl); - return ROFF_IGN; + return e; } if ( ! ctl) - return roff_parsetext(r, buf, pos, offs); + return roff_parsetext(r, buf, pos, offs) | e; /* Skip empty request lines. */ @@ -1806,7 +1808,7 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos) /* --- handling of request blocks ----------------------------------------- */ -static enum rofferr +static int roff_cblock(ROFF_ARGS) { @@ -1846,50 +1848,51 @@ roff_cblock(ROFF_ARGS) } -static void +static int roffnode_cleanscope(struct roff *r) { + int inloop; - while (r->last) { + inloop = 0; + while (r->last != NULL) { if (--r->last->endspan != 0) break; - roffnode_pop(r); + inloop += roffnode_pop(r); } + return inloop; } -static void +static int roff_ccond(struct roff *r, int ln, int ppos) { - if (NULL == r->last) { mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "\\}"); - return; + return 0; } switch (r->last->tok) { case ROFF_el: case ROFF_ie: case ROFF_if: + case ROFF_while: break; default: mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "\\}"); - return; + return 0; } if (r->last->endspan > -1) { mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "\\}"); - return; + return 0; } - roffnode_pop(r); - roffnode_cleanscope(r); - return; + return roffnode_pop(r) + roffnode_cleanscope(r); } -static enum rofferr +static int roff_block(ROFF_ARGS) { const char *name, *value; @@ -2014,7 +2017,7 @@ roff_block(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_block_sub(ROFF_ARGS) { enum roff_tok t; @@ -2068,7 +2071,7 @@ roff_block_sub(ROFF_ARGS) return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); } -static enum rofferr +static int roff_block_text(ROFF_ARGS) { @@ -2078,15 +2081,19 @@ roff_block_text(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_cond_sub(ROFF_ARGS) { - enum roff_tok t; char *ep; - int rr; + int endloop, irc, rr; + enum roff_tok t; + irc = ROFF_IGN; rr = r->last->rule; - roffnode_cleanscope(r); + endloop = tok != ROFF_while ? ROFF_IGN : + rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT; + if (roffnode_cleanscope(r)) + irc |= endloop; /* * If `\}' occurs on a macro line without a preceding macro, @@ -2103,7 +2110,8 @@ roff_cond_sub(ROFF_ARGS) switch (ep[1]) { case '}': memmove(ep, ep + 2, strlen(ep + 2) + 1); - roff_ccond(r, ln, ep - buf->buf); + if (roff_ccond(r, ln, ep - buf->buf)) + irc |= endloop; break; case '\0': ++ep; @@ -2120,30 +2128,38 @@ roff_cond_sub(ROFF_ARGS) */ t = roff_parse(r, buf->buf, &pos, ln, ppos); - return t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) - ? (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) : rr - ? ROFF_CONT : ROFF_IGN; + 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; + return irc; } -static enum rofferr +static int roff_cond_text(ROFF_ARGS) { char *ep; - int rr; + int endloop, irc, rr; + irc = ROFF_IGN; rr = r->last->rule; - roffnode_cleanscope(r); + endloop = tok != ROFF_while ? ROFF_IGN : + rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT; + if (roffnode_cleanscope(r)) + irc |= endloop; ep = buf->buf + pos; while ((ep = strchr(ep, '\\')) != NULL) { if (*(++ep) == '}') { *ep = '&'; - roff_ccond(r, ln, ep - buf->buf - 1); + if (roff_ccond(r, ln, ep - buf->buf - 1)) + irc |= endloop; } if (*ep != '\0') ++ep; } - return rr ? ROFF_CONT : ROFF_IGN; + if (rr) + irc |= ROFF_CONT; + return irc; } /* --- handling of numeric and conditional expressions -------------------- */ @@ -2363,14 +2379,14 @@ roff_evalcond(struct roff *r, int ln, char *v, int *pos) return 0; } -static enum rofferr +static int roff_line_ignore(ROFF_ARGS) { return ROFF_IGN; } -static enum rofferr +static int roff_insec(ROFF_ARGS) { @@ -2379,7 +2395,7 @@ roff_insec(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_unsupp(ROFF_ARGS) { @@ -2388,9 +2404,10 @@ roff_unsupp(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_cond(ROFF_ARGS) { + int irc; roffnode_push(r, tok, NULL, ln, ppos); @@ -2429,9 +2446,10 @@ roff_cond(ROFF_ARGS) * Determine scope. * If there is nothing on the line after the conditional, * not even whitespace, use next-line scope. + * Except that .while does not support next-line scope. */ - if (buf->buf[pos] == '\0') { + if (buf->buf[pos] == '\0' && tok != ROFF_while) { r->last->endspan = 2; goto out; } @@ -2463,10 +2481,13 @@ roff_cond(ROFF_ARGS) out: *offs = pos; - return ROFF_RERUN; + irc = ROFF_RERUN; + if (tok == ROFF_while) + irc |= ROFF_WHILE; + return irc; } -static enum rofferr +static int roff_ds(ROFF_ARGS) { char *string; @@ -2855,7 +2876,7 @@ roff_freereg(struct roffreg *reg) } } -static enum rofferr +static int roff_nr(ROFF_ARGS) { char *key, *val, *step; @@ -2889,7 +2910,7 @@ roff_nr(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_rr(ROFF_ARGS) { struct roffreg *reg, **prev; @@ -2919,7 +2940,7 @@ roff_rr(ROFF_ARGS) /* --- handler functions for roff requests -------------------------------- */ -static enum rofferr +static int roff_rm(ROFF_ARGS) { const char *name; @@ -2938,7 +2959,7 @@ roff_rm(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_it(ROFF_ARGS) { int iv; @@ -2967,7 +2988,7 @@ roff_it(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_Dd(ROFF_ARGS) { int mask; @@ -2997,7 +3018,7 @@ roff_Dd(ROFF_ARGS) return ROFF_CONT; } -static enum rofferr +static int roff_TE(ROFF_ARGS) { if (r->tbl == NULL) { @@ -3017,7 +3038,7 @@ roff_TE(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_T_(ROFF_ARGS) { @@ -3033,7 +3054,7 @@ roff_T_(ROFF_ARGS) /* * Handle in-line equation delimiters. */ -static enum rofferr +static int roff_eqndelim(struct roff *r, struct buf *buf, int pos) { char *cp1, *cp2; @@ -3096,7 +3117,7 @@ roff_eqndelim(struct roff *r, struct buf *buf, int pos) return ROFF_REPARSE; } -static enum rofferr +static int roff_EQ(ROFF_ARGS) { struct roff_node *n; @@ -3126,7 +3147,7 @@ roff_EQ(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_EN(ROFF_ARGS) { if (r->eqn != NULL) { @@ -3140,7 +3161,7 @@ roff_EN(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_TS(ROFF_ARGS) { if (r->tbl != NULL) { @@ -3157,7 +3178,7 @@ roff_TS(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_onearg(ROFF_ARGS) { struct roff_node *n; @@ -3217,7 +3238,7 @@ roff_onearg(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_manyarg(ROFF_ARGS) { struct roff_node *n; @@ -3240,7 +3261,7 @@ roff_manyarg(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_als(ROFF_ARGS) { char *oldn, *newn, *end, *value; @@ -3267,7 +3288,7 @@ roff_als(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_br(ROFF_ARGS) { if (r->man->flags & (MAN_BLINE | MAN_ELINE)) @@ -3281,7 +3302,7 @@ roff_br(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_cc(ROFF_ARGS) { const char *p; @@ -3298,7 +3319,7 @@ roff_cc(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_ec(ROFF_ARGS) { const char *p; @@ -3315,7 +3336,7 @@ roff_ec(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_eo(ROFF_ARGS) { r->escape = '\0'; @@ -3325,7 +3346,7 @@ roff_eo(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_nop(ROFF_ARGS) { while (buf->buf[pos] == ' ') @@ -3334,7 +3355,7 @@ roff_nop(ROFF_ARGS) return ROFF_RERUN; } -static enum rofferr +static int roff_tr(ROFF_ARGS) { const char *p, *first, *second; @@ -3402,17 +3423,17 @@ roff_tr(ROFF_ARGS) * The read module will call that after rewinding the reader stack * to the place from where the current macro was called. */ -static enum rofferr +static int roff_return(ROFF_ARGS) { if (r->mstackpos >= 0) - return ROFF_USERRET; + return ROFF_IGN | ROFF_USERRET; mandoc_msg(MANDOCERR_REQ_NOMAC, r->parse, ln, ppos, "return"); return ROFF_IGN; } -static enum rofferr +static int roff_rn(ROFF_ARGS) { const char *value; @@ -3462,7 +3483,7 @@ roff_rn(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_shift(ROFF_ARGS) { struct mctx *ctx; @@ -3495,7 +3516,7 @@ roff_shift(ROFF_ARGS) return ROFF_IGN; } -static enum rofferr +static int roff_so(ROFF_ARGS) { char *name, *cp; @@ -3527,7 +3548,7 @@ roff_so(ROFF_ARGS) /* --- user defined strings and macros ------------------------------------ */ -static enum rofferr +static int roff_userdef(ROFF_ARGS) { struct mctx *ctx; @@ -3581,14 +3602,14 @@ roff_userdef(ROFF_ARGS) *offs = 0; return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ? - ROFF_USERCALL : ROFF_APPEND; + ROFF_REPARSE | ROFF_USERCALL : ROFF_IGN | ROFF_APPEND; } /* * Calling a high-level macro that was renamed with .rn. * r->current_string has already been set up by roff_parse(). */ -static enum rofferr +static int roff_renamed(ROFF_ARGS) { char *nbuf; -- 2.20.1