-/* $Id: roff.c,v 1.143 2011/06/30 08:05:13 kristaps Exp $ */
+/* $Id: roff.c,v 1.153 2011/07/26 14:24:06 kristaps Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
ROFFRULE_DENY
};
+/*
+ * A single register entity. If "set" is zero, the value of the
+ * register should be the default one, which is per-register.
+ * Registers are assumed to be unsigned ints for now.
+ */
+struct reg {
+ int set; /* whether set or not */
+ unsigned int u; /* unsigned integer */
+};
+
struct roffstr {
char *name; /* key of symbol */
char *string; /* current value */
struct roffnode *last; /* leaf of stack */
enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
int rstackpos; /* position in rstack */
- struct regset *regs; /* read/writable registers */
+ struct reg regs[REG__MAX];
struct roffstr *first_string; /* user-defined strings & macros */
const char *current_string; /* value of last called user macro */
struct tbl_node *first_tbl; /* first table parsed */
roff_free1(r);
+ memset(&r->regs, 0, sizeof(struct reg) * REG__MAX);
+
for (i = 0; i < PREDEFS_MAX; i++)
roff_setstr(r, predefs[i].name, predefs[i].str, 0);
}
struct roff *
-roff_alloc(struct regset *regs, struct mparse *parse)
+roff_alloc(struct mparse *parse)
{
struct roff *r;
int i;
r = mandoc_calloc(1, sizeof(struct roff));
- r->regs = regs;
r->parse = parse;
r->rstackpos = -1;
return(r);
}
-
/*
* Pre-filter each and every line for reserved words (one beginning with
* `\*', e.g., `\*(ab'). These must be handled before the actual line
* is processed.
- */
+ * This also checks the syntax of regular escapes.
+*/
static int
roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
{
+ enum mandoc_esc esc;
const char *stesc; /* start of an escape sequence ('\\') */
const char *stnam; /* start of the name, after "[(*" */
const char *cp; /* end of the name, e.g. before ']' */
if ('\0' == *cp)
return(1);
- if ('*' != *cp++)
+
+ if ('*' != *cp) {
+ res = cp;
+ esc = mandoc_escape(&cp, NULL, NULL);
+ if (ESCAPE_ERROR != esc)
+ continue;
+ cp = res;
+ mandoc_msg
+ (MANDOCERR_BADESCAPE, r->parse,
+ ln, (int)(stesc - *bufp), NULL);
continue;
+ }
+
+ cp++;
/*
* The third character decides the length
/* Advance to the end of the name. */
for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
- if ('\0' == *cp)
- return(1); /* Error. */
+ if ('\0' == *cp) {
+ mandoc_msg
+ (MANDOCERR_BADESCAPE,
+ r->parse, ln,
+ (int)(stesc - *bufp), NULL);
+ return(1);
+ }
if (0 == maxl && ']' == *cp)
break;
}
res = roff_getstrn(r, stnam, (size_t)i);
if (NULL == res) {
- /* TODO: keep track of the correct position. */
- mandoc_msg(MANDOCERR_BADESCAPE, r->parse, ln, pos, NULL);
+ mandoc_msg
+ (MANDOCERR_BADESCAPE, r->parse,
+ ln, (int)(stesc - *bufp), NULL);
res = "";
}
return(1);
}
-
enum rofferr
roff_parseln(struct roff *r, int ln, char **bufp,
size_t *szp, int pos, int *offs)
* words to fill in.
*/
- if (r->first_string && ! roff_res(r, bufp, szp, ln, pos))
+ if ( ! roff_res(r, bufp, szp, ln, pos))
return(ROFF_REPARSE);
ppos = pos;
if (ROFF_CONT != e)
return(e);
if (r->eqn)
- return(eqn_read(&r->eqn, ln, *bufp, pos));
+ return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
if (r->tbl)
return(tbl_read(r->tbl, ln, *bufp, pos));
return(ROFF_CONT);
} else if ( ! ctl) {
if (r->eqn)
- return(eqn_read(&r->eqn, ln, *bufp, pos));
+ return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
if (r->tbl)
return(tbl_read(r->tbl, ln, *bufp, pos));
return(ROFF_CONT);
} else if (r->eqn)
- return(eqn_read(&r->eqn, ln, *bufp, ppos));
+ return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
/*
* If a scope is open, go to the child handler for that macro,
if (r->eqn) {
mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->eqn->eqn.line, r->eqn->eqn.pos, NULL);
- eqn_end(r->eqn);
- r->eqn = NULL;
+ r->eqn->eqn.ln, r->eqn->eqn.pos, NULL);
+ eqn_end(&r->eqn);
}
if (r->tbl) {
mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
r->tbl->line, r->tbl->pos, NULL);
- tbl_end(r->tbl);
- r->tbl = NULL;
+ tbl_end(&r->tbl);
}
}
size_t maclen;
enum rofft t;
- if ('\0' == buf[*pos] || '"' == buf[*pos])
+ if ('\0' == buf[*pos] || '"' == buf[*pos] ||
+ '\t' == buf[*pos] || ' ' == buf[*pos])
return(ROFF_MAX);
+ /*
+ * We stop the macro parse at an escape, tab, space, or nil.
+ * However, `\}' is also a valid macro, so make sure we don't
+ * clobber it by seeing the `\' as the end of token.
+ */
+
mac = buf + *pos;
- maclen = strcspn(mac, " \\\t\0");
+ maclen = strcspn(mac + 1, " \\\t\0") + 1;
t = (r->current_string = roff_getstrn(r, mac, maclen))
? ROFF_USERDEF : roff_hash_find(mac, maclen);
ep++;
if ('}' != *ep)
continue;
- *ep = '&';
+
+ /*
+ * Make the \} go away.
+ * This is a little haphazard, as it's not quite
+ * clear how nroff does this.
+ * If we're at the end of line, then just chop
+ * off the \} and resize the buffer.
+ * If we aren't, then conver it to spaces.
+ */
+
+ if ('\0' == *(ep + 1)) {
+ *--ep = '\0';
+ *szp -= 2;
+ } else
+ *(ep - 1) = *ep = ' ';
+
roff_ccond(r, ROFF_ccond, bufp, szp,
ln, pos, pos + 2, offs);
break;
return(ROFF_IGN);
}
+int
+roff_regisset(const struct roff *r, enum regs reg)
+{
+
+ return(r->regs[(int)reg].set);
+}
+
+unsigned int
+roff_regget(const struct roff *r, enum regs reg)
+{
+
+ return(r->regs[(int)reg].u);
+}
+
+void
+roff_regunset(struct roff *r, enum regs reg)
+{
+
+ r->regs[(int)reg].set = 0;
+}
/* ARGSUSED */
static enum rofferr
const char *key;
char *val;
int iv;
- struct reg *rg;
val = *bufp + pos;
key = roff_getname(r, &val, ln, pos);
- rg = r->regs->regs;
if (0 == strcmp(key, "nS")) {
- rg[(int)REG_nS].set = 1;
- if ((iv = mandoc_strntou(val, strlen(val), 10)) >= 0)
- rg[REG_nS].v.u = (unsigned)iv;
+ r->regs[(int)REG_nS].set = 1;
+ if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0)
+ r->regs[(int)REG_nS].u = (unsigned)iv;
else
- rg[(int)REG_nS].v.u = 0u;
+ r->regs[(int)REG_nS].u = 0u;
}
return(ROFF_IGN);
if (NULL == r->tbl)
mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
else
- tbl_end(r->tbl);
+ tbl_end(&r->tbl);
- r->tbl = NULL;
return(ROFF_IGN);
}
return(ROFF_IGN);
}
-/* ARGSUSED */
-static enum rofferr
-roff_EQ(ROFF_ARGS)
+int
+roff_closeeqn(struct roff *r)
{
- struct eqn_node *e;
+
+ return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0);
+}
+
+void
+roff_openeqn(struct roff *r, const char *name, int line,
+ int offs, const char *buf)
+{
+ struct eqn_node *e;
+ int poff;
assert(NULL == r->eqn);
- e = eqn_alloc(ppos, ln);
+ e = eqn_alloc(name, offs, line, r->parse);
if (r->last_eqn)
r->last_eqn->next = e;
r->first_eqn = r->last_eqn = e;
r->eqn = r->last_eqn = e;
+
+ if (buf) {
+ poff = 0;
+ eqn_read(&r->eqn, line, buf, offs, &poff);
+ }
+}
+
+/* ARGSUSED */
+static enum rofferr
+roff_EQ(ROFF_ARGS)
+{
+
+ roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
return(ROFF_IGN);
}
if (r->tbl) {
mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
- tbl_end(r->tbl);
+ tbl_end(&r->tbl);
}
t = tbl_alloc(ppos, ln, r->parse);
return(r->last_eqn ? &r->last_eqn->eqn : NULL);
}
+
+char
+roff_eqndelim(const struct roff *r)
+{
+
+ return('\0');
+}