summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristaps Dzonsons <kristaps@bsd.lv>2010-05-16 19:08:11 +0000
committerKristaps Dzonsons <kristaps@bsd.lv>2010-05-16 19:08:11 +0000
commit76918e2e1d5b60e535b8c4ee567f001fa667bc1a (patch)
treee1b5ed9da404584e88719360d82b6cea2f7ad59c
parentf20ec3ad8a63200ea468d6350f96622a33060719 (diff)
downloadmandoc-76918e2e1d5b60e535b8c4ee567f001fa667bc1a.tar.gz
Regression tests in place for `.if' in libroff.
Check against some strange `.if' constructs I missed. Added initial roff.7 manual.
-rw-r--r--main.c1
-rw-r--r--mandoc.h1
-rw-r--r--regress/roff/if/line-nest.in11
-rw-r--r--regress/roff/if/multiline0.in12
-rw-r--r--regress/roff/if/multiline1.in13
-rw-r--r--regress/roff/if/multiline2.in15
-rw-r--r--regress/roff/if/multiline3.in15
-rw-r--r--regress/roff/if/simple0.in10
-rw-r--r--regress/roff/if/simple1.in11
-rw-r--r--regress/roff/if/simple2.in11
-rw-r--r--roff.7128
-rw-r--r--roff.c33
12 files changed, 257 insertions, 4 deletions
diff --git a/main.c b/main.c
index 65fde5c3..d6f3c008 100644
--- a/main.c
+++ b/main.c
@@ -799,6 +799,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"ok",
"multi-line scope open on exit",
"request for scope closure when no matching scope is open",
+ "macro requires line argument(s)",
"line arguments will be lost",
"memory exhausted"
};
diff --git a/mandoc.h b/mandoc.h
index b0cdf181..d127625b 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -23,6 +23,7 @@ enum mandocerr {
MANDOCERR_OK,
MANDOCERR_SCOPEEXIT, /* scope open on exit */
MANDOCERR_NOSCOPE, /* request scope close w/none open */
+ MANDOCERR_NOARGS, /* macro requires argument(s) */
#define MANDOCERR_WARNING MANDOCERR_SCOPEEXIT
MANDOCERR_ARGSLOST, /* line arguments will be lost */
diff --git a/regress/roff/if/line-nest.in b/regress/roff/if/line-nest.in
new file mode 100644
index 00000000..06e58b67
--- /dev/null
+++ b/regress/roff/if/line-nest.in
@@ -0,0 +1,11 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.if t .if t \
+fdsa
+asdf
diff --git a/regress/roff/if/multiline0.in b/regress/roff/if/multiline0.in
new file mode 100644
index 00000000..0b6e132d
--- /dev/null
+++ b/regress/roff/if/multiline0.in
@@ -0,0 +1,12 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.if t \{\
+asdf
+.\}
+fdsa
diff --git a/regress/roff/if/multiline1.in b/regress/roff/if/multiline1.in
new file mode 100644
index 00000000..b69edaf4
--- /dev/null
+++ b/regress/roff/if/multiline1.in
@@ -0,0 +1,13 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.if t \
+\{\
+asdf
+.\}
+fdsa
diff --git a/regress/roff/if/multiline2.in b/regress/roff/if/multiline2.in
new file mode 100644
index 00000000..6076685f
--- /dev/null
+++ b/regress/roff/if/multiline2.in
@@ -0,0 +1,15 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.if t \{\
+asdf
+. if t \{\
+shmoop moop
+. \}
+.\}
+fdsa
diff --git a/regress/roff/if/multiline3.in b/regress/roff/if/multiline3.in
new file mode 100644
index 00000000..c32e902b
--- /dev/null
+++ b/regress/roff/if/multiline3.in
@@ -0,0 +1,15 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.if t \{ .if t
+asdf
+. if t \{\
+shmoop moop
+. \}
+.\}
+fdsa
diff --git a/regress/roff/if/simple0.in b/regress/roff/if/simple0.in
new file mode 100644
index 00000000..7ba9b7c9
--- /dev/null
+++ b/regress/roff/if/simple0.in
@@ -0,0 +1,10 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.if t \
+asdf
diff --git a/regress/roff/if/simple1.in b/regress/roff/if/simple1.in
new file mode 100644
index 00000000..0462ffce
--- /dev/null
+++ b/regress/roff/if/simple1.in
@@ -0,0 +1,11 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.\" Note this has no whitespace...
+.if t
+asdf
diff --git a/regress/roff/if/simple2.in b/regress/roff/if/simple2.in
new file mode 100644
index 00000000..3d7a831b
--- /dev/null
+++ b/regress/roff/if/simple2.in
@@ -0,0 +1,11 @@
+.Dd $Mdocdate$
+.Dt FOO 1
+.Os
+.Sh NAME
+.Nm foo
+.Nd bar
+.Sh DESCRIPTION
+123
+.\" Note that this has whitespace...
+.if t
+asdf
diff --git a/roff.7 b/roff.7
new file mode 100644
index 00000000..7a41aeee
--- /dev/null
+++ b/roff.7
@@ -0,0 +1,128 @@
+.\" $Id$
+.\"
+.\" Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt ROFF 7
+.Os
+.Sh NAME
+.Nm roff
+.Nd roff language reference
+.Sh DESCRIPTION
+The
+.Nm roff
+language is a general-purpose text-formatting language. The purpose of
+this document is to consistently describe those language constructs
+accepted by the
+.Xr mandoc 1
+utility. It is a work in progress.
+.Pp
+An
+.Nm
+document follows simple rules: lines beginning with the control
+characters
+.Sq \.
+or
+.Sq \(aq
+are parsed for macros. Other lines are interpreted within the scope of
+prior macros:
+.Bd -literal -offset indent
+\&.xx Macro lines change control state.
+Other lines are interpreted within the current state.
+.Ed
+.Sh LANGUAGE SYNTAX
+.Nm
+documents may contain only graphable 7-bit ASCII characters, the space
+character, and, in certain circumstances, the tab character. All
+manuals must have
+.Ux
+line terminators.
+.Sh MACRO SYNTAX
+Macros are arbitrary in length and begin with a control character ,
+.Sq \.
+or
+.Sq \(aq ,
+at the beginning of the line.
+An arbitrary amount of whitespace may sit between the control character
+and the macro name.
+Thus, the following are equivalent:
+.Bd -literal -offset indent
+\&.if
+\&.\ \ \ \&if
+.Ed
+.Sh REFERENCE
+This section is a canonical reference of all macros, arranged
+alphabetically.
+.Ss \&if
+Begins a conditional.
+Has the following syntax:
+.Pp
+.Bd -literal -offset indent -compact
+\&.if COND \e{\e
+BODY...
+\&.\e}
+.Ed
+.Bd -literal -offset indent -compact
+\&.if COND \e{ BODY
+BODY...
+\&.\e}
+.Ed
+.Bd -literal -offset indent -compact
+\&.if COND \e
+BODY
+.Ed
+.Pp
+COND is a conditional (TODO: document).
+.Pp
+If the BODY section is begun by an escaped brace
+.Sq \e{ ,
+scope continues until a closing-brace macro
+.Sq \.\e} .
+If the BODY is not enclosed in braces, scope continues until the next
+macro or word.
+If the COND is followed by a BODY on the same line, whether after a
+brace or not, then macros
+.Em must
+begin with a control character.
+It is generally more intuitive, in this case, to write
+.Bd -literal -offset indent
+\&.if COND \e{\e
+\&.foo
+bar
+\&.\e}
+.Ed
+.Pp
+than having the macro follow as
+.Pp
+.D1 \&.if COND \e{ .foo
+.Pp
+The scope of a conditional is always parsed, but only executed if the
+conditional evaluates to true.
+.Pp
+Note that text subsequent a
+.Sq \e}
+is discarded.
+.Ss \&ig
+Ignore input until a
+.Sq \.\.
+macro is encountered on its own line.
+Note that text subsequent the
+.Sq \.\.
+is discarded.
+.Sh AUTHORS
+The
+.Nm
+reference was written by
+.An Kristaps Dzonsons Aq kristaps@bsd.lv .
diff --git a/roff.c b/roff.c
index f4858b00..e606bcd5 100644
--- a/roff.c
+++ b/roff.c
@@ -381,7 +381,9 @@ roff_ig(ROFF_ARGS)
ROFF_MDEBUG(r, "opening ignore block");
- /* FIXME: warn about end of line. */
+ if ((*bufp)[pos])
+ if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
+ return(ROFF_ERR);
return(ROFF_IGN);
}
@@ -391,6 +393,7 @@ roff_ig(ROFF_ARGS)
static enum rofferr
roff_if(ROFF_ARGS)
{
+ int sv;
/*
* Read ahead past the conditional.
@@ -399,14 +402,29 @@ roff_if(ROFF_ARGS)
* It's good enough for now, however.
*/
- if ( ! roffnode_push(r, tok, ln, ppos))
- return(ROFF_ERR);
-
while ((*bufp)[pos] && ' ' != (*bufp)[pos])
pos++;
+
+ sv = pos;
while (' ' == (*bufp)[pos])
pos++;
+ /*
+ * Roff is weird. If we have just white-space after the
+ * conditional, it's considered the BODY and we exit without
+ * 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 ( ! roffnode_push(r, tok, ln, ppos))
+ return(ROFF_ERR);
+
/* Don't evaluate: just assume NO. */
r->last->endspan = 1;
@@ -418,9 +436,16 @@ roff_if(ROFF_ARGS)
} else
ROFF_MDEBUG(r, "opening implicit scope");
+ /*
+ * If there are no arguments on the line, the next-line scope is
+ * assumed.
+ */
+
if ('\0' == (*bufp)[pos])
return(ROFF_IGN);
+ /* Otherwise re-run the roff parser after recalculating. */
+
*offs = pos;
return(ROFF_RERUN);
}