version 1.129, 2011/03/22 09:50:11 |
version 1.139, 2011/05/24 14:00:39 |
|
|
#endif |
#endif |
|
|
#include <assert.h> |
#include <assert.h> |
#include <errno.h> |
|
#include <ctype.h> |
#include <ctype.h> |
#include <limits.h> |
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <stdio.h> |
|
|
|
#include "mandoc.h" |
#include "mandoc.h" |
#include "libroff.h" |
#include "libroff.h" |
|
|
|
|
#define RSTACK_MAX 128 |
#define RSTACK_MAX 128 |
|
|
#define ROFF_CTL(c) \ |
|
('.' == (c) || '\'' == (c)) |
|
|
|
enum rofft { |
enum rofft { |
ROFF_ad, |
ROFF_ad, |
ROFF_am, |
ROFF_am, |
Line 209 static void roffnode_push(struct roff *, enum rofft, |
|
Line 203 static void roffnode_push(struct roff *, enum rofft, |
|
const char *, int, int); |
const char *, int, int); |
static void roffnode_pop(struct roff *); |
static void roffnode_pop(struct roff *); |
static enum rofft roff_parse(struct roff *, const char *, int *); |
static enum rofft roff_parse(struct roff *, const char *, int *); |
static int roff_parse_nat(const char *, unsigned int *); |
|
|
|
/* See roff_hash_find() */ |
/* See roff_hash_find() */ |
#define ROFF_HASH(p) (p[0] - ASCII_LO) |
#define ROFF_HASH(p) (p[0] - ASCII_LO) |
Line 280 roffnode_pop(struct roff *r) |
|
Line 273 roffnode_pop(struct roff *r) |
|
assert(r->last); |
assert(r->last); |
p = r->last; |
p = r->last; |
|
|
if (ROFF_el == p->tok) |
|
if (r->rstackpos > -1) |
|
r->rstackpos--; |
|
|
|
r->last = r->last->parent; |
r->last = r->last->parent; |
free(p->name); |
free(p->name); |
free(p->end); |
free(p->end); |
Line 476 roff_parseln(struct roff *r, int ln, char **bufp, |
|
Line 465 roff_parseln(struct roff *r, int ln, char **bufp, |
|
{ |
{ |
enum rofft t; |
enum rofft t; |
enum rofferr e; |
enum rofferr e; |
int ppos; |
int ppos, ctl; |
|
|
/* |
/* |
* Run the reserved-word filter only if we have some reserved |
* Run the reserved-word filter only if we have some reserved |
Line 486 roff_parseln(struct roff *r, int ln, char **bufp, |
|
Line 475 roff_parseln(struct roff *r, int ln, char **bufp, |
|
if (r->first_string && ! roff_res(r, bufp, szp, pos)) |
if (r->first_string && ! roff_res(r, bufp, szp, pos)) |
return(ROFF_REPARSE); |
return(ROFF_REPARSE); |
|
|
|
ppos = pos; |
|
ctl = mandoc_getcontrol(*bufp, &pos); |
|
|
/* |
/* |
* First, if a scope is open and we're not a macro, pass the |
* First, if a scope is open and we're not a macro, pass the |
* text through the macro's filter. If a scope isn't open and |
* text through the macro's filter. If a scope isn't open and |
Line 494 roff_parseln(struct roff *r, int ln, char **bufp, |
|
Line 486 roff_parseln(struct roff *r, int ln, char **bufp, |
|
* no matter our state. |
* no matter our state. |
*/ |
*/ |
|
|
if (r->last && ! ROFF_CTL((*bufp)[pos])) { |
if (r->last && ! ctl) { |
t = r->last->tok; |
t = r->last->tok; |
assert(roffs[t].text); |
assert(roffs[t].text); |
e = (*roffs[t].text) |
e = (*roffs[t].text) |
Line 503 roff_parseln(struct roff *r, int ln, char **bufp, |
|
Line 495 roff_parseln(struct roff *r, int ln, char **bufp, |
|
if (ROFF_CONT != e) |
if (ROFF_CONT != e) |
return(e); |
return(e); |
if (r->eqn) |
if (r->eqn) |
return(eqn_read(&r->eqn, ln, *bufp, *offs)); |
return(eqn_read(&r->eqn, ln, *bufp, pos)); |
if (r->tbl) |
if (r->tbl) |
return(tbl_read(r->tbl, ln, *bufp, *offs)); |
return(tbl_read(r->tbl, ln, *bufp, pos)); |
return(ROFF_CONT); |
return(ROFF_CONT); |
} else if ( ! ROFF_CTL((*bufp)[pos])) { |
} else if ( ! ctl) { |
if (r->eqn) |
if (r->eqn) |
return(eqn_read(&r->eqn, ln, *bufp, *offs)); |
return(eqn_read(&r->eqn, ln, *bufp, pos)); |
if (r->tbl) |
if (r->tbl) |
return(tbl_read(r->tbl, ln, *bufp, *offs)); |
return(tbl_read(r->tbl, ln, *bufp, pos)); |
return(ROFF_CONT); |
return(ROFF_CONT); |
} else if (r->eqn) |
} else if (r->eqn) |
return(eqn_read(&r->eqn, ln, *bufp, *offs)); |
return(eqn_read(&r->eqn, ln, *bufp, ppos)); |
|
|
/* |
/* |
* If a scope is open, go to the child handler for that macro, |
* If a scope is open, go to the child handler for that macro, |
Line 527 roff_parseln(struct roff *r, int ln, char **bufp, |
|
Line 519 roff_parseln(struct roff *r, int ln, char **bufp, |
|
assert(roffs[t].sub); |
assert(roffs[t].sub); |
return((*roffs[t].sub) |
return((*roffs[t].sub) |
(r, t, bufp, szp, |
(r, t, bufp, szp, |
ln, pos, pos, offs)); |
ln, ppos, pos, offs)); |
} |
} |
|
|
/* |
/* |
Line 536 roff_parseln(struct roff *r, int ln, char **bufp, |
|
Line 528 roff_parseln(struct roff *r, int ln, char **bufp, |
|
* the compilers handle it. |
* the compilers handle it. |
*/ |
*/ |
|
|
ppos = pos; |
|
if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) |
if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) |
return(ROFF_CONT); |
return(ROFF_CONT); |
|
|
Line 570 roff_endparse(struct roff *r) |
|
Line 561 roff_endparse(struct roff *r) |
|
} |
} |
} |
} |
|
|
|
|
/* |
/* |
* Parse a roff node's type from the input buffer. This must be in the |
* Parse a roff node's type from the input buffer. This must be in the |
* form of ".foo xxx" in the usual way. |
* form of ".foo xxx" in the usual way. |
Line 582 roff_parse(struct roff *r, const char *buf, int *pos) |
|
Line 572 roff_parse(struct roff *r, const char *buf, int *pos) |
|
size_t maclen; |
size_t maclen; |
enum rofft t; |
enum rofft t; |
|
|
assert(ROFF_CTL(buf[*pos])); |
if ('\0' == buf[*pos] || '"' == buf[*pos]) |
(*pos)++; |
|
|
|
while (' ' == buf[*pos] || '\t' == buf[*pos]) |
|
(*pos)++; |
|
|
|
if ('\0' == buf[*pos]) |
|
return(ROFF_MAX); |
return(ROFF_MAX); |
|
|
mac = buf + *pos; |
mac = buf + *pos; |
Line 598 roff_parse(struct roff *r, const char *buf, int *pos) |
|
Line 582 roff_parse(struct roff *r, const char *buf, int *pos) |
|
? ROFF_USERDEF : roff_hash_find(mac, maclen); |
? ROFF_USERDEF : roff_hash_find(mac, maclen); |
|
|
*pos += (int)maclen; |
*pos += (int)maclen; |
|
|
while (buf[*pos] && ' ' == buf[*pos]) |
while (buf[*pos] && ' ' == buf[*pos]) |
(*pos)++; |
(*pos)++; |
|
|
return(t); |
return(t); |
} |
} |
|
|
|
|
static int |
|
roff_parse_nat(const char *buf, unsigned int *res) |
|
{ |
|
char *ep; |
|
long lval; |
|
|
|
errno = 0; |
|
lval = strtol(buf, &ep, 10); |
|
if (buf[0] == '\0' || *ep != '\0') |
|
return(0); |
|
if ((errno == ERANGE && |
|
(lval == LONG_MAX || lval == LONG_MIN)) || |
|
(lval > INT_MAX || lval < 0)) |
|
return(0); |
|
|
|
*res = (unsigned int)lval; |
|
return(1); |
|
} |
|
|
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static enum rofferr |
static enum rofferr |
roff_cblock(ROFF_ARGS) |
roff_cblock(ROFF_ARGS) |
Line 746 roff_block(ROFF_ARGS) |
|
Line 710 roff_block(ROFF_ARGS) |
|
mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, |
mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, |
roffs[tok].name); |
roffs[tok].name); |
|
|
while ((*bufp)[pos] && ' ' != (*bufp)[pos]) |
while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos])) |
pos++; |
pos++; |
|
|
while (' ' == (*bufp)[pos]) |
while (isspace((unsigned char)(*bufp)[pos])) |
(*bufp)[pos++] = '\0'; |
(*bufp)[pos++] = '\0'; |
} |
} |
|
|
Line 770 roff_block(ROFF_ARGS) |
|
Line 734 roff_block(ROFF_ARGS) |
|
/* If present, process the custom end-of-line marker. */ |
/* If present, process the custom end-of-line marker. */ |
|
|
sv = pos; |
sv = pos; |
while ((*bufp)[pos] && |
while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos])) |
' ' != (*bufp)[pos] && |
|
'\t' != (*bufp)[pos]) |
|
pos++; |
pos++; |
|
|
/* |
/* |
Line 816 roff_block_sub(ROFF_ARGS) |
|
Line 778 roff_block_sub(ROFF_ARGS) |
|
*/ |
*/ |
|
|
if (r->last->end) { |
if (r->last->end) { |
i = pos + 1; |
for (i = pos, j = 0; r->last->end[j]; j++, i++) |
while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) |
|
i++; |
|
|
|
for (j = 0; r->last->end[j]; j++, i++) |
|
if ((*bufp)[i] != r->last->end[j]) |
if ((*bufp)[i] != r->last->end[j]) |
break; |
break; |
|
|
Line 831 roff_block_sub(ROFF_ARGS) |
|
Line 789 roff_block_sub(ROFF_ARGS) |
|
roffnode_pop(r); |
roffnode_pop(r); |
roffnode_cleanscope(r); |
roffnode_cleanscope(r); |
|
|
|
while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) |
|
i++; |
|
|
|
pos = i; |
if (ROFF_MAX != roff_parse(r, *bufp, &pos)) |
if (ROFF_MAX != roff_parse(r, *bufp, &pos)) |
return(ROFF_RERUN); |
return(ROFF_RERUN); |
return(ROFF_IGN); |
return(ROFF_IGN); |
Line 842 roff_block_sub(ROFF_ARGS) |
|
Line 804 roff_block_sub(ROFF_ARGS) |
|
* pulling it out of the hashtable. |
* pulling it out of the hashtable. |
*/ |
*/ |
|
|
ppos = pos; |
|
t = roff_parse(r, *bufp, &pos); |
t = roff_parse(r, *bufp, &pos); |
|
|
/* |
/* |
Line 879 roff_cond_sub(ROFF_ARGS) |
|
Line 840 roff_cond_sub(ROFF_ARGS) |
|
{ |
{ |
enum rofft t; |
enum rofft t; |
enum roffrule rr; |
enum roffrule rr; |
|
char *ep; |
|
|
ppos = pos; |
|
rr = r->last->rule; |
rr = r->last->rule; |
|
roffnode_cleanscope(r); |
|
|
/* |
/* |
* Clean out scope. If we've closed ourselves, then don't |
* If the macro is unknown, first check if it contains a closing |
* continue. |
* delimiter `\}'. If it does, close out our scope and return |
|
* the currently-scoped rule (ignore or continue). Else, drop |
|
* into the currently-scoped rule. |
*/ |
*/ |
|
|
roffnode_cleanscope(r); |
|
|
|
if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) { |
if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) { |
if ('\\' == (*bufp)[pos] && '}' == (*bufp)[pos + 1]) |
/* |
return(roff_ccond |
* Jump through hoops to detect a \}, because it could |
(r, ROFF_ccond, bufp, szp, |
* be (say) \\}, which is something completely |
ln, pos, pos + 2, offs)); |
* different. |
|
*/ |
|
ep = &(*bufp)[pos]; |
|
for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { |
|
ep++; |
|
if ('}' != *ep) |
|
continue; |
|
*--ep = '\0'; |
|
roff_ccond(r, ROFF_ccond, bufp, szp, |
|
ln, pos, pos + 2, offs); |
|
break; |
|
} |
return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); |
return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); |
} |
} |
|
|
Line 903 roff_cond_sub(ROFF_ARGS) |
|
Line 876 roff_cond_sub(ROFF_ARGS) |
|
* if they're either structurally required (such as loops and |
* if they're either structurally required (such as loops and |
* conditionals) or a closing macro. |
* conditionals) or a closing macro. |
*/ |
*/ |
|
|
if (ROFFRULE_DENY == rr) |
if (ROFFRULE_DENY == rr) |
if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) |
if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) |
if (ROFF_ccond != t) |
if (ROFF_ccond != t) |
Line 986 roff_cond(ROFF_ARGS) |
|
Line 960 roff_cond(ROFF_ARGS) |
|
int sv; |
int sv; |
enum roffrule rule; |
enum roffrule rule; |
|
|
/* Stack overflow! */ |
/* |
|
* An `.el' has no conditional body: it will consume the value |
|
* of the current rstack entry set in prior `ie' calls or |
|
* defaults to DENY. |
|
* |
|
* If we're not an `el', however, then evaluate the conditional. |
|
*/ |
|
|
if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) { |
rule = ROFF_el == tok ? |
mandoc_msg(MANDOCERR_MEM, r->parse, ln, ppos, NULL); |
(r->rstackpos < 0 ? |
return(ROFF_ERR); |
ROFFRULE_DENY : r->rstack[r->rstackpos--]) : |
} |
roff_evalcond(*bufp, &pos); |
|
|
/* First, evaluate the conditional. */ |
|
|
|
if (ROFF_el == tok) { |
|
/* |
|
* An `.el' will get the value of the current rstack |
|
* entry set in prior `ie' calls or defaults to DENY. |
|
*/ |
|
if (r->rstackpos < 0) |
|
rule = ROFFRULE_DENY; |
|
else |
|
rule = r->rstack[r->rstackpos]; |
|
} else |
|
rule = roff_evalcond(*bufp, &pos); |
|
|
|
sv = pos; |
sv = pos; |
|
|
while (' ' == (*bufp)[pos]) |
while (' ' == (*bufp)[pos]) |
pos++; |
pos++; |
|
|
Line 1028 roff_cond(ROFF_ARGS) |
|
Line 993 roff_cond(ROFF_ARGS) |
|
|
|
r->last->rule = rule; |
r->last->rule = rule; |
|
|
|
/* |
|
* An if-else will put the NEGATION of the current evaluated |
|
* conditional into the stack of rules. |
|
*/ |
|
|
if (ROFF_ie == tok) { |
if (ROFF_ie == tok) { |
/* |
if (r->rstackpos == RSTACK_MAX - 1) { |
* An if-else will put the NEGATION of the current |
mandoc_msg(MANDOCERR_MEM, |
* evaluated conditional into the stack. |
r->parse, ln, ppos, NULL); |
*/ |
return(ROFF_ERR); |
r->rstackpos++; |
} |
if (ROFFRULE_DENY == r->last->rule) |
r->rstack[++r->rstackpos] = |
r->rstack[r->rstackpos] = ROFFRULE_ALLOW; |
ROFFRULE_DENY == r->last->rule ? |
else |
ROFFRULE_ALLOW : ROFFRULE_DENY; |
r->rstack[r->rstackpos] = ROFFRULE_DENY; |
|
} |
} |
|
|
/* If the parent has false as its rule, then so do we. */ |
/* If the parent has false as its rule, then so do we. */ |
Line 1110 roff_nr(ROFF_ARGS) |
|
Line 1079 roff_nr(ROFF_ARGS) |
|
{ |
{ |
const char *key; |
const char *key; |
char *val; |
char *val; |
|
int iv; |
struct reg *rg; |
struct reg *rg; |
|
|
val = *bufp + pos; |
val = *bufp + pos; |
Line 1118 roff_nr(ROFF_ARGS) |
|
Line 1088 roff_nr(ROFF_ARGS) |
|
|
|
if (0 == strcmp(key, "nS")) { |
if (0 == strcmp(key, "nS")) { |
rg[(int)REG_nS].set = 1; |
rg[(int)REG_nS].set = 1; |
if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u)) |
if ((iv = mandoc_strntou(val, strlen(val), 10)) >= 0) |
rg[(int)REG_nS].v.u = 0; |
rg[REG_nS].v.u = (unsigned)iv; |
|
else |
|
rg[(int)REG_nS].v.u = 0u; |
} |
} |
|
|
return(ROFF_IGN); |
return(ROFF_IGN); |