summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2010-05-17 02:01:05 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2010-05-17 02:01:05 +0000
commitb2c69380f33dc4e4386ea05b9265b2e845e6a147 (patch)
treefa6e0c0831aaacfb1b62557becf6af49f53527c8
parente4d387ec9112592d7da65673d6227866ae8199dc (diff)
downloadmandoc-b2c69380f33dc4e4386ea05b9265b2e845e6a147.tar.gz
Full support for ie/el. This completes the initial roff support.
Added test files for ie/el. Using `if 0' as a baseline for "false" roff instructions instead of `if t'.
-rw-r--r--regress/roff/ie/simple0.in12
-rw-r--r--regress/roff/ie/simple1.in11
-rw-r--r--regress/roff/ie/simple2.in11
-rw-r--r--regress/roff/ie/with-el0.in13
-rw-r--r--regress/roff/ie/with-el1.in15
-rw-r--r--regress/roff/ie/with-el2.in16
-rw-r--r--regress/roff/ie/with-el3.in23
-rw-r--r--regress/roff/ie/with-el4.in29
-rw-r--r--regress/roff/ie/with-el5.in51
-rw-r--r--regress/roff/if/line-nest.in2
-rw-r--r--regress/roff/if/multiline-free0.in2
-rw-r--r--regress/roff/if/multiline-free1.in2
-rw-r--r--regress/roff/if/multiline0.in2
-rw-r--r--regress/roff/if/multiline1.in2
-rw-r--r--regress/roff/if/multiline2.in4
-rw-r--r--regress/roff/if/multiline3.in4
-rw-r--r--regress/roff/if/simple0.in2
-rw-r--r--regress/roff/if/simple1.in2
-rw-r--r--regress/roff/if/simple2.in2
-rw-r--r--regress/roff/ig/cond0.in2
-rw-r--r--regress/roff/ig/redef0.in2
-rw-r--r--regress/roff/ig/simple0.in2
-rw-r--r--regress/roff/ig/simple2.in2
-rw-r--r--roff.75
-rw-r--r--roff.c174
25 files changed, 316 insertions, 76 deletions
diff --git a/regress/roff/ie/simple0.in b/regress/roff/ie/simple0.in
new file mode 100644
index 00000000..d3c4d93d
--- /dev/null
+++ b/regress/roff/ie/simple0.in
@@ -0,0 +1,12 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+asdf
+.ie 0 \{\
+1
+.\}
+fdsa
diff --git a/regress/roff/ie/simple1.in b/regress/roff/ie/simple1.in
new file mode 100644
index 00000000..110538d6
--- /dev/null
+++ b/regress/roff/ie/simple1.in
@@ -0,0 +1,11 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+asdf
+.ie 0 \
+1
+fdsa
diff --git a/regress/roff/ie/simple2.in b/regress/roff/ie/simple2.in
new file mode 100644
index 00000000..f4d88de7
--- /dev/null
+++ b/regress/roff/ie/simple2.in
@@ -0,0 +1,11 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+asdf
+.ie 0
+1
+fdsa
diff --git a/regress/roff/ie/with-el0.in b/regress/roff/ie/with-el0.in
new file mode 100644
index 00000000..27da9f9b
--- /dev/null
+++ b/regress/roff/ie/with-el0.in
@@ -0,0 +1,13 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+asdf
+.ie 0 \
+1
+.el \
+2
+fdsa
diff --git a/regress/roff/ie/with-el1.in b/regress/roff/ie/with-el1.in
new file mode 100644
index 00000000..51abb9fd
--- /dev/null
+++ b/regress/roff/ie/with-el1.in
@@ -0,0 +1,15 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+asdf
+.ie 0 \{\
+1
+2
+.\}
+.el \
+3
+fdsa
diff --git a/regress/roff/ie/with-el2.in b/regress/roff/ie/with-el2.in
new file mode 100644
index 00000000..27e93493
--- /dev/null
+++ b/regress/roff/ie/with-el2.in
@@ -0,0 +1,16 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+asdf
+.ie 0 \{\
+1
+2
+.\}
+xyzzy
+.el \
+3
+fdsa
diff --git a/regress/roff/ie/with-el3.in b/regress/roff/ie/with-el3.in
new file mode 100644
index 00000000..8ccd208a
--- /dev/null
+++ b/regress/roff/ie/with-el3.in
@@ -0,0 +1,23 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+asdf
+.ie 0 \{\
+1
+.de garglepants
+2
+.\}
+foobar
+.ie 0 \{\
+1
+.de actuallygarglepantsisadouche
+2
+.\}
+xyzzy
+.el \
+3
+fdsa
diff --git a/regress/roff/ie/with-el4.in b/regress/roff/ie/with-el4.in
new file mode 100644
index 00000000..ea0d5ed2
--- /dev/null
+++ b/regress/roff/ie/with-el4.in
@@ -0,0 +1,29 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+asdf
+.ie 0 \{\
+1
+.de garglepants
+2
+.\}
+foobar
+.ie 0 \{\
+1
+.de actuallygarglepantsisadouche
+2
+.\}
+xyzzy
+.el \
+3
+fdsa
+.el \
+3
+fdsa
+.el \
+3
+fdsa
diff --git a/regress/roff/ie/with-el5.in b/regress/roff/ie/with-el5.in
new file mode 100644
index 00000000..aca9776e
--- /dev/null
+++ b/regress/roff/ie/with-el5.in
@@ -0,0 +1,51 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+asdf
+.ie 0 \{\
+1
+.de garglepants
+2
+.\}
+foobar
+.ie 0 \{\
+1
+.de actuallygarglepantsisadouche
+2
+.\}
+.ie 0 \{\
+1
+.de garglepants
+2
+.\}
+foobar
+.ie 0 \{\
+1
+.de actuallygarglepantsisadouche
+2
+.\}
+.ie 0 \{\
+1
+.de garglepants
+2
+.\}
+foobar
+.ie 0 \{\
+1
+.de actuallygarglepantsisadouche
+2
+.\}
+xyzzy
+.el \
+3
+fdsa
+.el \
+3
+fdsa
+.el \
+3
+fdsa
diff --git a/regress/roff/if/line-nest.in b/regress/roff/if/line-nest.in
index 06e58b67..b405a9fb 100644
--- a/regress/roff/if/line-nest.in
+++ b/regress/roff/if/line-nest.in
@@ -6,6 +6,6 @@
.Nd bar
.Sh DESCRIPTION
123
-.if t .if t \
+.if 0 .if 0 \
fdsa
asdf
diff --git a/regress/roff/if/multiline-free0.in b/regress/roff/if/multiline-free0.in
index f9fb0fd9..562adcac 100644
--- a/regress/roff/if/multiline-free0.in
+++ b/regress/roff/if/multiline-free0.in
@@ -5,6 +5,6 @@
.Nm foo
.Nd bar
.Sh DESCRIPTION
-.if t \{\
+.if 0 \{\
there \} dude
fdsa
diff --git a/regress/roff/if/multiline-free1.in b/regress/roff/if/multiline-free1.in
index ac147435..2d51caa7 100644
--- a/regress/roff/if/multiline-free1.in
+++ b/regress/roff/if/multiline-free1.in
@@ -5,7 +5,7 @@
.Nm foo
.Nd bar
.Sh DESCRIPTION
-.if t \{\
+.if 0 \{\
there \\} dude
.\}
fdsa
diff --git a/regress/roff/if/multiline0.in b/regress/roff/if/multiline0.in
index 0b6e132d..14fa576c 100644
--- a/regress/roff/if/multiline0.in
+++ b/regress/roff/if/multiline0.in
@@ -6,7 +6,7 @@
.Nd bar
.Sh DESCRIPTION
123
-.if t \{\
+.if 0 \{\
asdf
.\}
fdsa
diff --git a/regress/roff/if/multiline1.in b/regress/roff/if/multiline1.in
index b69edaf4..4d007a6e 100644
--- a/regress/roff/if/multiline1.in
+++ b/regress/roff/if/multiline1.in
@@ -6,7 +6,7 @@
.Nd bar
.Sh DESCRIPTION
123
-.if t \
+.if 0 \
\{\
asdf
.\}
diff --git a/regress/roff/if/multiline2.in b/regress/roff/if/multiline2.in
index 6076685f..299c3d8a 100644
--- a/regress/roff/if/multiline2.in
+++ b/regress/roff/if/multiline2.in
@@ -6,9 +6,9 @@
.Nd bar
.Sh DESCRIPTION
123
-.if t \{\
+.if 0 \{\
asdf
-. if t \{\
+. if 0 \{\
shmoop moop
. \}
.\}
diff --git a/regress/roff/if/multiline3.in b/regress/roff/if/multiline3.in
index c32e902b..fe83c9f1 100644
--- a/regress/roff/if/multiline3.in
+++ b/regress/roff/if/multiline3.in
@@ -6,9 +6,9 @@
.Nd bar
.Sh DESCRIPTION
123
-.if t \{ .if t
+.if 0 \{ .if 0
asdf
-. if t \{\
+. if 0 \{\
shmoop moop
. \}
.\}
diff --git a/regress/roff/if/simple0.in b/regress/roff/if/simple0.in
index 7ba9b7c9..8bb2d074 100644
--- a/regress/roff/if/simple0.in
+++ b/regress/roff/if/simple0.in
@@ -6,5 +6,5 @@
.Nd bar
.Sh DESCRIPTION
123
-.if t \
+.if 0 \
asdf
diff --git a/regress/roff/if/simple1.in b/regress/roff/if/simple1.in
index 0462ffce..55a4cf60 100644
--- a/regress/roff/if/simple1.in
+++ b/regress/roff/if/simple1.in
@@ -7,5 +7,5 @@
.Sh DESCRIPTION
123
.\" Note this has no whitespace...
-.if t
+.if 0
asdf
diff --git a/regress/roff/if/simple2.in b/regress/roff/if/simple2.in
index 3d7a831b..609e51ac 100644
--- a/regress/roff/if/simple2.in
+++ b/regress/roff/if/simple2.in
@@ -7,5 +7,5 @@
.Sh DESCRIPTION
123
.\" Note that this has whitespace...
-.if t
+.if 0
asdf
diff --git a/regress/roff/ig/cond0.in b/regress/roff/ig/cond0.in
index 63b25c5c..88f6c66d 100644
--- a/regress/roff/ig/cond0.in
+++ b/regress/roff/ig/cond0.in
@@ -10,7 +10,7 @@
.Nd bar
.Sh DESCRIPTION
garglebats!
-.if t \
+.if 0 \
.ig .
foo
..
diff --git a/regress/roff/ig/redef0.in b/regress/roff/ig/redef0.in
index 4d5a7e76..b3f2fc23 100644
--- a/regress/roff/ig/redef0.in
+++ b/regress/roff/ig/redef0.in
@@ -8,6 +8,6 @@
a
.ig if
asdf
-.if t \
+.if 0 \
b
c
diff --git a/regress/roff/ig/simple0.in b/regress/roff/ig/simple0.in
index d693ce77..6b24bd50 100644
--- a/regress/roff/ig/simple0.in
+++ b/regress/roff/ig/simple0.in
@@ -8,5 +8,5 @@
123
.ig
hello
-..
+.0
12124
diff --git a/regress/roff/ig/simple2.in b/regress/roff/ig/simple2.in
index 4e82458c..5247e35f 100644
--- a/regress/roff/ig/simple2.in
+++ b/regress/roff/ig/simple2.in
@@ -8,7 +8,7 @@
123
.ig
hello
-.if t \{\
+.if 0 \{\
hello
.\}
..
diff --git a/roff.7 b/roff.7
index 2d3ae9cb..aa816e6b 100644
--- a/roff.7
+++ b/roff.7
@@ -228,6 +228,11 @@ Historic groff did not accept white-space buffering the custom END tag
for the
.Sx \&ig
macro.
+.It
+The
+.Sx \&if
+and family would print funny white-spaces with historic groff when
+depending on next-line syntax.
.El
.Sh AUTHORS
The
diff --git a/roff.c b/roff.c
index 48a77d79..cb0c85d9 100644
--- a/roff.c
+++ b/roff.c
@@ -26,6 +26,8 @@
#include "mandoc.h"
#include "roff.h"
+#define RSTACK_MAX 128
+
#define ROFF_CTL(c) \
('.' == (c) || '\'' == (c))
@@ -36,26 +38,26 @@ enum rofft {
ROFF_de,
ROFF_dei,
ROFF_de1,
+ ROFF_el,
+ ROFF_ie,
ROFF_if,
ROFF_ig,
ROFF_cblock,
ROFF_ccond,
-#if 0
- ROFF_ie,
- ROFF_el,
-#endif
ROFF_MAX
};
+enum roffrule {
+ ROFFRULE_ALLOW,
+ ROFFRULE_DENY
+};
+
struct roff {
struct roffnode *last; /* leaf of stack */
mandocmsg msg; /* err/warn/fatal messages */
void *data; /* privdata for messages */
-};
-
-enum roffrule {
- ROFFRULE_ALLOW,
- ROFFRULE_DENY
+ enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
+ int rstackpos; /* position in rstack */
};
struct roffnode {
@@ -65,7 +67,7 @@ struct roffnode {
int col; /* parse col */
char *end; /* end-rules: custom token */
int endspan; /* end-rules: next-line or infty */
- enum roffrule rule;
+ enum roffrule rule; /* current evaluation rule */
};
#define ROFF_ARGS struct roff *r, /* parse ctx */ \
@@ -93,9 +95,9 @@ static enum rofferr roff_block_text(ROFF_ARGS);
static enum rofferr roff_block_sub(ROFF_ARGS);
static enum rofferr roff_cblock(ROFF_ARGS);
static enum rofferr roff_ccond(ROFF_ARGS);
-static enum rofferr roff_if(ROFF_ARGS);
-static enum rofferr roff_if_text(ROFF_ARGS);
-static enum rofferr roff_if_sub(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);
const struct roffmac roffs[ROFF_MAX] = {
{ "am", roff_block, roff_block_text, roff_block_sub, 0 },
@@ -104,7 +106,9 @@ const struct roffmac roffs[ROFF_MAX] = {
{ "de", roff_block, roff_block_text, roff_block_sub, 0 },
{ "dei", roff_block, roff_block_text, roff_block_sub, 0 },
{ "de1", roff_block, roff_block_text, roff_block_sub, 0 },
- { "if", roff_if, roff_if_text, roff_if_sub, ROFFMAC_STRUCT },
+ { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },
+ { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },
+ { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },
{ "ig", roff_block, roff_block_text, roff_block_sub, 0 },
{ ".", roff_cblock, NULL, NULL, 0 },
{ "\\}", roff_ccond, NULL, NULL, 0 },
@@ -149,6 +153,11 @@ roffnode_pop(struct roff *r)
assert(r->last);
p = r->last;
+
+ if (ROFF_el == p->tok)
+ if (r->rstackpos > -1)
+ r->rstackpos--;
+
r->last = r->last->parent;
if (p->end)
free(p->end);
@@ -219,6 +228,7 @@ roff_alloc(const mandocmsg msg, void *data)
r->msg = msg;
r->data = data;
+ r->rstackpos = -1;
return(r);
}
@@ -306,7 +316,7 @@ roff_parse(const char *buf, int *pos)
for (j = 0; j < 4; j++, (*pos)++)
if ('\0' == (mac[j] = buf[*pos]))
break;
- else if (' ' == buf[*pos])
+ else if (' ' == buf[*pos] || (j && '\\' == buf[*pos]))
break;
if (j == 4 || j < 1)
@@ -395,7 +405,14 @@ roff_ccond(ROFF_ARGS)
return(ROFF_IGN);
}
- if (ROFF_if != r->last->tok) {
+ switch (r->last->tok) {
+ case (ROFF_el):
+ /* FALLTHROUGH */
+ case (ROFF_ie):
+ /* FALLTHROUGH */
+ case (ROFF_if):
+ break;
+ default:
if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
return(ROFF_ERR);
return(ROFF_IGN);
@@ -478,36 +495,6 @@ roff_block(ROFF_ARGS)
/* ARGSUSED */
static enum rofferr
-roff_if_sub(ROFF_ARGS)
-{
- enum rofft t;
- enum roffrule rr;
-
- ppos = pos;
- rr = r->last->rule;
- roffnode_cleanscope(r);
-
- if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
- return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
-
- /*
- * A denied conditional must evaluate its children if and only
- * if they're either structurally required (such as loops and
- * conditionals) or a closing macro.
- */
- if (ROFFRULE_DENY == rr)
- if ( ! (ROFFMAC_STRUCT & roffs[t].flags))
- if (ROFF_ccond != t)
- return(ROFF_IGN);
-
- assert(roffs[t].proc);
- return((*roffs[t].proc)
- (r, t, bufp, szp, ln, ppos, pos, offs));
-}
-
-
-/* ARGSUSED */
-static enum rofferr
roff_block_sub(ROFF_ARGS)
{
enum rofft t;
@@ -573,39 +560,86 @@ roff_block_text(ROFF_ARGS)
/* ARGSUSED */
static enum rofferr
-roff_if_text(ROFF_ARGS)
+roff_cond_sub(ROFF_ARGS)
+{
+ enum rofft t;
+ enum roffrule rr;
+
+ ppos = pos;
+ rr = r->last->rule;
+
+ roffnode_cleanscope(r);
+
+ if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
+ return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
+
+ /*
+ * A denied conditional must evaluate its children if and only
+ * if they're either structurally required (such as loops and
+ * conditionals) or a closing macro.
+ */
+ if (ROFFRULE_DENY == rr)
+ if ( ! (ROFFMAC_STRUCT & roffs[t].flags))
+ if (ROFF_ccond != t)
+ return(ROFF_IGN);
+
+ assert(roffs[t].proc);
+ return((*roffs[t].proc)
+ (r, t, bufp, szp, ln, ppos, pos, offs));
+}
+
+
+/* ARGSUSED */
+static enum rofferr
+roff_cond_text(ROFF_ARGS)
{
char *ep, *st;
+ enum roffrule rr;
+
+ rr = r->last->rule;
+
+ /*
+ * We display the value of the text if out current evaluation
+ * scope permits us to do so.
+ */
st = &(*bufp)[pos];
if (NULL == (ep = strstr(st, "\\}"))) {
roffnode_cleanscope(r);
- return(ROFF_IGN);
+ return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
}
if (ep > st && '\\' != *(ep - 1))
roffnode_pop(r);
roffnode_cleanscope(r);
- return(ROFF_IGN);
+ return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
}
/* ARGSUSED */
static enum rofferr
-roff_if(ROFF_ARGS)
+roff_cond(ROFF_ARGS)
{
int sv;
- /*
- * 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.
- */
+ /* Stack overflow! */
- while ((*bufp)[pos] && ' ' != (*bufp)[pos])
- pos++;
+ if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) {
+ (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL);
+ return(ROFF_ERR);
+ }
+
+ 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++;
+ }
sv = pos;
while (' ' == (*bufp)[pos])
@@ -617,7 +651,6 @@ roff_if(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);
@@ -627,7 +660,28 @@ roff_if(ROFF_ARGS)
if ( ! roffnode_push(r, tok, ln, ppos))
return(ROFF_ERR);
- /* Don't evaluate: just assume NO. */
+ /* TODO: here we would evaluate the conditional. */
+
+ 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];
+ } else if (ROFF_ie == tok) {
+ /*
+ * An if-else will put the NEGATION of the current
+ * evaluated conditional into the stack.
+ */
+ r->rstackpos++;
+ if (ROFFRULE_DENY == r->last->rule)
+ r->rstack[r->rstackpos] = ROFFRULE_ALLOW;
+ else
+ r->rstack[r->rstackpos] = ROFFRULE_DENY;
+ }
r->last->endspan = 1;