diff options
-rw-r--r-- | main.c | 1 | ||||
-rw-r--r-- | mandoc.h | 1 | ||||
-rw-r--r-- | regress/roff/if/line-nest.in | 11 | ||||
-rw-r--r-- | regress/roff/if/multiline0.in | 12 | ||||
-rw-r--r-- | regress/roff/if/multiline1.in | 13 | ||||
-rw-r--r-- | regress/roff/if/multiline2.in | 15 | ||||
-rw-r--r-- | regress/roff/if/multiline3.in | 15 | ||||
-rw-r--r-- | regress/roff/if/simple0.in | 10 | ||||
-rw-r--r-- | regress/roff/if/simple1.in | 11 | ||||
-rw-r--r-- | regress/roff/if/simple2.in | 11 | ||||
-rw-r--r-- | roff.7 | 128 | ||||
-rw-r--r-- | roff.c | 33 |
12 files changed, 257 insertions, 4 deletions
@@ -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" }; @@ -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 @@ -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 . @@ -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); } |