X-Git-Url: https://git.cameronkatri.com/mandoc.git/blobdiff_plain/b20db833ab9fe345d4463b10d6fa74aa21c49aca..4a599f470e8524900db79db76d5a05dca9ce00f7:/roff.c?ds=sidebyside

diff --git a/roff.c b/roff.c
index 999fda5b..33361402 100644
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/*	$Id: roff.c,v 1.216 2014/07/03 21:23:54 schwarze Exp $ */
+/*	$Id: roff.c,v 1.226 2014/08/19 16:52:32 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,9 +15,9 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
+
+#include <sys/types.h>
 
 #include <assert.h>
 #include <ctype.h>
@@ -27,8 +27,8 @@
 
 #include "mandoc.h"
 #include "mandoc_aux.h"
-#include "libroff.h"
 #include "libmandoc.h"
+#include "libroff.h"
 
 /* Maximum number of nested if-else conditionals. */
 #define	RSTACK_MAX	128
@@ -106,11 +106,8 @@ struct	roffreg {
 
 struct	roff {
 	struct mparse	*parse; /* parse point */
-	int		 options; /* parse options */
 	struct roffnode	*last; /* leaf of stack */
-	int		 rstack[RSTACK_MAX]; /* stack of !`ie' rules */
-	char		 control; /* control character */
-	int		 rstackpos; /* position in rstack */
+	int		*rstack; /* stack of inverted `ie' values */
 	struct roffreg	*regtab; /* number registers */
 	struct roffkv	*strtab; /* user-defined strings & macros */
 	struct roffkv	*xmbtab; /* multi-byte trans table (`tr') */
@@ -122,6 +119,10 @@ struct	roff {
 	struct eqn_node	*last_eqn; /* last equation parsed */
 	struct eqn_node	*first_eqn; /* first equation parsed */
 	struct eqn_node	*eqn; /* current equation being parsed */
+	int		 options; /* parse options */
+	int		 rstacksz; /* current size limit of rstack */
+	int		 rstackpos; /* position in rstack */
+	char		 control; /* control character */
 };
 
 struct	roffnode {
@@ -420,32 +421,32 @@ roff_free1(struct roff *r)
 		r->first_tbl = tbl->next;
 		tbl_free(tbl);
 	}
-
 	r->first_tbl = r->last_tbl = r->tbl = NULL;
 
 	while (NULL != (e = r->first_eqn)) {
 		r->first_eqn = e->next;
 		eqn_free(e);
 	}
-
 	r->first_eqn = r->last_eqn = r->eqn = NULL;
 
 	while (r->last)
 		roffnode_pop(r);
 
-	roff_freestr(r->strtab);
-	roff_freestr(r->xmbtab);
-
-	r->strtab = r->xmbtab = NULL;
+	free (r->rstack);
+	r->rstack = NULL;
+	r->rstacksz = 0;
+	r->rstackpos = -1;
 
 	roff_freereg(r->regtab);
-
 	r->regtab = NULL;
 
+	roff_freestr(r->strtab);
+	roff_freestr(r->xmbtab);
+	r->strtab = r->xmbtab = NULL;
+
 	if (r->xtab)
 		for (i = 0; i < 128; i++)
 			free(r->xtab[i].p);
-
 	free(r->xtab);
 	r->xtab = NULL;
 }
@@ -500,7 +501,7 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 	size_t		 naml;	/* actual length of the escape name */
 	int		 expand_count;	/* to avoid infinite loops */
 	int		 npos;	/* position in numeric expression */
-	int		 irc;	/* return code from roff_evalnum() */
+	int		 arg_complete; /* argument not interrupted by eol */
 	char		 term;	/* character terminating the escape */
 
 	expand_count = 0;
@@ -542,8 +543,9 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 			break;
 		default:
 			if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL))
-				mandoc_msg(MANDOCERR_BADESCAPE, r->parse,
-				    ln, (int)(stesc - *bufp), NULL);
+				mandoc_vmsg(MANDOCERR_ESC_BAD,
+				    r->parse, ln, (int)(stesc - *bufp),
+				    "%.*s", (int)(cp - stesc), stesc);
 			continue;
 		}
 
@@ -585,10 +587,12 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 
 		/* Advance to the end of the name. */
 
+		arg_complete = 1;
 		for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
 			if ('\0' == *cp) {
-				mandoc_msg(MANDOCERR_BADESCAPE, r->parse,
-				    ln, (int)(stesc - *bufp), NULL);
+				mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+				    ln, (int)(stesc - *bufp), stesc);
+				arg_complete = 0;
 				break;
 			}
 			if (0 == maxl && *cp == term) {
@@ -604,28 +608,34 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 
 		switch (stesc[1]) {
 		case '*':
-			res = roff_getstrn(r, stnam, naml);
+			if (arg_complete)
+				res = roff_getstrn(r, stnam, naml);
 			break;
 		case 'B':
 			npos = 0;
-			irc = roff_evalnum(stnam, &npos, NULL, 0);
-			ubuf[0] = irc && stnam + npos + 1 == cp
-			    ? '1' : '0';
+			ubuf[0] = arg_complete &&
+			    roff_evalnum(stnam, &npos, NULL, 0) &&
+			    stnam + npos + 1 == cp ? '1' : '0';
 			ubuf[1] = '\0';
 			break;
 		case 'n':
-			(void)snprintf(ubuf, sizeof(ubuf), "%d",
-			    roff_getregn(r, stnam, naml));
+			if (arg_complete)
+				(void)snprintf(ubuf, sizeof(ubuf), "%d",
+				    roff_getregn(r, stnam, naml));
+			else
+				ubuf[0] = '\0';
 			break;
 		case 'w':
+			/* use even incomplete args */
 			(void)snprintf(ubuf, sizeof(ubuf), "%d",
 			    24 * (int)naml);
 			break;
 		}
 
 		if (NULL == res) {
-			mandoc_msg(MANDOCERR_BADESCAPE, r->parse,
-			    ln, (int)(stesc - *bufp), NULL);
+			mandoc_vmsg(MANDOCERR_STR_UNDEF,
+			    r->parse, ln, (int)(stesc - *bufp),
+			    "%.*s", (int)naml, stnam);
 			res = "";
 		}
 
@@ -777,18 +787,19 @@ roff_endparse(struct roff *r)
 {
 
 	if (r->last)
-		mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
-		    r->last->line, r->last->col, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+		    r->last->line, r->last->col,
+		    roffs[r->last->tok].name);
 
 	if (r->eqn) {
-		mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
-		    r->eqn->eqn.ln, r->eqn->eqn.pos, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+		    r->eqn->eqn.ln, r->eqn->eqn.pos, "EQ");
 		eqn_end(&r->eqn);
 	}
 
 	if (r->tbl) {
-		mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
-		    r->tbl->line, r->tbl->pos, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+		    r->tbl->line, r->tbl->pos, "TS");
 		tbl_end(&r->tbl);
 	}
 }
@@ -832,17 +843,17 @@ roff_cblock(ROFF_ARGS)
 	 */
 
 	if (NULL == r->last) {
-		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+		    ln, ppos, "..");
 		return(ROFF_IGN);
 	}
 
 	switch (r->last->tok) {
 	case ROFF_am:
+		/* ROFF_am1 is remapped to ROFF_am in roff_block(). */
 		/* FALLTHROUGH */
 	case ROFF_ami:
 		/* FALLTHROUGH */
-	case ROFF_am1:
-		/* FALLTHROUGH */
 	case ROFF_de:
 		/* ROFF_de1 is remapped to ROFF_de in roff_block(). */
 		/* FALLTHROUGH */
@@ -851,12 +862,14 @@ roff_cblock(ROFF_ARGS)
 	case ROFF_ig:
 		break;
 	default:
-		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+		    ln, ppos, "..");
 		return(ROFF_IGN);
 	}
 
 	if ((*bufp)[pos])
-		mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
+		mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
+		    ".. %s", *bufp + pos);
 
 	roffnode_pop(r);
 	roffnode_cleanscope(r);
@@ -880,7 +893,8 @@ roff_ccond(struct roff *r, int ln, int ppos)
 {
 
 	if (NULL == r->last) {
-		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+		    ln, ppos, "\\}");
 		return;
 	}
 
@@ -892,12 +906,14 @@ roff_ccond(struct roff *r, int ln, int ppos)
 	case ROFF_if:
 		break;
 	default:
-		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+		    ln, ppos, "\\}");
 		return;
 	}
 
 	if (r->last->endspan > -1) {
-		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+		    ln, ppos, "\\}");
 		return;
 	}
 
@@ -909,34 +925,47 @@ roff_ccond(struct roff *r, int ln, int ppos)
 static enum rofferr
 roff_block(ROFF_ARGS)
 {
-	char		*name, *cp;
+	const char	*name;
+	char		*iname, *cp;
 	size_t		 namesz;
 
-	name = cp = *bufp + pos;
-	namesz = 0;
+	/* Ignore groff compatibility mode for now. */
 
-	if (ROFF_ig != tok) {
-		if ('\0' == *cp) {
-			mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse,
-			    ln, ppos, roffs[tok].name);
-			return(ROFF_IGN);
-		}
+	if (ROFF_de1 == tok)
+		tok = ROFF_de;
+	else if (ROFF_am1 == tok)
+		tok = ROFF_am;
 
-		/*
-		 * Re-write `de1', since we don't really care about
-		 * groff's strange compatibility mode, into `de'.
-		 */
-
-		if (ROFF_de1 == tok)
-			tok = ROFF_de;
-		else if (ROFF_de != tok)
-			mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
-			    roffs[tok].name);
+	/* Parse the macro name argument. */
 
+	cp = *bufp + pos;
+	if (ROFF_ig == tok) {
+		iname = NULL;
+		namesz = 0;
+	} else {
+		iname = cp;
 		namesz = roff_getname(r, &cp, ln, ppos);
-		name[namesz] = '\0';
+		iname[namesz] = '\0';
+	}
+
+	/* Resolve the macro name argument if it is indirect. */
+
+	if (namesz && (ROFF_dei == tok || ROFF_ami == tok)) {
+		if (NULL == (name = roff_getstrn(r, iname, namesz))) {
+			mandoc_vmsg(MANDOCERR_STR_UNDEF,
+			    r->parse, ln, (int)(iname - *bufp),
+			    "%.*s", (int)namesz, iname);
+			namesz = 0;
+		} else
+			namesz = strlen(name);
 	} else
-		name = NULL;
+		name = iname;
+
+	if (0 == namesz && ROFF_ig != tok) {
+		mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse,
+		    ln, ppos, roffs[tok].name);
+		return(ROFF_IGN);
+	}
 
 	roffnode_push(r, tok, name, ln, ppos);
 
@@ -946,21 +975,36 @@ roff_block(ROFF_ARGS)
 	 * appended from roff_block_text() in multiline mode.
 	 */
 
-	if (namesz && ROFF_de == tok)
+	if (ROFF_de == tok || ROFF_dei == tok)
 		roff_setstrn(&r->strtab, name, namesz, "", 0, 0);
 
 	if ('\0' == *cp)
 		return(ROFF_IGN);
 
-	/* If present, process the custom end-of-line marker. */
+	/* Get the custom end marker. */
 
-	name = cp;
+	iname = cp;
 	namesz = roff_getname(r, &cp, ln, ppos);
+
+	/* Resolve the end marker if it is indirect. */
+
+	if (namesz && (ROFF_dei == tok || ROFF_ami == tok)) {
+		if (NULL == (name = roff_getstrn(r, iname, namesz))) {
+			mandoc_vmsg(MANDOCERR_STR_UNDEF,
+			    r->parse, ln, (int)(iname - *bufp),
+			    "%.*s", (int)namesz, iname);
+			namesz = 0;
+		} else
+			namesz = strlen(name);
+	} else
+		name = iname;
+
 	if (namesz)
 		r->last->end = mandoc_strndup(name, namesz);
 
 	if ('\0' != *cp)
-		mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
+		mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
+		    ln, pos, ".%s ... %s", roffs[tok].name, cp);
 
 	return(ROFF_IGN);
 }
@@ -1009,12 +1053,8 @@ roff_block_sub(ROFF_ARGS)
 
 	t = roff_parse(r, *bufp, &pos, ln, ppos);
 
-	/*
-	 * Macros other than block-end are only significant
-	 * in `de' blocks; elsewhere, simply throw them away.
-	 */
 	if (ROFF_cblock != t) {
-		if (ROFF_de == tok)
+		if (ROFF_ig != tok)
 			roff_setstr(r, r->last->name, *bufp + ppos, 2);
 		return(ROFF_IGN);
 	}
@@ -1027,7 +1067,7 @@ static enum rofferr
 roff_block_text(ROFF_ARGS)
 {
 
-	if (ROFF_de == tok)
+	if (ROFF_ig != tok)
 		roff_setstr(r, r->last->name, *bufp + pos, 2);
 
 	return(ROFF_IGN);
@@ -1244,10 +1284,10 @@ roff_cond(ROFF_ARGS)
 	 */
 
 	if (ROFF_ie == tok) {
-		if (r->rstackpos == RSTACK_MAX - 1) {
-			mandoc_msg(MANDOCERR_MEM,
-			    r->parse, ln, ppos, NULL);
-			return(ROFF_ERR);
+		if (r->rstackpos + 1 == r->rstacksz) {
+			r->rstacksz += 16;
+			r->rstack = mandoc_reallocarray(r->rstack,
+			    r->rstacksz, sizeof(int));
 		}
 		r->rstack[++r->rstackpos] = !r->last->rule;
 	}
@@ -1719,7 +1759,7 @@ roff_it(ROFF_ARGS)
 	len = strcspn(cp, " \t");
 	cp[len] = '\0';
 	if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
-		mandoc_msg(MANDOCERR_NUMERIC, r->parse,
+		mandoc_msg(MANDOCERR_IT_NONUM, r->parse,
 		    ln, ppos, *bufp + 1);
 		return(ROFF_IGN);
 	}
@@ -1760,7 +1800,8 @@ roff_TE(ROFF_ARGS)
 {
 
 	if (NULL == r->tbl)
-		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+		    ln, ppos, "TE");
 	else
 		tbl_end(&r->tbl);
 
@@ -1772,7 +1813,8 @@ roff_T_(ROFF_ARGS)
 {
 
 	if (NULL == r->tbl)
-		mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+		mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+		    ln, ppos, "T&");
 	else
 		tbl_restart(ppos, ln, r->tbl);
 
@@ -1823,7 +1865,7 @@ static enum rofferr
 roff_EN(ROFF_ARGS)
 {
 
-	mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+	mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN");
 	return(ROFF_IGN);
 }
 
@@ -1833,7 +1875,8 @@ roff_TS(ROFF_ARGS)
 	struct tbl_node	*tbl;
 
 	if (r->tbl) {
-		mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
+		mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse,
+		    ln, ppos, "TS breaks TS");
 		tbl_end(&r->tbl);
 	}
 
@@ -1885,9 +1928,8 @@ roff_tr(ROFF_ARGS)
 		if ('\\' == *first) {
 			esc = mandoc_escape(&p, NULL, NULL);
 			if (ESCAPE_ERROR == esc) {
-				mandoc_msg(MANDOCERR_BADESCAPE,
-				    r->parse, ln,
-				    (int)(p - *bufp), NULL);
+				mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+				    ln, (int)(p - *bufp), first);
 				return(ROFF_IGN);
 			}
 			fsz = (size_t)(p - first);
@@ -1897,9 +1939,8 @@ roff_tr(ROFF_ARGS)
 		if ('\\' == *second) {
 			esc = mandoc_escape(&p, NULL, NULL);
 			if (ESCAPE_ERROR == esc) {
-				mandoc_msg(MANDOCERR_BADESCAPE,
-				    r->parse, ln,
-				    (int)(p - *bufp), NULL);
+				mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+				    ln, (int)(p - *bufp), second);
 				return(ROFF_IGN);
 			}
 			ssz = (size_t)(p - second);
@@ -1934,7 +1975,7 @@ roff_so(ROFF_ARGS)
 	char *name;
 
 	name = *bufp + pos;
-	mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, ".so %s", name);
+	mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name);
 
 	/*
 	 * Handle `so'.  Be EXTREMELY careful, as we shouldn't be
@@ -2026,7 +2067,8 @@ roff_getname(struct roff *r, char **cpp, int ln, int pos)
 		cp++;
 		if ('\\' == *cp)
 			continue;
-		mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL);
+		mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos,
+		    "%.*s", (int)(cp - name + 1), name);
 		mandoc_escape((const char **)&cp, NULL, NULL);
 		break;
 	}