-/* $Id: roff.c,v 1.128 2011/03/20 16:02:05 kristaps Exp $ */
+/* $Id: roff.c,v 1.138 2011/05/14 16:06:08 kristaps Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
#endif
#include <assert.h>
-#include <errno.h>
#include <ctype.h>
-#include <limits.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
#include "mandoc.h"
-#include "roff.h"
#include "libroff.h"
#include "libmandoc.h"
#define RSTACK_MAX 128
-#define ROFF_CTL(c) \
- ('.' == (c) || '\'' == (c))
-
enum rofft {
ROFF_ad,
ROFF_am,
const char *, int, int);
static void roffnode_pop(struct roff *);
static enum rofft roff_parse(struct roff *, const char *, int *);
-static int roff_parse_nat(const char *, unsigned int *);
/* See roff_hash_find() */
#define ROFF_HASH(p) (p[0] - ASCII_LO)
assert(r->last);
p = r->last;
- if (ROFF_el == p->tok)
- if (r->rstackpos > -1)
- r->rstackpos--;
-
r->last = r->last->parent;
free(p->name);
free(p->end);
{
enum rofft t;
enum rofferr e;
- int ppos;
+ int ppos, ctl;
/*
* Run the reserved-word filter only if we have some reserved
if (r->first_string && ! roff_res(r, bufp, szp, pos))
return(ROFF_REPARSE);
+ ppos = pos;
+ ctl = mandoc_getcontrol(*bufp, &pos);
+
/*
* 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
* no matter our state.
*/
- if (r->last && ! ROFF_CTL((*bufp)[pos])) {
+ if (r->last && ! ctl) {
t = r->last->tok;
assert(roffs[t].text);
e = (*roffs[t].text)
if (ROFF_CONT != e)
return(e);
if (r->eqn)
- return(eqn_read(&r->eqn, ln, *bufp, *offs));
+ return(eqn_read(&r->eqn, ln, *bufp, pos));
if (r->tbl)
- return(tbl_read(r->tbl, ln, *bufp, *offs));
+ return(tbl_read(r->tbl, ln, *bufp, pos));
return(ROFF_CONT);
- } else if ( ! ROFF_CTL((*bufp)[pos])) {
+ } else if ( ! ctl) {
if (r->eqn)
- return(eqn_read(&r->eqn, ln, *bufp, *offs));
+ return(eqn_read(&r->eqn, ln, *bufp, pos));
if (r->tbl)
- return(tbl_read(r->tbl, ln, *bufp, *offs));
+ return(tbl_read(r->tbl, ln, *bufp, pos));
return(ROFF_CONT);
} 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,
assert(roffs[t].sub);
return((*roffs[t].sub)
(r, t, bufp, szp,
- ln, pos, pos, offs));
+ ln, ppos, pos, offs));
}
/*
* the compilers handle it.
*/
- ppos = pos;
if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos)))
return(ROFF_CONT);
}
}
-
/*
* Parse a roff node's type from the input buffer. This must be in the
* form of ".foo xxx" in the usual way.
size_t maclen;
enum rofft t;
- assert(ROFF_CTL(buf[*pos]));
- (*pos)++;
-
- while (' ' == buf[*pos] || '\t' == buf[*pos])
- (*pos)++;
-
- if ('\0' == buf[*pos])
+ if ('\0' == buf[*pos] || '"' == buf[*pos])
return(ROFF_MAX);
mac = buf + *pos;
? ROFF_USERDEF : roff_hash_find(mac, maclen);
*pos += (int)maclen;
+
while (buf[*pos] && ' ' == buf[*pos])
(*pos)++;
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 */
static enum rofferr
roff_cblock(ROFF_ARGS)
mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
roffs[tok].name);
- while ((*bufp)[pos] && ' ' != (*bufp)[pos])
+ while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
pos++;
- while (' ' == (*bufp)[pos])
+ while (isspace((unsigned char)(*bufp)[pos]))
(*bufp)[pos++] = '\0';
}
/* If present, process the custom end-of-line marker. */
sv = pos;
- while ((*bufp)[pos] &&
- ' ' != (*bufp)[pos] &&
- '\t' != (*bufp)[pos])
+ while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
pos++;
/*
*/
if (r->last->end) {
- i = pos + 1;
- while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
- i++;
-
- for (j = 0; r->last->end[j]; j++, i++)
+ for (i = pos, j = 0; r->last->end[j]; j++, i++)
if ((*bufp)[i] != r->last->end[j])
break;
roffnode_pop(r);
roffnode_cleanscope(r);
+ while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
+ i++;
+
+ pos = i;
if (ROFF_MAX != roff_parse(r, *bufp, &pos))
return(ROFF_RERUN);
return(ROFF_IGN);
* pulling it out of the hashtable.
*/
- ppos = pos;
t = roff_parse(r, *bufp, &pos);
/*
enum rofft t;
enum roffrule rr;
- ppos = pos;
rr = r->last->rule;
/*
int sv;
enum roffrule rule;
- /* Stack overflow! */
-
- if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) {
- mandoc_msg(MANDOCERR_MEM, r->parse, ln, ppos, NULL);
- return(ROFF_ERR);
- }
+ /*
+ * 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.
+ */
- /* 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);
+ rule = ROFF_el == tok ?
+ (r->rstackpos < 0 ?
+ ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
+ roff_evalcond(*bufp, &pos);
sv = pos;
-
while (' ' == (*bufp)[pos])
pos++;
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) {
- /*
- * An if-else will put the NEGATION of the current
- * evaluated conditional into the stack.
- */
- r->rstackpos++;
- if (ROFFRULE_DENY == r->last->rule)
- r->rstack[r->rstackpos] = ROFFRULE_ALLOW;
- else
- r->rstack[r->rstackpos] = ROFFRULE_DENY;
+ if (r->rstackpos == RSTACK_MAX - 1) {
+ mandoc_msg(MANDOCERR_MEM,
+ r->parse, ln, ppos, NULL);
+ return(ROFF_ERR);
+ }
+ r->rstack[++r->rstackpos] =
+ ROFFRULE_DENY == r->last->rule ?
+ ROFFRULE_ALLOW : ROFFRULE_DENY;
}
/* If the parent has false as its rule, then so do we. */
{
const char *key;
char *val;
+ int iv;
struct reg *rg;
val = *bufp + pos;
if (0 == strcmp(key, "nS")) {
rg[(int)REG_nS].set = 1;
- if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u))
- rg[(int)REG_nS].v.u = 0;
+ if ((iv = mandoc_strntou(val, strlen(val), 10)) >= 0)
+ rg[REG_nS].v.u = (unsigned)iv;
+ else
+ rg[(int)REG_nS].v.u = 0u;
}
return(ROFF_IGN);