source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Fully implement the \B (validate numerical expression) and
@ 2014-04-08  1:37 schwarze
  0 siblings, 0 replies; only message in thread
From: schwarze @ 2014-04-08  1:37 UTC (permalink / raw)
  To: source

Log Message:
-----------
Fully implement the \B (validate numerical expression) and 
partially implement the \w (measure text width) escape sequence
in a way that makes them usable in numerical expressions and in 
conditional requests, similar to how \n (interpolate number register)
and \* (expand user-defined string) are implemented.

This lets mandoc(1) handle the baroque low-level roff code
found at the beginning of the ggrep(1) manual.
Thanks to pascal@ for the report.

Modified Files:
--------------
    mdocml:
        mandoc.c
        roff.7
        roff.c

Revision Data
-------------
Index: mandoc.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/mandoc.c,v
retrieving revision 1.77
retrieving revision 1.78
diff -Lmandoc.c -Lmandoc.c -u -p -r1.77 -r1.78
--- mandoc.c
+++ mandoc.c
@@ -1,7 +1,7 @@
 /*	$Id$ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -161,20 +161,17 @@ mandoc_escape(const char **end, const ch
 	/*
 	 * These escapes are of the form \X'Y', where 'X' is the trigger
 	 * and 'Y' is any string.  These have opaque sub-strings.
+	 * The \B and \w escapes are handled in roff.c, roff_res().
 	 */
 	case ('A'):
 		/* FALLTHROUGH */
 	case ('b'):
 		/* FALLTHROUGH */
-	case ('B'):
-		/* FALLTHROUGH */
 	case ('D'):
 		/* FALLTHROUGH */
 	case ('o'):
 		/* FALLTHROUGH */
 	case ('R'):
-		/* FALLTHROUGH */
-	case ('w'):
 		/* FALLTHROUGH */
 	case ('X'):
 		/* FALLTHROUGH */
Index: roff.7
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/roff.7,v
retrieving revision 1.53
retrieving revision 1.54
diff -Lroff.7 -Lroff.7 -u -p -r1.53 -r1.54
--- roff.7
+++ roff.7
@@ -1172,10 +1172,15 @@ Digit width space character.
 Anchor definition; ignored by
 .Xr mandoc 1 .
 .Ss \eB\(aq Ns Ar string Ns \(aq
-Test whether
+Interpolate
+.Sq 1
+if
 .Ar string
-is a numerical expession; ignored by
-.Xr mandoc 1 .
+conforms to the syntax of
+.Sx Numerical expressions
+explained above and
+.Sq 0
+otherwise.
 .Ss \eb\(aq Ns Ar string Ns \(aq
 Bracket building function; ignored by
 .Xr mandoc 1 .
@@ -1299,9 +1304,13 @@ Vertical motion; ignored by
 .Xr mandoc 1 .
 .Ss \ew\(aq Ns Ar string Ns \(aq
 Interpolate the width of the
-.Ar string ;
-ignored by
-.Xr mandoc 1 .
+.Ar string .
+The
+.Xr mandoc 1
+implementation assumes that after expansion of user-defined strings, the
+.Ar string
+only contains normal characters, no escape sequences, and that each
+character has a width of 24 basic units.
 .Ss \eX\(aq Ns Ar string Ns \(aq
 Output
 .Ar string
Index: roff.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/roff.c,v
retrieving revision 1.205
retrieving revision 1.206
diff -Lroff.c -Lroff.c -u -p -r1.205 -r1.206
--- roff.c
+++ roff.c
@@ -485,9 +485,9 @@ roff_alloc(struct mparse *parse, int opt
 }
 
 /*
- * In the current line, expand user-defined strings ("\*")
- * and references to number registers ("\n").
- * Also check the syntax of other escape sequences.
+ * In the current line, expand escape sequences that tend to get
+ * used in numerical expressions and conditional requests.
+ * Also check the syntax of the remaining escape sequences.
  */
 static enum rofferr
 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
@@ -503,6 +503,9 @@ roff_res(struct roff *r, char **bufp, si
 	size_t		 naml;	/* actual length of the escape name */
 	size_t		 ressz;	/* size of the replacement string */
 	int		 expand_count;	/* to avoid infinite loops */
+	int		 npos;	/* position in numeric expression */
+	int		 irc;	/* return code from roff_evalnum() */
+	char		 term;	/* character terminating the escape */
 
 	expand_count = 0;
 	start = *bufp + pos;
@@ -525,16 +528,19 @@ roff_res(struct roff *r, char **bufp, si
 			continue;
 		}
 
-		/*
-		 * Everything except user-defined strings and number
-		 * registers is only checked, not expanded.
-		 */
+		/* Decide whether to expand or to check only. */
 
+		term = '\0';
 		cp = stesc + 1;
 		switch (*cp) {
 		case ('*'):
 			res = NULL;
 			break;
+		case ('B'):
+			/* FALLTHROUGH */
+		case ('w'):
+			term = cp[1];
+			/* FALLTHROUGH */
 		case ('n'):
 			res = ubuf;
 			break;
@@ -557,20 +563,27 @@ roff_res(struct roff *r, char **bufp, si
 		 * Save a pointer to the name.
 		 */
 
-		switch (*++cp) {
-		case ('\0'):
-			continue;
-		case ('('):
-			cp++;
-			maxl = 2;
-			break;
-		case ('['):
-			cp++;
+		if ('\0' == term) {
+			switch (*++cp) {
+			case ('\0'):
+				maxl = 0;
+				break;
+			case ('('):
+				cp++;
+				maxl = 2;
+				break;
+			case ('['):
+				cp++;
+				term = ']';
+				maxl = 0;
+				break;
+			default:
+				maxl = 1;
+				break;
+			}
+		} else {
+			cp += 2;
 			maxl = 0;
-			break;
-		default:
-			maxl = 1;
-			break;
 		}
 		stnam = cp;
 
@@ -582,10 +595,12 @@ roff_res(struct roff *r, char **bufp, si
 					(MANDOCERR_BADESCAPE, 
 					 r->parse, ln, 
 					 (int)(stesc - *bufp), NULL);
-				continue;
+				break;
 			}
-			if (0 == maxl && ']' == *cp)
+			if (0 == maxl && *cp == term) {
+				cp++;
 				break;
+			}
 		}
 
 		/*
@@ -593,11 +608,26 @@ roff_res(struct roff *r, char **bufp, si
 		 * undefined, resume searching for escapes.
 		 */
 
-		if (NULL == res)
+		switch (stesc[1]) {
+		case ('*'):
 			res = roff_getstrn(r, stnam, naml);
-		else
+			break;
+		case ('B'):
+			npos = 0;
+			irc = roff_evalnum(stnam, &npos, NULL, 0);
+			ubuf[0] = irc && stnam + npos + 1 == cp
+			    ? '1' : '0';
+			ubuf[1] = '\0';
+			break;
+		case ('n'):
 			snprintf(ubuf, sizeof(ubuf), "%d",
 			    roff_getregn(r, stnam, naml));
+			break;
+		case ('w'):
+			snprintf(ubuf, sizeof(ubuf), "%d",
+			    24 * (int)naml);
+			break;
+		}
 
 		if (NULL == res) {
 			mandoc_msg
@@ -614,7 +644,7 @@ roff_res(struct roff *r, char **bufp, si
 
 		strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
 		strlcat(nbuf, res, *szp);
-		strlcat(nbuf, cp + (maxl ? 0 : 1), *szp);
+		strlcat(nbuf, cp, *szp);
 
 		/* Prepare for the next replacement. */
 
@@ -1126,7 +1156,10 @@ roff_cond_text(ROFF_ARGS)
 static int
 roff_getnum(const char *v, int *pos, int *res)
 {
-	int p, n;
+	int	 myres, n, p;
+
+	if (NULL == res)
+		res = &myres;
 
 	p = *pos;
 	n = v[p] == '-';
@@ -1430,9 +1463,16 @@ roff_evalpar(const char *v, int *pos, in
 	if ( ! roff_evalnum(v, pos, res, 1))
 		return(0);
 
-	/* If the trailing parenthesis is missing, ignore the error. */
+	/*
+	 * Omission of the closing parenthesis
+	 * is an error in validation mode,
+	 * but ignored in evaluation mode.
+	 */
+
 	if (')' == v[*pos])
 		(*pos)++;
+	else if (NULL == res)
+		return(0);
 
 	return(1);
 }
@@ -1477,6 +1517,9 @@ roff_evalnum(const char *v, int *pos, in
 		if (skipwhite)
 			while (isspace((unsigned char)v[*pos]))
 				(*pos)++;
+
+		if (NULL == res)
+			continue;
 
 		switch (operator) {
 		case ('+'):
--
 To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv

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

only message in thread, other threads:[~2014-04-08  1:37 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-08  1:37 mdocml: Fully implement the \B (validate numerical expression) and 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).