diff options
author | Kristaps Dzonsons <kristaps@bsd.lv> | 2011-07-17 14:08:49 +0000 |
---|---|---|
committer | Kristaps Dzonsons <kristaps@bsd.lv> | 2011-07-17 14:08:49 +0000 |
commit | a726649696ac45144dc2ee6745a227b2c3d904ff (patch) | |
tree | 14ca09df41b18bf478a0cf96a464deeb70d38731 | |
parent | 5a3cf14ed1f0ef522bef48d363615fe746b6e9ee (diff) | |
download | mandoc-a726649696ac45144dc2ee6745a227b2c3d904ff.tar.gz |
Provide implementations of `define', `set', and `unset'.
Tie them into the stream of data.
Document these appropriate, bringing in the grammar as defined by the
original eqn manual (Kernighan/Richie).
-rw-r--r-- | eqn.7 | 75 | ||||
-rw-r--r-- | eqn.c | 251 | ||||
-rw-r--r-- | mandoc.h | 3 | ||||
-rw-r--r-- | read.c | 3 |
4 files changed, 261 insertions, 71 deletions
@@ -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 , @@ -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); +} @@ -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 */ @@ -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", |