version 1.6, 2011/07/17 12:13:37 |
version 1.9, 2011/07/17 14:11:25 |
|
|
#include "libmandoc.h" |
#include "libmandoc.h" |
#include "libroff.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 *); |
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 */ |
/* ARGSUSED */ |
enum rofferr |
enum rofferr |
eqn_read(struct eqn_node **epp, int ln, |
eqn_read(struct eqn_node **epp, int ln, |
const char *p, int pos, int *offs) |
const char *p, int pos, int *offs) |
{ |
{ |
size_t sz; |
size_t sz; |
struct eqn_node *ep; |
struct eqn_node *ep; |
const char *start, *end; |
struct mparse *mp; |
int i; |
const char *start, *end; |
|
int i, c; |
|
|
if (0 == strcmp(p, ".EN")) { |
if (0 == strcmp(p, ".EN")) { |
*epp = NULL; |
*epp = NULL; |
Line 47 eqn_read(struct eqn_node **epp, int ln, |
|
Line 75 eqn_read(struct eqn_node **epp, int ln, |
|
} |
} |
|
|
ep = *epp; |
ep = *epp; |
|
mp = ep->parse; |
end = p + pos; |
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); |
return(ROFF_IGN); |
|
|
if (6 == sz && 0 == strncmp("define", start, 6)) { |
for (i = 0; i < (int)EQN__MAX; i++) { |
|
if (eqnparts[i].sz != sz) |
|
continue; |
|
if (strncmp(eqnparts[i].name, start, sz)) |
|
continue; |
|
|
|
if ((c = (*eqnparts[i].fp)(ep, ln, pos, &end)) < 0) |
|
return(ROFF_ERR); |
|
else if (0 == c || '\0' == *end) |
|
return(ROFF_IGN); |
|
|
/* |
/* |
* TODO: warn if key is quoted: groff doesn't seem to |
* Re-calculate offset and rerun, if trailing text. |
* like this (I don't know why). |
* This allows multiple definitions (say) on each line. |
*/ |
*/ |
start = eqn_nexttok(ep->parse, ln, pos, &end, &sz); |
|
for (i = 0; i < (int)ep->defsz; i++) { |
*offs = end - (p + pos); |
|
return(ROFF_RERUN); |
|
} |
|
|
|
end = p + pos; |
|
while (NULL != (start = eqn_nexttok(mp, ln, pos, &end, &sz))) { |
|
if (0 == sz) |
|
continue; |
|
|
|
for (i = 0; i < (int)ep->defsz; i++) { |
|
if (0 == ep->defs[i].keysz) |
|
continue; |
if (ep->defs[i].keysz != sz) |
if (ep->defs[i].keysz != sz) |
continue; |
continue; |
if (0 == strncmp(ep->defs[i].key, start, sz)) |
if (strncmp(ep->defs[i].key, start, sz)) |
break; |
continue; |
|
start = ep->defs[i].val; |
|
sz = ep->defs[i].valsz; |
|
break; |
} |
} |
|
|
/* |
ep->eqn.data = mandoc_realloc |
* TODO: merge this code with roff_getstr(). |
(ep->eqn.data, ep->eqn.sz + sz + 1); |
*/ |
|
|
|
if (i == (int)ep->defsz) { |
if (0 == ep->eqn.sz) |
ep->defsz++; |
*ep->eqn.data = '\0'; |
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->eqn.sz += sz; |
|
strlcat(ep->eqn.data, start, ep->eqn.sz + 1); |
|
} |
|
|
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'; |
|
|
|
if ('\0' == *end) |
|
return(ROFF_IGN); |
|
|
|
*offs = end - (p + pos); |
|
assert(*offs > 0); |
|
|
|
return(ROFF_RERUN); |
|
} else |
|
end = p + pos; |
|
|
|
if (0 == (sz = strlen(end))) |
|
return(ROFF_IGN); |
|
|
|
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, end, ep->eqn.sz + 1); |
|
return(ROFF_IGN); |
return(ROFF_IGN); |
} |
} |
|
|
Line 150 eqn_free(struct eqn_node *p) |
|
Line 168 eqn_free(struct eqn_node *p) |
|
free(p); |
free(p); |
} |
} |
|
|
|
/* |
|
* Return the current equation token setting "next" on the next one, |
|
* setting the token size in "sz". |
|
* This does the Right Thing for quoted strings, too. |
|
* Returns NULL if no more tokens exist. |
|
*/ |
static const char * |
static const char * |
eqn_nexttok(struct mparse *mp, int ln, int pos, |
eqn_nexttok(struct mparse *mp, int ln, int pos, |
const char **next, size_t *sz) |
const char **next, size_t *sz) |
Line 177 eqn_nexttok(struct mparse *mp, int ln, int pos, |
|
Line 201 eqn_nexttok(struct mparse *mp, int ln, int pos, |
|
while (' ' == **next) |
while (' ' == **next) |
(*next)++; |
(*next)++; |
} else { |
} else { |
|
/* |
|
* XXX: groff gets confused by this and doesn't always |
|
* do the "right thing" (just terminate it and warn |
|
* about it). |
|
*/ |
if (q) |
if (q) |
mandoc_msg(MANDOCERR_BADQUOTE, |
mandoc_msg(MANDOCERR_BADQUOTE, |
mp, ln, pos, NULL); |
mp, ln, pos, NULL); |
Line 185 eqn_nexttok(struct mparse *mp, int ln, int pos, |
|
Line 214 eqn_nexttok(struct mparse *mp, int ln, int pos, |
|
} |
} |
|
|
return(start); |
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].key = ep->defs[i].val = NULL; |
|
} |
|
|
|
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); |
} |
} |