source@mandoc.bsd.lv
 help / color / mirror / Atom feed
* mdocml: Improve .if/.ie condition handling.
@ 2014-03-08  4:43 schwarze
  0 siblings, 0 replies; only message in thread
From: schwarze @ 2014-03-08  4:43 UTC (permalink / raw)
  To: source

Log Message:
-----------
Improve .if/.ie condition handling.
* Support string comparisons.
* Support negation not only for numerical, but for all conditions.
* Switch the `o' condition from false to true.
* Handle the `c', `d', and `r' conditions as false for now.
* Use int for boolean data instead of rolling our own "enum roffrule";
needed such that we can use the standard ! and == operators.

Havard Eidnes reported via the NetBSD bug tracking system that some 
Tcl*(3) manuals need this, and Thomas Klausner <wiz at NetBSD> 
forwarded the report to me.  This doesn't make the crazy Tcl*(3) 
macrology maze happy yet, but brings us a bit closer.

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

Revision Data
-------------
Index: roff.7
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/roff.7,v
retrieving revision 1.47
retrieving revision 1.48
diff -Lroff.7 -Lroff.7 -u -p -r1.47 -r1.48
--- roff.7
+++ roff.7
@@ -677,10 +677,73 @@ Its syntax is equivalent to
 .Sx \&if .
 .Ss \&if
 Begins a conditional.
-Right now, the conditional evaluates to true
-if and only if it starts with the letter
-.Sy n ,
-indicating processing in nroff style as opposed to troff style.
+This request has the following syntax:
+.Bd -literal -offset indent
+\&.if COND BODY
+.Ed
+.Bd -literal -offset indent
+\&.if COND \e{BODY
+BODY...\e}
+.Ed
+.Bd -literal -offset indent
+\&.if COND \e{\e
+BODY...
+\&.\e}
+.Ed
+.Pp
+COND is a conditional statement.
+Currently,
+.Xr mandoc 1
+supports the following subset of roff conditionals:
+.Bl -bullet
+.It
+If
+.Sq \&!
+is prefixed to COND, the condition is logically inverted.
+.It
+If the first character of COND is
+.Sq n
+.Pq nroff mode
+or
+.Sq o
+.Pq odd page ,
+COND evaluates to true.
+.It
+If the first character of COND is
+.Sq c
+.Pq character available ,
+.Sq d
+.Pq string defined ,
+.Sq e
+.Pq even page ,
+.Sq r
+.Pq register accessed ,
+or
+.Sq t
+.Pq troff mode ,
+COND evaluates to false.
+.It
+If COND starts with a digit, optionally prefixed by a minus sign,
+it is evaluated as a numerical expression of the form
+.Ar number operator number ,
+where
+.Ar operator
+is one of
+.Sq < ,
+.Sq <= ,
+.Sq = ,
+.Sq >= ,
+or
+.Sq > .
+.It
+Otherwise, the first character of COND is regarded as a delimiter
+and COND evaluates to true if the string extending from its first
+to its second occurrence is equal to the string extending from its
+second to its third occurrence.
+.It
+If COND cannot be parsed, it evaluates to false.
+.El
+.Pp
 If a conditional is false, its children are not processed, but are
 syntactically interpreted to preserve the integrity of the input
 document.
@@ -698,44 +761,12 @@ will continue to syntactically interpret
 conditional.
 Sub-conditionals, in this case, obviously inherit the truth value of
 the parent.
-This request has the following syntax:
-.Bd -literal -offset indent
-\&.if COND \e{\e
-BODY...
-\&.\e}
-.Ed
-.Bd -literal -offset indent
-\&.if COND \e{ BODY
-BODY... \e}
-.Ed
-.Bd -literal -offset indent
-\&.if COND \e{ BODY
-BODY...
-\&.\e}
-.Ed
-.Bd -literal -offset indent
-\&.if COND \e
-BODY
-.Ed
-.Pp
-COND is a conditional statement.
-roff allows for complicated conditionals; mandoc is much simpler.
-At this time, mandoc supports only
-.Sq n ,
-evaluating to true;
-and
-.Sq t ,
-.Sq e ,
-and
-.Sq o ,
-evaluating to false.
-All other invocations are read up to the next end of line or space and
-evaluate as false.
 .Pp
 If the BODY section is begun by an escaped brace
 .Sq \e{ ,
-scope continues until a closing-brace escape sequence
-.Sq \.\e} .
+scope continues until the end of the input line containing the
+matching closing-brace escape sequence
+.Sq \e} .
 If the BODY is not enclosed in braces, scope continues until
 the end of the line.
 If the COND is followed by a BODY on the same line, whether after a
Index: roff.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/roff.c,v
retrieving revision 1.197
retrieving revision 1.198
diff -Lroff.c -Lroff.c -u -p -r1.197 -r1.198
--- roff.c
+++ roff.c
@@ -76,11 +76,6 @@ enum	rofft {
 	ROFF_MAX
 };
 
-enum	roffrule {
-	ROFFRULE_DENY,
-	ROFFRULE_ALLOW
-};
-
 /*
  * An incredibly-simple string buffer.
  */
@@ -112,7 +107,7 @@ struct	roff {
 	struct mparse	*parse; /* parse point */
 	int		 quick; /* skip standard macro deletion */
 	struct roffnode	*last; /* leaf of stack */
-	enum roffrule	 rstack[RSTACK_MAX]; /* stack of !`ie' rules */
+	int		 rstack[RSTACK_MAX]; /* stack of !`ie' rules */
 	char		 control; /* control character */
 	int		 rstackpos; /* position in rstack */
 	struct roffreg	*regtab; /* number registers */
@@ -136,7 +131,7 @@ struct	roffnode {
 	char		*name; /* node name, e.g. macro name */
 	char		*end; /* end-rules: custom token */
 	int		 endspan; /* end-rules: next-line or infty */
-	enum roffrule	 rule; /* current evaluation rule */
+	int		 rule; /* current evaluation rule */
 };
 
 #define	ROFF_ARGS	 struct roff *r, /* parse ctx */ \
@@ -184,7 +179,8 @@ 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 roffrule	 roff_evalcond(const char *, int *);
+static	int		 roff_evalcond(const char *, int *);
+static	int		 roff_evalstrcond(const char *, int *);
 static	void		 roff_free1(struct roff *);
 static	void		 roff_freereg(struct roffreg *);
 static	void		 roff_freestr(struct roffkv *);
@@ -401,7 +397,7 @@ roffnode_push(struct roff *r, enum rofft
 	p->parent = r->last;
 	p->line = line;
 	p->col = col;
-	p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
+	p->rule = p->parent ? p->parent->rule : 0;
 
 	r->last = p;
 }
@@ -1050,8 +1046,8 @@ static enum rofferr
 roff_cond_sub(ROFF_ARGS)
 {
 	enum rofft	 t;
-	enum roffrule	 rr;
 	char		*ep;
+	int		 rr;
 
 	rr = r->last->rule;
 	roffnode_cleanscope(r);
@@ -1063,8 +1059,7 @@ roff_cond_sub(ROFF_ARGS)
 	 */
 
 	if ((ROFF_MAX != t) &&
-	    (ROFFRULE_ALLOW == rr ||
-	     ROFFMAC_STRUCT & roffs[t].flags)) {
+	    (rr || ROFFMAC_STRUCT & roffs[t].flags)) {
 		assert(roffs[t].proc);
 		return((*roffs[t].proc)(r, t, bufp, szp,
 					ln, ppos, pos, offs));
@@ -1077,7 +1072,7 @@ roff_cond_sub(ROFF_ARGS)
 
 	ep = *bufp + pos;
 	if ('\\' == ep[0] && '}' == ep[1])
-		rr = ROFFRULE_DENY;
+		rr = 0;
 
 	/* Always check for the closing delimiter `\}'. */
 
@@ -1088,7 +1083,7 @@ roff_cond_sub(ROFF_ARGS)
 		}
 		++ep;
 	}
-	return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
+	return(rr ? ROFF_CONT : ROFF_IGN);
 }
 
 /* ARGSUSED */
@@ -1096,7 +1091,7 @@ static enum rofferr
 roff_cond_text(ROFF_ARGS)
 {
 	char		*ep;
-	enum roffrule	 rr;
+	int		 rr;
 
 	rr = r->last->rule;
 	roffnode_cleanscope(r);
@@ -1109,7 +1104,7 @@ roff_cond_text(ROFF_ARGS)
 		}
 		++ep;
 	}
-	return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
+	return(rr ? ROFF_CONT : ROFF_IGN);
 }
 
 static int
@@ -1162,64 +1157,103 @@ roff_getop(const char *v, int *pos, char
 	return(*res);
 }
 
-static enum roffrule
+/*
+ * Evaluate a string comparison condition.
+ * The first character is the delimiter.
+ * Succeed if the string up to its second occurrence
+ * matches the string up to its third occurence.
+ * Advance the cursor after the third occurrence
+ * or lacking that, to the end of the line.
+ */
+static int
+roff_evalstrcond(const char *v, int *pos)
+{
+	const char	*s1, *s2, *s3;
+	int		 match;
+
+	match = 0;
+	s1 = v + *pos;		/* initial delimiter */
+	s2 = s1 + 1;		/* for scanning the first string */
+	s3 = strchr(s2, *s1);	/* for scanning the second string */
+
+	if (NULL == s3)		/* found no middle delimiter */
+		goto out;
+
+	while ('\0' != *++s3) {
+		if (*s2 != *s3) {  /* mismatch */
+			s3 = strchr(s3, *s1);
+			break;
+		}
+		if (*s3 == *s1) {  /* found the final delimiter */
+			match = 1;
+			break;
+		}
+		s2++;
+	}
+
+out:
+	if (NULL == s3)
+		s3 = strchr(s2, '\0');
+	else
+		s3++;
+	*pos = s3 - v;
+	return(match);
+}
+
+static int
 roff_evalcond(const char *v, int *pos)
 {
-	int	 not, lh, rh;
+	int	 wanttrue, lh, rh;
 	char	 op;
 
+	if ('!' == v[*pos]) {
+		wanttrue = 0;
+		(*pos)++;
+	} else
+		wanttrue = 1;
+
 	switch (v[*pos]) {
 	case ('n'):
+		/* FALLTHROUGH */
+	case ('o'):
 		(*pos)++;
-		return(ROFFRULE_ALLOW);
+		return(wanttrue);
+	case ('c'):
+		/* FALLTHROUGH */
+	case ('d'):
+		/* FALLTHROUGH */
 	case ('e'):
 		/* FALLTHROUGH */
-	case ('o'):
+	case ('r'):
 		/* FALLTHROUGH */
 	case ('t'):
 		(*pos)++;
-		return(ROFFRULE_DENY);
-	case ('!'):
-		(*pos)++;
-		not = 1;
-		break;
+		return(!wanttrue);
 	default:
-		not = 0;
 		break;
 	}
 
 	if (!roff_getnum(v, pos, &lh))
-		return ROFFRULE_DENY;
-	if (!roff_getop(v, pos, &op)) {
-		if (lh < 0)
-			lh = 0;
-		goto out;
-	}
+		return(roff_evalstrcond(v, pos) == wanttrue);
+	if (!roff_getop(v, pos, &op))
+		return((lh > 0) == wanttrue);
 	if (!roff_getnum(v, pos, &rh))
-		return ROFFRULE_DENY;
+		return(0);
+
 	switch (op) {
 	case 'g':
-		lh = lh >= rh;
-		break;
+		return((lh >= rh) == wanttrue);
 	case 'l':
-		lh = lh <= rh;
-		break;
+		return((lh <= rh) == wanttrue);
 	case '=':
-		lh = lh == rh;
-		break;
+		return((lh == rh) == wanttrue);
 	case '>':
-		lh = lh > rh;
-		break;
+		return((lh > rh) == wanttrue);
 	case '<':
-		lh = lh < rh;
-		break;
+		return((lh < rh) == wanttrue);
 	default:
-		return ROFFRULE_DENY;
+		return(0);
 	}
-out:
-	if (not)
-		lh = !lh;
-	return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
 }
 
 /* ARGSUSED */
@@ -1246,8 +1280,7 @@ roff_cond(ROFF_ARGS)
 	 */
 
 	r->last->rule = ROFF_el == tok ?
-		(r->rstackpos < 0 ? 
-		 ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
+		(r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) :
 		roff_evalcond(*bufp, &pos);
 
 	/*
@@ -1261,15 +1294,13 @@ roff_cond(ROFF_ARGS)
 				r->parse, ln, ppos, NULL);
 			return(ROFF_ERR);
 		}
-		r->rstack[++r->rstackpos] = 
-			ROFFRULE_DENY == r->last->rule ?
-			ROFFRULE_ALLOW : ROFFRULE_DENY;
+		r->rstack[++r->rstackpos] = !r->last->rule;
 	}
 
 	/* If the parent has false as its rule, then so do we. */
 
-	if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
-		r->last->rule = ROFFRULE_DENY;
+	if (r->last->parent && !r->last->parent->rule)
+		r->last->rule = 0;
 
 	/*
 	 * Determine scope.
--
 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-03-08  4:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-08  4:43 mdocml: Improve .if/.ie condition handling 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).