summaryrefslogtreecommitdiffstats
path: root/roff.c
diff options
context:
space:
mode:
Diffstat (limited to 'roff.c')
-rw-r--r--roff.c83
1 files changed, 52 insertions, 31 deletions
diff --git a/roff.c b/roff.c
index a33baa2d..56733186 100644
--- a/roff.c
+++ b/roff.c
@@ -97,11 +97,10 @@ struct roffkv {
/*
* A single number register as part of a singly-linked list.
- * Registers are assumed to be unsigned ints for now.
*/
struct roffreg {
struct roffstr key;
- unsigned int u;
+ int val;
struct roffreg *next;
};
@@ -186,6 +185,8 @@ 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 int roff_getregn(const struct roff *,
+ const char *, size_t);
static const char *roff_getstrn(const struct roff *,
const char *, size_t);
static enum rofferr roff_it(ROFF_ARGS);
@@ -480,22 +481,23 @@ roff_alloc(enum mparset type, struct mparse *parse)
}
/*
- * 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.
+ * In the current line, expand user-defined strings ("\*")
+ * and references to number registers ("\n").
+ * Also check the syntax of other escape sequences.
*/
static enum rofferr
roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
{
- enum mandoc_esc esc;
+ char ubuf[12]; /* buffer to print the number */
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 ']' */
const char *res; /* the string to be substituted */
- int i, maxl, expand_count;
- size_t nsz;
- char *n;
+ char *nbuf; /* new buffer to copy bufp to */
+ size_t nsz; /* size of the new buffer */
+ size_t maxl; /* expected length of the escape name */
+ size_t naml; /* actual length of the escape name */
+ int expand_count; /* to avoid infinite loops */
expand_count = 0;
@@ -505,7 +507,7 @@ again:
stesc = cp++;
/*
- * The second character must be an asterisk.
+ * The second character must be an asterisk or an n.
* If it isn't, skip it anyway: It is escaped,
* so it can't start another escape sequence.
*/
@@ -513,12 +515,16 @@ again:
if ('\0' == *cp)
return(ROFF_CONT);
- if ('*' != *cp) {
- res = cp;
- esc = mandoc_escape(&cp, NULL, NULL);
- if (ESCAPE_ERROR != esc)
+ switch (*cp) {
+ case ('*'):
+ res = NULL;
+ break;
+ case ('n'):
+ res = ubuf;
+ break;
+ default:
+ if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
continue;
- cp = res;
mandoc_msg
(MANDOCERR_BADESCAPE, r->parse,
ln, (int)(stesc - *bufp), NULL);
@@ -529,7 +535,7 @@ again:
/*
* The third character decides the length
- * of the name of the string.
+ * of the name of the string or register.
* Save a pointer to the name.
*/
@@ -552,7 +558,7 @@ again:
/* Advance to the end of the name. */
- for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
+ for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
if ('\0' == *cp) {
mandoc_msg
(MANDOCERR_BADESCAPE,
@@ -569,7 +575,11 @@ again:
* undefined, resume searching for escapes.
*/
- res = roff_getstrn(r, stnam, (size_t)i);
+ if (NULL == res)
+ res = roff_getstrn(r, stnam, naml);
+ else
+ snprintf(ubuf, sizeof(ubuf), "%d",
+ roff_getregn(r, stnam, naml));
if (NULL == res) {
mandoc_msg
@@ -583,15 +593,15 @@ again:
pos = stesc - *bufp;
nsz = *szp + strlen(res) + 1;
- n = mandoc_malloc(nsz);
+ nbuf = mandoc_malloc(nsz);
- strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1));
- strlcat(n, res, nsz);
- strlcat(n, cp + (maxl ? 0 : 1), nsz);
+ strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
+ strlcat(nbuf, res, nsz);
+ strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);
free(*bufp);
- *bufp = n;
+ *bufp = nbuf;
*szp = nsz;
if (EXPAND_LIMIT >= ++expand_count)
@@ -1263,7 +1273,7 @@ roff_ds(ROFF_ARGS)
}
void
-roff_setreg(struct roff *r, const char *name, unsigned int val)
+roff_setreg(struct roff *r, const char *name, int val)
{
struct roffreg *reg;
@@ -1282,17 +1292,30 @@ roff_setreg(struct roff *r, const char *name, unsigned int val)
r->regtab = reg;
}
- reg->u = val;
+ reg->val = val;
}
-unsigned int
+int
roff_getreg(const struct roff *r, const char *name)
{
struct roffreg *reg;
for (reg = r->regtab; reg; reg = reg->next)
if (0 == strcmp(name, reg->key.p))
- return(reg->u);
+ return(reg->val);
+
+ return(0);
+}
+
+static int
+roff_getregn(const struct roff *r, const char *name, size_t len)
+{
+ struct roffreg *reg;
+
+ for (reg = r->regtab; reg; reg = reg->next)
+ if (len == reg->key.sz &&
+ 0 == strncmp(name, reg->key.p, len))
+ return(reg->val);
return(0);
}
@@ -1322,10 +1345,8 @@ roff_nr(ROFF_ARGS)
key = roff_getname(r, &val, ln, pos);
iv = mandoc_strntoi(val, strlen(val), 10);
- if (0 > iv)
- iv = 0;
- roff_setreg(r, key, (unsigned)iv);
+ roff_setreg(r, key, iv);
return(ROFF_IGN);
}