summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--regress/roff/if/real0.in30
-rw-r--r--roff.715
-rw-r--r--roff.c121
3 files changed, 131 insertions, 35 deletions
diff --git a/regress/roff/if/real0.in b/regress/roff/if/real0.in
new file mode 100644
index 00000000..28f4aee4
--- /dev/null
+++ b/regress/roff/if/real0.in
@@ -0,0 +1,30 @@
+.Dd June 9, 2010
+.Dt TITLE 1
+.Os
+.Sh NAME
+.Nm test
+.Nd test
+.Sh SYNOPSIS
+foo
+.Sh DESCRIPTION
+to polar
+.if n\
+(r,theta)
+.if t\
+(r,\(*h)
+coordinates
+.if n\
+r\(**cos theta
+.if t\
+r\(**cos\(*h
+and y =
+.if n\
+r\(**sin theta.
+.if t\
+r\(**sin\(*h.
+These
+.if n \
+(r=0,theta=0).
+.if t \
+(r=0,\(*h=0).
+In
diff --git a/roff.7 b/roff.7
index 469b5765..58fb4d19 100644
--- a/roff.7
+++ b/roff.7
@@ -173,8 +173,19 @@ BODY...
BODY
.Ed
.Pp
-COND is a conditional (for the time being, this always evaluates to
-false).
+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{ ,
diff --git a/roff.c b/roff.c
index a3a5b550..f0c23664 100644
--- a/roff.c
+++ b/roff.c
@@ -32,6 +32,14 @@
#define ROFF_CTL(c) \
('.' == (c) || '\'' == (c))
+#if 1
+#define ROFF_DEBUG(fmt, args...) \
+ do { /* Nothing. */ } while (/*CONSTCOND*/ 0)
+#else
+#define ROFF_DEBUG(fmt, args...) \
+ do { fprintf(stderr, fmt , ##args); } while (/*CONSTCOND*/ 0)
+#endif
+
enum rofft {
ROFF_am,
ROFF_ami,
@@ -103,6 +111,7 @@ static enum rofferr roff_ccond(ROFF_ARGS);
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 roffrule roff_evalcond(const char *, int *);
static enum rofferr roff_line(ROFF_ARGS);
/* See roff_hash_find() */
@@ -306,10 +315,15 @@ roff_parseln(struct roff *r, int ln,
if (r->last && ! ROFF_CTL((*bufp)[pos])) {
t = r->last->tok;
assert(roffs[t].text);
+ ROFF_DEBUG("roff: intercept scoped text: %s, [%s]\n",
+ roffs[t].name, &(*bufp)[pos]);
return((*roffs[t].text)
(r, t, bufp, szp, ln, pos, pos, offs));
- } else if ( ! ROFF_CTL((*bufp)[pos]))
+ } else if ( ! ROFF_CTL((*bufp)[pos])) {
+ ROFF_DEBUG("roff: pass non-scoped text: [%s]\n",
+ &(*bufp)[pos]);
return(ROFF_CONT);
+ }
/*
* If a scope is open, go to the child handler for that macro,
@@ -319,6 +333,8 @@ roff_parseln(struct roff *r, int ln,
if (r->last) {
t = r->last->tok;
assert(roffs[t].sub);
+ ROFF_DEBUG("roff: intercept scoped context: %s\n",
+ roffs[t].name);
return((*roffs[t].sub)
(r, t, bufp, szp, ln, pos, pos, offs));
}
@@ -330,9 +346,14 @@ roff_parseln(struct roff *r, int ln,
*/
ppos = pos;
- if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
+ if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) {
+ ROFF_DEBUG("roff: pass non-scoped non-macro: [%s]\n",
+ &(*bufp)[pos]);
return(ROFF_CONT);
+ }
+ ROFF_DEBUG("roff: intercept new-scope: %s, [%s]\n",
+ roffs[t].name, &(*bufp)[pos]);
assert(roffs[t].proc);
return((*roffs[t].proc)
(r, t, bufp, szp, ln, ppos, pos, offs));
@@ -684,12 +705,37 @@ roff_cond_text(ROFF_ARGS)
}
+static enum roffrule
+roff_evalcond(const char *v, int *pos)
+{
+
+ switch (v[*pos]) {
+ case ('n'):
+ (*pos)++;
+ return(ROFFRULE_ALLOW);
+ case ('e'):
+ /* FALLTHROUGH */
+ case ('o'):
+ /* FALLTHROUGH */
+ case ('t'):
+ (*pos)++;
+ return(ROFFRULE_DENY);
+ default:
+ break;
+ }
+
+ while (v[*pos] && ' ' != v[*pos])
+ (*pos)++;
+ return(ROFFRULE_DENY);
+}
+
+
/* ARGSUSED */
static enum rofferr
roff_cond(ROFF_ARGS)
{
- int cpos; /* position of the condition */
int sv;
+ enum roffrule rule;
/* Stack overflow! */
@@ -698,20 +744,22 @@ roff_cond(ROFF_ARGS)
return(ROFF_ERR);
}
- cpos = pos;
+ /* First, evaluate the conditional. */
- if (ROFF_if == tok || ROFF_ie == tok) {
- /*
- * Read ahead past the conditional. FIXME: this does
- * not work, as conditionals don't end on whitespace,
- * but are parsed according to a formal grammar. It's
- * good enough for now, however.
- */
- while ((*bufp)[pos] && ' ' != (*bufp)[pos])
- pos++;
- }
+ if (ROFF_el == tok) {
+ /*
+ * An `.el' will get the value of the current rstack
+ * entry set in prior `ie' calls or defaults to DENY.
+ */
+ if (r->rstackpos < 0)
+ rule = ROFFRULE_DENY;
+ else
+ rule = r->rstack[r->rstackpos];
+ } else
+ rule = roff_evalcond(*bufp, &pos);
sv = pos;
+
while (' ' == (*bufp)[pos])
pos++;
@@ -721,30 +769,21 @@ roff_cond(ROFF_ARGS)
* really doing anything. Warn about this. It's probably
* wrong.
*/
+
if ('\0' == (*bufp)[pos] && sv != pos) {
- if ( ! (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
- return(ROFF_ERR);
- return(ROFF_IGN);
+ if ((*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
+ return(ROFF_IGN);
+ return(ROFF_ERR);
}
if ( ! roffnode_push(r, tok, ln, ppos))
return(ROFF_ERR);
- /* XXX: Implement more conditionals. */
+ r->last->rule = rule;
+
+ ROFF_DEBUG("roff: cond: %s -> %s\n", roffs[tok].name,
+ ROFFRULE_ALLOW == rule ? "allow" : "deny");
- if (ROFF_if == tok || ROFF_ie == tok)
- r->last->rule = 'n' == (*bufp)[cpos] ?
- ROFFRULE_ALLOW : ROFFRULE_DENY;
- else if (ROFF_el == tok) {
- /*
- * An `.el' will get the value of the current rstack
- * entry set in prior `ie' calls or defaults to DENY.
- */
- if (r->rstackpos < 0)
- r->last->rule = ROFFRULE_DENY;
- else
- r->last->rule = r->rstack[r->rstackpos];
- }
if (ROFF_ie == tok) {
/*
* An if-else will put the NEGATION of the current
@@ -756,15 +795,31 @@ roff_cond(ROFF_ARGS)
else
r->rstack[r->rstackpos] = ROFFRULE_DENY;
}
- if (r->last->parent && ROFFRULE_DENY == r->last->parent->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;
+ ROFF_DEBUG("roff: cond override: %s -> deny\n",
+ roffs[tok].name);
+ }
+
+ /*
+ * Determine scope. If we're invoked with "\{" trailing the
+ * conditional, then we're in a multiline scope. Else our scope
+ * expires on the next line.
+ */
r->last->endspan = 1;
if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
r->last->endspan = -1;
pos += 2;
- }
+ ROFF_DEBUG("roff: cond-scope: %s, multi-line\n",
+ roffs[tok].name);
+ } else
+ ROFF_DEBUG("roff: cond-scope: %s, one-line\n",
+ roffs[tok].name);
/*
* If there are no arguments on the line, the next-line scope is