summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eqn.775
-rw-r--r--eqn.c251
-rw-r--r--mandoc.h3
-rw-r--r--read.c3
4 files changed, 261 insertions, 71 deletions
diff --git a/eqn.7 b/eqn.7
index 49a355e7..46540b8d 100644
--- a/eqn.7
+++ b/eqn.7
@@ -40,26 +40,69 @@ Equations within
.Xr mdoc 7
or
.Xr man 7
-are enclosed by the
-.Sq EQ
+documents are enclosed by the standalone
+.Sq \&.EQ
and
-.Sq EN
-macro tags, whose precise syntax is documented in
-.Xr roff 7 .
-Equations consist of multi-line equation data.
+.Sq \&.EN
+tags.
+Equations are multi-line blocks consisting of formulas and control
+statements.
+.Sh EQUATION STRUCTURE
+Each equation is bracketed by
+.Sq \&.EQ
+and
+.Sq \&.EN
+strings.
+.Em Note :
+these are not the same as
+.Xr roff 7
+macros, and may only be invoked as
+.Sq \&.EQ .
.Pp
-For the time being,
-.Xr mandoc 1
-reproduces the contents of
-.Nm
-equations verbatim in its output.
+The equation grammar is as follows:
+.Bd -literal -offset indent
+eqn : box | eqn box
+box : text
+ | DEFINE text text
+ | SET text text
+ | UNDEF text
+text : TEXT
+.Ed
.Pp
-The
+Data in TEXT form is a non-empty sequence of non-space characters or a
+non-empty quoted string.
+White-space (and enclosing literal quote pairs) is thrown away and
+productions may not be broken by newlines.
+.Pp
+The following control statements are available:
+.Bl -tag -width Ds
+.It Cm define
+Replace all occurances of a key with a value.
+Its syntax is as follows:
+.Pp
+.D1 define Ar key val
+.Pp
+It is an error to have an empty
+.Ar key or
+.Ar value .
+Note that a quoted
+.Ar key
+causes errors in some
.Nm
-implementation in
-.Xr mandoc 1
-is
-.Ud
+implementations and should not be considered portable.
+.It Cm set
+Set an equation mode.
+Both arguments are thrown away.
+.It Cm undef
+Unset a previously-defined key.
+Its syntax is as follows:
+.Pp
+.D1 define Ar key
+.Pp
+Once invoked, the definition for
+.Ar key
+is discarded.
+.El
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr man 7 ,
diff --git a/eqn.c b/eqn.c
index 66850466..9727f116 100644
--- a/eqn.c
+++ b/eqn.c
@@ -28,18 +28,46 @@
#include "libmandoc.h"
#include "libroff.h"
-static const char *eqn_nexttok(struct mparse *, int, int,
+#define EQN_ARGS struct eqn_node *ep, \
+ int ln, \
+ int pos, \
+ const char **end
+
+struct eqnpart {
+ const char *name;
+ size_t sz;
+ int (*fp)(EQN_ARGS);
+};
+
+enum eqnpartt {
+ EQN_DEFINE = 0,
+ EQN_SET,
+ EQN_UNDEF,
+ EQN__MAX
+};
+
+static int eqn_do_define(EQN_ARGS);
+static int eqn_do_set(EQN_ARGS);
+static int eqn_do_undef(EQN_ARGS);
+static const char *eqn_nexttok(struct mparse *, int, int,
const char **, size_t *);
+static const struct eqnpart eqnparts[EQN__MAX] = {
+ { "define", 6, eqn_do_define }, /* EQN_DEFINE */
+ { "set", 3, eqn_do_set }, /* EQN_SET */
+ { "undef", 5, eqn_do_undef }, /* EQN_UNDEF */
+};
+
/* ARGSUSED */
enum rofferr
eqn_read(struct eqn_node **epp, int ln,
const char *p, int pos, int *offs)
{
- size_t sz;
- struct eqn_node *ep;
- const char *start, *end;
- int i;
+ size_t sz;
+ struct eqn_node *ep;
+ struct mparse *mp;
+ const char *start, *end;
+ int i, c;
if (0 == strcmp(p, ".EN")) {
*epp = NULL;
@@ -47,70 +75,59 @@ eqn_read(struct eqn_node **epp, int ln,
}
ep = *epp;
+ mp = ep->parse;
end = p + pos;
- start = eqn_nexttok(ep->parse, ln, pos, &end, &sz);
- if (NULL == start)
+ if (NULL == (start = eqn_nexttok(mp, ln, pos, &end, &sz)))
return(ROFF_IGN);
- if (6 == sz && 0 == strncmp("define", start, 6)) {
- if (end && '"' == *end)
- mandoc_msg(MANDOCERR_EQNQUOTE,
- ep->parse, ln, pos, NULL);
-
- start = eqn_nexttok(ep->parse, ln, pos, &end, &sz);
+ for (i = 0; i < (int)EQN__MAX; i++) {
+ if (eqnparts[i].sz != sz)
+ continue;
+ if (strncmp(eqnparts[i].name, start, sz))
+ continue;
- for (i = 0; i < (int)ep->defsz; i++) {
- if (ep->defs[i].keysz != sz)
- continue;
- if (0 == strncmp(ep->defs[i].key, start, sz))
- break;
- }
+ if ((c = (*eqnparts[i].fp)(ep, ln, pos, &end)) < 0)
+ return(ROFF_ERR);
+ else if (0 == c || '\0' == *end)
+ return(ROFF_IGN);
- /*
- * TODO: merge this code with roff_getstr().
+ /*
+ * Re-calculate offset and rerun, if trailing text.
+ * This allows multiple definitions (say) on each line.
*/
- if (i == (int)ep->defsz) {
- ep->defsz++;
- ep->defs = mandoc_realloc
- (ep->defs, ep->defsz *
- sizeof(struct eqn_def));
- ep->defs[i].keysz = sz;
- ep->defs[i].key = mandoc_malloc(sz + 1);
- memcpy(ep->defs[i].key, start, sz);
- ep->defs[i].key[(int)sz] = '\0';
- ep->defs[i].val = NULL;
- ep->defs[i].valsz = 0;
- }
-
- start = eqn_nexttok(ep->parse, ln, pos, &end, &sz);
-
- ep->defs[i].valsz = sz;
- ep->defs[i].val = mandoc_realloc
- (ep->defs[i].val, sz + 1);
- memcpy(ep->defs[i].val, start, sz);
- ep->defs[i].val[(int)sz] = '\0';
+ *offs = end - (p + pos);
+ return(ROFF_RERUN);
+ }
- if ('\0' == *end)
- return(ROFF_IGN);
+ end = p + pos;
+ while (NULL != (start = eqn_nexttok(mp, ln, pos, &end, &sz))) {
+ if (0 == sz)
+ continue;
- *offs = end - (p + pos);
- assert(*offs > 0);
+ for (i = 0; i < (int)ep->defsz; i++) {
+ if (0 == ep->defs[i].keysz)
+ continue;
+ if (ep->defs[i].keysz != sz)
+ continue;
+ if (strncmp(ep->defs[i].key, start, sz))
+ continue;
+ start = ep->defs[i].val;
+ sz = ep->defs[i].valsz;
+ break;
+ }
- return(ROFF_RERUN);
- } else
- end = p + pos;
+ ep->eqn.data = mandoc_realloc
+ (ep->eqn.data, ep->eqn.sz + sz + 1);
- if (0 == (sz = strlen(end)))
- return(ROFF_IGN);
+ if (0 == ep->eqn.sz)
+ *ep->eqn.data = '\0';
- ep->eqn.data = mandoc_realloc(ep->eqn.data, ep->eqn.sz + sz + 1);
- if (0 == ep->eqn.sz)
- *ep->eqn.data = '\0';
+ ep->eqn.sz += sz;
+ strlcat(ep->eqn.data, start, ep->eqn.sz + 1);
+ }
- ep->eqn.sz += sz;
- strlcat(ep->eqn.data, end, ep->eqn.sz + 1);
return(ROFF_IGN);
}
@@ -198,3 +215,127 @@ eqn_nexttok(struct mparse *mp, int ln, int pos,
return(start);
}
+
+static int
+eqn_do_set(struct eqn_node *ep, int ln, int pos, const char **end)
+{
+ const char *start;
+ struct mparse *mp;
+ size_t sz;
+
+ mp = ep->parse;
+
+ start = eqn_nexttok(ep->parse, ln, pos, end, &sz);
+ if (NULL == start || 0 == sz) {
+ mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
+ return(0);
+ }
+
+ start = eqn_nexttok(ep->parse, ln, pos, end, &sz);
+ if (NULL == start || 0 == sz) {
+ mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
+ return(0);
+ }
+
+ return(1);
+}
+
+static int
+eqn_do_define(struct eqn_node *ep, int ln, int pos, const char **end)
+{
+ const char *start;
+ struct mparse *mp;
+ size_t sz;
+ int i;
+
+ mp = ep->parse;
+
+ start = eqn_nexttok(mp, ln, pos, end, &sz);
+ if (NULL == start || 0 == sz) {
+ mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
+ return(0);
+ }
+
+ /* TODO: merge this code with roff_getstr(). */
+
+ /*
+ * Search for a key that already exists.
+ * Note that the string array can have "holes" (null key).
+ */
+
+ for (i = 0; i < (int)ep->defsz; i++) {
+ if (0 == ep->defs[i].keysz || ep->defs[i].keysz != sz)
+ continue;
+ if (0 == strncmp(ep->defs[i].key, start, sz))
+ break;
+ }
+
+ /* Create a new key. */
+
+ if (i == (int)ep->defsz) {
+ /* Find holes in string array. */
+ for (i = 0; i < (int)ep->defsz; i++)
+ if (0 == ep->defs[i].keysz)
+ break;
+
+ if (i == (int)ep->defsz) {
+ ep->defsz++;
+ ep->defs = mandoc_realloc
+ (ep->defs, ep->defsz *
+ sizeof(struct eqn_def));
+ }
+
+ ep->defs[i].keysz = sz;
+ ep->defs[i].key = mandoc_realloc
+ (ep->defs[i].key, sz + 1);
+
+ memcpy(ep->defs[i].key, start, sz);
+ ep->defs[i].key[(int)sz] = '\0';
+ ep->defs[i].val = NULL;
+ ep->defs[i].valsz = 0;
+ }
+
+ start = eqn_nexttok(mp, ln, pos, end, &sz);
+
+ if (NULL == start || 0 == sz) {
+ ep->defs[i].keysz = 0;
+ mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
+ return(0);
+ }
+
+ ep->defs[i].valsz = sz;
+ ep->defs[i].val = mandoc_realloc
+ (ep->defs[i].val, sz + 1);
+ memcpy(ep->defs[i].val, start, sz);
+ ep->defs[i].val[(int)sz] = '\0';
+
+ return(sz ? 1 : 0);
+}
+
+static int
+eqn_do_undef(struct eqn_node *ep, int ln, int pos, const char **end)
+{
+ const char *start;
+ struct mparse *mp;
+ size_t sz;
+ int i;
+
+ mp = ep->parse;
+
+ start = eqn_nexttok(mp, ln, pos, end, &sz);
+ if (NULL == start || 0 == sz) {
+ mandoc_msg(MANDOCERR_EQNARGS, mp, ln, pos, NULL);
+ return(0);
+ }
+
+ for (i = 0; i < (int)ep->defsz; i++) {
+ if (0 == ep->defs[i].keysz || ep->defs[i].keysz != sz)
+ continue;
+ if (strncmp(ep->defs[i].key, start, sz))
+ continue;
+ ep->defs[i].keysz = 0;
+ break;
+ }
+
+ return(1);
+}
diff --git a/mandoc.h b/mandoc.h
index f545be22..f83154aa 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -109,6 +109,9 @@ enum mandocerr {
MANDOCERR_ERROR, /* ===== start of errors ===== */
+ /* related to equations */
+ MANDOCERR_EQNARGS, /* bad equation macro arguments */
+
/* related to tables */
MANDOCERR_TBL, /* bad table syntax */
MANDOCERR_TBLOPT, /* bad table option */
diff --git a/read.c b/read.c
index f8390552..28d53acc 100644
--- a/read.c
+++ b/read.c
@@ -152,6 +152,9 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"generic error",
+ /* related to equations */
+ "bad equation macro syntax",
+
/* related to tables */
"bad table syntax",
"bad table option",