-/* $Id: roff.c,v 1.208 2014/04/20 19:40:13 schwarze Exp $ */
+/* $Id: roff.c,v 1.227 2014/09/06 22:39:36 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include "mandoc.h"
#include "mandoc_aux.h"
-#include "libroff.h"
#include "libmandoc.h"
+#include "libroff.h"
/* Maximum number of nested if-else conditionals. */
#define RSTACK_MAX 128
struct roff {
struct mparse *parse; /* parse point */
- int options; /* parse options */
struct roffnode *last; /* leaf of stack */
- int rstack[RSTACK_MAX]; /* stack of !`ie' rules */
- char control; /* control character */
- int rstackpos; /* position in rstack */
+ int *rstack; /* stack of inverted `ie' values */
struct roffreg *regtab; /* number registers */
struct roffkv *strtab; /* user-defined strings & macros */
struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
struct eqn_node *last_eqn; /* last equation parsed */
struct eqn_node *first_eqn; /* first equation parsed */
struct eqn_node *eqn; /* current equation being parsed */
+ int options; /* parse options */
+ int rstacksz; /* current size limit of rstack */
+ int rstackpos; /* position in rstack */
+ int format; /* current file in mdoc or man format */
+ char control; /* control character */
};
struct roffnode {
static void roff_free1(struct roff *);
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
-static char *roff_getname(struct roff *, char **, int, int);
+static size_t roff_getname(struct roff *, char **, int, int);
static int roff_getnum(const char *, int *, int *);
static int roff_getop(const char *, int *, char *);
static int roff_getregn(const struct roff *,
static enum rofferr roff_nr(ROFF_ARGS);
static void roff_openeqn(struct roff *, const char *,
int, int, const char *);
-static enum rofft roff_parse(struct roff *, const char *, int *);
+static enum rofft roff_parse(struct roff *, char *, int *,
+ int, int);
static enum rofferr roff_parsetext(char **, size_t *, int, int *);
static enum rofferr roff_res(struct roff *,
char **, size_t *, int, int);
r->first_tbl = tbl->next;
tbl_free(tbl);
}
-
r->first_tbl = r->last_tbl = r->tbl = NULL;
while (NULL != (e = r->first_eqn)) {
r->first_eqn = e->next;
eqn_free(e);
}
-
r->first_eqn = r->last_eqn = r->eqn = NULL;
while (r->last)
roffnode_pop(r);
- roff_freestr(r->strtab);
- roff_freestr(r->xmbtab);
-
- r->strtab = r->xmbtab = NULL;
+ free (r->rstack);
+ r->rstack = NULL;
+ r->rstacksz = 0;
+ r->rstackpos = -1;
roff_freereg(r->regtab);
-
r->regtab = NULL;
+ roff_freestr(r->strtab);
+ roff_freestr(r->xmbtab);
+ r->strtab = r->xmbtab = NULL;
+
if (r->xtab)
for (i = 0; i < 128; i++)
free(r->xtab[i].p);
-
free(r->xtab);
r->xtab = NULL;
}
{
roff_free1(r);
+ r->format = r->options & (MPARSE_MDOC | MPARSE_MAN);
r->control = 0;
}
r = mandoc_calloc(1, sizeof(struct roff));
r->parse = parse;
r->options = options;
+ r->format = options & (MPARSE_MDOC | MPARSE_MAN);
r->rstackpos = -1;
roffhash_init();
{
char ubuf[24]; /* buffer to print the number */
const char *start; /* start of the string to process */
- const char *stesc; /* start of an escape sequence ('\\') */
+ 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 ']' */
const char *res; /* the string to be substituted */
char *nbuf; /* new buffer to copy bufp to */
size_t maxl; /* expected length of the escape name */
size_t naml; /* actual length of the escape name */
- size_t ressz; /* size of the replacement string */
int expand_count; /* to avoid infinite loops */
int npos; /* position in numeric expression */
- int irc; /* return code from roff_evalnum() */
+ int arg_complete; /* argument not interrupted by eol */
char term; /* character terminating the escape */
expand_count = 0;
break;
if (0 == (stesc - cp) % 2) {
- stesc = cp;
+ stesc = (char *)cp;
continue;
}
break;
default:
if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL))
- mandoc_msg(MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(stesc - *bufp), NULL);
+ mandoc_vmsg(MANDOCERR_ESC_BAD,
+ r->parse, ln, (int)(stesc - *bufp),
+ "%.*s", (int)(cp - stesc), stesc);
continue;
}
/* Advance to the end of the name. */
+ arg_complete = 1;
for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
if ('\0' == *cp) {
- mandoc_msg(MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(stesc - *bufp), NULL);
+ mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+ ln, (int)(stesc - *bufp), stesc);
+ arg_complete = 0;
break;
}
if (0 == maxl && *cp == term) {
switch (stesc[1]) {
case '*':
- res = roff_getstrn(r, stnam, naml);
+ if (arg_complete)
+ res = roff_getstrn(r, stnam, naml);
break;
case 'B':
npos = 0;
- irc = roff_evalnum(stnam, &npos, NULL, 0);
- ubuf[0] = irc && stnam + npos + 1 == cp
- ? '1' : '0';
+ ubuf[0] = arg_complete &&
+ roff_evalnum(stnam, &npos, NULL, 0) &&
+ stnam + npos + 1 == cp ? '1' : '0';
ubuf[1] = '\0';
break;
case 'n':
- (void)snprintf(ubuf, sizeof(ubuf), "%d",
- roff_getregn(r, stnam, naml));
+ if (arg_complete)
+ (void)snprintf(ubuf, sizeof(ubuf), "%d",
+ roff_getregn(r, stnam, naml));
+ else
+ ubuf[0] = '\0';
break;
case 'w':
+ /* use even incomplete args */
(void)snprintf(ubuf, sizeof(ubuf), "%d",
24 * (int)naml);
break;
}
if (NULL == res) {
- mandoc_msg(MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(stesc - *bufp), NULL);
+ mandoc_vmsg(MANDOCERR_STR_UNDEF,
+ r->parse, ln, (int)(stesc - *bufp),
+ "%.*s", (int)naml, stnam);
res = "";
}
- ressz = strlen(res);
/* Replace the escape sequence by the string. */
- *szp += ressz + 1;
- nbuf = mandoc_malloc(*szp);
-
- strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
- strlcat(nbuf, res, *szp);
- strlcat(nbuf, cp, *szp);
+ *stesc = '\0';
+ *szp = mandoc_asprintf(&nbuf, "%s%s%s",
+ *bufp, res, cp) + 1;
/* Prepare for the next replacement. */
start = nbuf + pos;
- stesc = nbuf + (stesc - *bufp) + ressz;
+ stesc = nbuf + (stesc - *bufp) + strlen(res);
free(*bufp);
*bufp = nbuf;
}
* the compilers handle it.
*/
- if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos)))
+ if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos, ln, ppos)))
return(ROFF_CONT);
assert(roffs[t].proc);
{
if (r->last)
- mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->last->line, r->last->col, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ r->last->line, r->last->col,
+ roffs[r->last->tok].name);
if (r->eqn) {
- mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->eqn->eqn.ln, r->eqn->eqn.pos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ r->eqn->eqn.ln, r->eqn->eqn.pos, "EQ");
eqn_end(&r->eqn);
}
if (r->tbl) {
- mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->tbl->line, r->tbl->pos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ r->tbl->line, r->tbl->pos, "TS");
tbl_end(&r->tbl);
}
}
* form of ".foo xxx" in the usual way.
*/
static enum rofft
-roff_parse(struct roff *r, const char *buf, int *pos)
+roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
{
+ char *cp;
const char *mac;
size_t maclen;
enum rofft t;
- if ('\0' == buf[*pos] || '"' == buf[*pos] ||
- '\t' == buf[*pos] || ' ' == buf[*pos])
- return(ROFF_MAX);
+ cp = buf + *pos;
- /* We stop the macro parse at an escape, tab, space, or nil. */
+ if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp)
+ return(ROFF_MAX);
- mac = buf + *pos;
- maclen = strcspn(mac, " \\\t\0");
+ mac = cp;
+ maclen = roff_getname(r, &cp, ln, ppos);
t = (r->current_string = roff_getstrn(r, mac, maclen))
? ROFF_USERDEF : roffhash_find(mac, maclen);
- *pos += (int)maclen;
-
- while (buf[*pos] && ' ' == buf[*pos])
- (*pos)++;
+ if (ROFF_MAX != t)
+ *pos = cp - buf;
return(t);
}
*/
if (NULL == r->last) {
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "..");
return(ROFF_IGN);
}
switch (r->last->tok) {
case ROFF_am:
+ /* ROFF_am1 is remapped to ROFF_am in roff_block(). */
/* FALLTHROUGH */
case ROFF_ami:
/* FALLTHROUGH */
- case ROFF_am1:
- /* FALLTHROUGH */
case ROFF_de:
/* ROFF_de1 is remapped to ROFF_de in roff_block(). */
/* FALLTHROUGH */
case ROFF_ig:
break;
default:
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "..");
return(ROFF_IGN);
}
if ((*bufp)[pos])
- mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
+ mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
+ ".. %s", *bufp + pos);
roffnode_pop(r);
roffnode_cleanscope(r);
{
if (NULL == r->last) {
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "\\}");
return;
}
case ROFF_if:
break;
default:
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "\\}");
return;
}
if (r->last->endspan > -1) {
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "\\}");
return;
}
static enum rofferr
roff_block(ROFF_ARGS)
{
- int sv;
- size_t sz;
- char *name;
+ const char *name;
+ char *iname, *cp;
+ size_t namesz;
- name = NULL;
+ /* Ignore groff compatibility mode for now. */
- if (ROFF_ig != tok) {
- if ('\0' == (*bufp)[pos]) {
- mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
- return(ROFF_IGN);
- }
+ if (ROFF_de1 == tok)
+ tok = ROFF_de;
+ else if (ROFF_am1 == tok)
+ tok = ROFF_am;
- /*
- * Re-write `de1', since we don't really care about
- * groff's strange compatibility mode, into `de'.
- */
+ /* Parse the macro name argument. */
- if (ROFF_de1 == tok)
- tok = ROFF_de;
- if (ROFF_de == tok)
- name = *bufp + pos;
- else
- mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
- roffs[tok].name);
+ cp = *bufp + pos;
+ if (ROFF_ig == tok) {
+ iname = NULL;
+ namesz = 0;
+ } else {
+ iname = cp;
+ namesz = roff_getname(r, &cp, ln, ppos);
+ iname[namesz] = '\0';
+ }
- while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
- pos++;
+ /* Resolve the macro name argument if it is indirect. */
- while (isspace((unsigned char)(*bufp)[pos]))
- (*bufp)[pos++] = '\0';
+ if (namesz && (ROFF_dei == tok || ROFF_ami == tok)) {
+ if (NULL == (name = roff_getstrn(r, iname, namesz))) {
+ mandoc_vmsg(MANDOCERR_STR_UNDEF,
+ r->parse, ln, (int)(iname - *bufp),
+ "%.*s", (int)namesz, iname);
+ namesz = 0;
+ } else
+ namesz = strlen(name);
+ } else
+ name = iname;
+
+ if (0 == namesz && ROFF_ig != tok) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse,
+ ln, ppos, roffs[tok].name);
+ return(ROFF_IGN);
}
roffnode_push(r, tok, name, ln, ppos);
* appended from roff_block_text() in multiline mode.
*/
- if (ROFF_de == tok)
- roff_setstr(r, name, "", 0);
+ if (ROFF_de == tok || ROFF_dei == tok)
+ roff_setstrn(&r->strtab, name, namesz, "", 0, 0);
- if ('\0' == (*bufp)[pos])
+ if ('\0' == *cp)
return(ROFF_IGN);
- /* If present, process the custom end-of-line marker. */
-
- sv = pos;
- while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
- pos++;
-
- /*
- * Note: groff does NOT like escape characters in the input.
- * Instead of detecting this, we're just going to let it fly and
- * to hell with it.
- */
+ /* Get the custom end marker. */
- assert(pos > sv);
- sz = (size_t)(pos - sv);
+ iname = cp;
+ namesz = roff_getname(r, &cp, ln, ppos);
- if (1 == sz && '.' == (*bufp)[sv])
- return(ROFF_IGN);
+ /* Resolve the end marker if it is indirect. */
- r->last->end = mandoc_malloc(sz + 1);
+ if (namesz && (ROFF_dei == tok || ROFF_ami == tok)) {
+ if (NULL == (name = roff_getstrn(r, iname, namesz))) {
+ mandoc_vmsg(MANDOCERR_STR_UNDEF,
+ r->parse, ln, (int)(iname - *bufp),
+ "%.*s", (int)namesz, iname);
+ namesz = 0;
+ } else
+ namesz = strlen(name);
+ } else
+ name = iname;
- memcpy(r->last->end, *bufp + sv, sz);
- r->last->end[(int)sz] = '\0';
+ if (namesz)
+ r->last->end = mandoc_strndup(name, namesz);
- if ((*bufp)[pos])
- mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
+ if ('\0' != *cp)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
+ ln, pos, ".%s ... %s", roffs[tok].name, cp);
return(ROFF_IGN);
}
i++;
pos = i;
- if (ROFF_MAX != roff_parse(r, *bufp, &pos))
+ if (ROFF_MAX != roff_parse(r, *bufp, &pos, ln, ppos))
return(ROFF_RERUN);
return(ROFF_IGN);
}
* pulling it out of the hashtable.
*/
- t = roff_parse(r, *bufp, &pos);
+ t = roff_parse(r, *bufp, &pos, ln, ppos);
- /*
- * Macros other than block-end are only significant
- * in `de' blocks; elsewhere, simply throw them away.
- */
if (ROFF_cblock != t) {
- if (ROFF_de == tok)
+ if (ROFF_ig != tok)
roff_setstr(r, r->last->name, *bufp + ppos, 2);
return(ROFF_IGN);
}
roff_block_text(ROFF_ARGS)
{
- if (ROFF_de == tok)
+ if (ROFF_ig != tok)
roff_setstr(r, r->last->name, *bufp + pos, 2);
return(ROFF_IGN);
rr = r->last->rule;
roffnode_cleanscope(r);
- t = roff_parse(r, *bufp, &pos);
+ t = roff_parse(r, *bufp, &pos, ln, ppos);
/*
* Fully handle known macros when they are structurally
*/
if (ROFF_ie == tok) {
- if (r->rstackpos == RSTACK_MAX - 1) {
- mandoc_msg(MANDOCERR_MEM,
- r->parse, ln, ppos, NULL);
- return(ROFF_ERR);
+ if (r->rstackpos + 1 == r->rstacksz) {
+ r->rstacksz += 16;
+ r->rstack = mandoc_reallocarray(r->rstack,
+ r->rstacksz, sizeof(int));
}
r->rstack[++r->rstackpos] = !r->last->rule;
}
*/
if ('\0' == (*bufp)[pos])
- mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_COND_EMPTY, r->parse,
+ ln, ppos, roffs[tok].name);
r->last->endspan = 1;
static enum rofferr
roff_ds(ROFF_ARGS)
{
- char *name, *string;
+ char *string;
+ const char *name;
+ size_t namesz;
/*
- * A symbol is named by the first word following the macro
- * invocation up to a space. Its value is anything after the
- * name's trailing whitespace and optional double-quote. Thus,
- *
- * [.ds foo "bar " ]
- *
- * will have `bar " ' as its value.
+ * The first word is the name of the string.
+ * If it is empty or terminated by an escape sequence,
+ * abort the `ds' request without defining anything.
*/
- string = *bufp + pos;
- name = roff_getname(r, &string, ln, pos);
+ name = string = *bufp + pos;
if ('\0' == *name)
return(ROFF_IGN);
- /* Read past initial double-quote. */
+ namesz = roff_getname(r, &string, ln, pos);
+ if ('\\' == name[namesz])
+ return(ROFF_IGN);
+
+ /* Read past the initial double-quote, if any. */
if ('"' == *string)
string++;
/* The rest is the value. */
- roff_setstr(r, name, string, ROFF_as == tok);
+ roff_setstrn(&r->strtab, name, namesz, string, strlen(string),
+ ROFF_as == tok);
return(ROFF_IGN);
}
static enum rofferr
roff_nr(ROFF_ARGS)
{
- const char *key;
- char *val;
+ char *key, *val;
+ size_t keysz;
int iv;
char sign;
- val = *bufp + pos;
- key = roff_getname(r, &val, ln, pos);
+ key = val = *bufp + pos;
+ if ('\0' == *key)
+ return(ROFF_IGN);
+
+ keysz = roff_getname(r, &val, ln, pos);
+ if ('\\' == key[keysz])
+ return(ROFF_IGN);
+ key[keysz] = '\0';
sign = *val;
if ('+' == sign || '-' == sign)
roff_rr(ROFF_ARGS)
{
struct roffreg *reg, **prev;
- const char *name;
- char *cp;
+ char *name, *cp;
+ size_t namesz;
- cp = *bufp + pos;
- name = roff_getname(r, &cp, ln, pos);
+ name = cp = *bufp + pos;
+ if ('\0' == *name)
+ return(ROFF_IGN);
+ namesz = roff_getname(r, &cp, ln, pos);
+ name[namesz] = '\0';
prev = &r->regtab;
while (1) {
{
const char *name;
char *cp;
+ size_t namesz;
cp = *bufp + pos;
while ('\0' != *cp) {
- name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
- if ('\0' != *name)
- roff_setstr(r, name, NULL, 0);
+ name = cp;
+ namesz = roff_getname(r, &cp, ln, (int)(cp - *bufp));
+ roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0);
+ if ('\\' == name[namesz])
+ break;
}
return(ROFF_IGN);
}
len = strcspn(cp, " \t");
cp[len] = '\0';
if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
- mandoc_msg(MANDOCERR_NUMERIC, r->parse,
+ mandoc_msg(MANDOCERR_IT_NONUM, r->parse,
ln, ppos, *bufp + 1);
return(ROFF_IGN);
}
{
const char *const *cp;
- if (0 == ((MPARSE_MDOC | MPARSE_QUICK) & r->options))
+ if ((r->options & (MPARSE_MDOC | MPARSE_QUICK)) == 0)
for (cp = __mdoc_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
+ if (r->format == 0)
+ r->format = MPARSE_MDOC;
+
return(ROFF_CONT);
}
{
const char *const *cp;
- if (0 == (MPARSE_QUICK & r->options))
+ if ((r->options & MPARSE_QUICK) == 0)
for (cp = __man_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
+ if (r->format == 0)
+ r->format = MPARSE_MAN;
+
return(ROFF_CONT);
}
{
if (NULL == r->tbl)
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "TE");
else
tbl_end(&r->tbl);
{
if (NULL == r->tbl)
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "T&");
else
tbl_restart(ppos, ln, r->tbl);
roff_EN(ROFF_ARGS)
{
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN");
return(ROFF_IGN);
}
struct tbl_node *tbl;
if (r->tbl) {
- mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse,
+ ln, ppos, "TS breaks TS");
tbl_end(&r->tbl);
}
if ('\\' == *first) {
esc = mandoc_escape(&p, NULL, NULL);
if (ESCAPE_ERROR == esc) {
- mandoc_msg(MANDOCERR_BADESCAPE,
- r->parse, ln,
- (int)(p - *bufp), NULL);
+ mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+ ln, (int)(p - *bufp), first);
return(ROFF_IGN);
}
fsz = (size_t)(p - first);
if ('\\' == *second) {
esc = mandoc_escape(&p, NULL, NULL);
if (ESCAPE_ERROR == esc) {
- mandoc_msg(MANDOCERR_BADESCAPE,
- r->parse, ln,
- (int)(p - *bufp), NULL);
+ mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+ ln, (int)(p - *bufp), second);
return(ROFF_IGN);
}
ssz = (size_t)(p - second);
{
char *name;
- mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL);
+ name = *bufp + pos;
+ mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name);
/*
* Handle `so'. Be EXTREMELY careful, as we shouldn't be
* or using absolute paths.
*/
- name = *bufp + pos;
if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
- mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
+ mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos,
+ ".so %s", name);
return(ROFF_ERR);
}
cp += 2;
continue;
}
-
- *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
- n2 = mandoc_malloc(*szp);
-
- strlcpy(n2, n1, (size_t)(cp - n1 + 1));
- strlcat(n2, arg[i], *szp);
- strlcat(n2, cp + 3, *szp);
-
+ *cp = '\0';
+ *szp = mandoc_asprintf(&n2, "%s%s%s",
+ n1, arg[i], cp + 3) + 1;
cp = n2 + (cp - n1);
free(n1);
n1 = n2;
ROFF_REPARSE : ROFF_APPEND);
}
-static char *
+static size_t
roff_getname(struct roff *r, char **cpp, int ln, int pos)
{
char *name, *cp;
+ size_t namesz;
name = *cpp;
if ('\0' == *name)
- return(name);
+ return(0);
- /* Read until end of name. */
- for (cp = name; '\0' != *cp && ' ' != *cp; cp++) {
+ /* Read until end of name and terminate it with NUL. */
+ for (cp = name; 1; cp++) {
+ if ('\0' == *cp || ' ' == *cp) {
+ namesz = cp - name;
+ break;
+ }
if ('\\' != *cp)
continue;
+ namesz = cp - name;
+ if ('{' == cp[1] || '}' == cp[1])
+ break;
cp++;
if ('\\' == *cp)
continue;
- mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL);
- *cp = '\0';
- name = cp;
+ mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos,
+ "%.*s", (int)(cp - name + 1), name);
+ mandoc_escape((const char **)&cp, NULL, NULL);
+ break;
}
- /* Nil-terminate name. */
- if ('\0' != *cp)
- *(cp++) = '\0';
-
/* Read past spaces. */
while (' ' == *cp)
cp++;
*cpp = cp;
- return(name);
+ return(namesz);
}
/*
/* Search for an existing string with the same name. */
n = *r;
- while (n && strcmp(name, n->key.p))
+ while (n && (namesz != n->key.sz ||
+ strncmp(n->key.p, name, namesz)))
n = n->next;
if (NULL == n) {
return(res);
}
+int
+roff_getformat(const struct roff *r)
+{
+
+ return(r->format);
+}
+
/*
* Find out whether a line is a macro line or not.
* If it is, adjust the current position and return one; if it isn't,