-/* $Id: roff.c,v 1.165 2011/07/28 14:53:22 kristaps Exp $ */
+/* $Id: roff.c,v 1.167 2011/07/29 10:16:59 kristaps Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
* Registers are assumed to be unsigned ints for now.
*/
struct reg {
- int set; /* whether set or not */
- unsigned int u; /* unsigned integer */
+ int set; /* whether set or not */
+ unsigned int u; /* unsigned integer */
};
+/*
+ * An incredibly-simple string buffer.
+ */
struct roffstr {
- char *key; /* key of symbol */
- size_t keysz;
- char *val; /* current value */
- size_t valsz;
- struct roffstr *next; /* next in list */
+ char *p; /* nil-terminated buffer */
+ size_t sz; /* saved strlen(p) */
+};
+
+/*
+ * A key-value roffstr pair as part of a singly-linked list.
+ */
+struct roffkv {
+ struct roffstr key;
+ struct roffstr val;
+ struct roffkv *next; /* next in list */
};
struct roff {
enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
int rstackpos; /* position in rstack */
struct reg regs[REG__MAX];
- struct roffstr *strtab; /* user-defined strings & macros */
- struct roffstr *chrtab; /* user-defined characters */
+ struct roffkv *strtab; /* user-defined strings & macros */
+ struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
+ struct roffstr *xtab; /* single-byte trans table (`tr') */
const char *current_string; /* value of last called user macro */
struct tbl_node *first_tbl; /* first table parsed */
struct tbl_node *last_tbl; /* last table parsed */
static enum rofferr roff_ds(ROFF_ARGS);
static enum roffrule roff_evalcond(const char *, int *);
static void roff_free1(struct roff *);
-static void roff_freestr(struct roffstr **);
+static void roff_freestr(struct roffkv *);
static char *roff_getname(struct roff *, char **, int, int);
static const char *roff_getstrn(const struct roff *,
const char *, size_t);
static enum rofferr roff_rm(ROFF_ARGS);
static void roff_setstr(struct roff *,
const char *, const char *, int);
-static void roff_setstrn(struct roffstr **, const char *,
+static void roff_setstrn(struct roffkv **, const char *,
size_t, const char *, size_t, int);
static enum rofferr roff_so(ROFF_ARGS);
static enum rofferr roff_tr(ROFF_ARGS);
{
struct tbl_node *t;
struct eqn_node *e;
+ int i;
while (NULL != (t = r->first_tbl)) {
r->first_tbl = t->next;
while (r->last)
roffnode_pop(r);
- roff_freestr(&r->strtab);
- roff_freestr(&r->chrtab);
-}
+ 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;
+}
void
roff_reset(struct roff *r)
p--;
}
- roff_setstrn(&r->chrtab, first, fsz, second, ssz, 0);
+ if (fsz > 1) {
+ roff_setstrn(&r->xmbtab, first,
+ fsz, second, ssz, 0);
+ continue;
+ }
+
+ if (NULL == r->xtab)
+ r->xtab = mandoc_calloc
+ (128, sizeof(struct roffstr));
+
+ free(r->xtab[(int)*first].p);
+ r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
+ r->xtab[(int)*first].sz = ssz;
}
return(ROFF_IGN);
}
static void
-roff_setstrn(struct roffstr **r, const char *name, size_t namesz,
+roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
const char *string, size_t stringsz, int multiline)
{
- struct roffstr *n;
+ struct roffkv *n;
char *c;
int i;
size_t oldch, newch;
/* Search for an existing string with the same name. */
n = *r;
- while (n && strcmp(name, n->key))
+ while (n && strcmp(name, n->key.p))
n = n->next;
if (NULL == n) {
/* Create a new string table entry. */
- n = mandoc_malloc(sizeof(struct roffstr));
- n->key = mandoc_strndup(name, namesz);
- n->keysz = namesz;
- n->val = NULL;
- n->valsz = 0;
+ n = mandoc_malloc(sizeof(struct roffkv));
+ n->key.p = mandoc_strndup(name, namesz);
+ n->key.sz = namesz;
+ n->val.p = NULL;
+ n->val.sz = 0;
n->next = *r;
*r = n;
} else if (0 == multiline) {
/* In multiline mode, append; else replace. */
- free(n->val);
- n->val = NULL;
- n->valsz = 0;
+ free(n->val.p);
+ n->val.p = NULL;
+ n->val.sz = 0;
}
if (NULL == string)
*/
newch = stringsz + (multiline ? 2u : 1u);
- if (NULL == n->val) {
- n->val = mandoc_malloc(newch);
- *n->val = '\0';
+ if (NULL == n->val.p) {
+ n->val.p = mandoc_malloc(newch);
+ *n->val.p = '\0';
oldch = 0;
} else {
- oldch = n->valsz;
- n->val = mandoc_realloc(n->val, oldch + newch);
+ oldch = n->val.sz;
+ n->val.p = mandoc_realloc(n->val.p, oldch + newch);
}
/* Skip existing content in the destination buffer. */
- c = n->val + (int)oldch;
+ c = n->val.p + (int)oldch;
/* Append new content to the destination buffer. */
i = 0;
*c++ = '\n';
*c = '\0';
- n->valsz = (int)(c - n->val);
+ n->val.sz = (int)(c - n->val.p);
}
static const char *
roff_getstrn(const struct roff *r, const char *name, size_t len)
{
- const struct roffstr *n;
+ const struct roffkv *n;
for (n = r->strtab; n; n = n->next)
- if (0 == strncmp(name, n->key, len) &&
- '\0' == n->key[(int)len])
- return(n->val);
+ if (0 == strncmp(name, n->key.p, len) &&
+ '\0' == n->key.p[(int)len])
+ return(n->val.p);
return(NULL);
}
static void
-roff_freestr(struct roffstr **r)
+roff_freestr(struct roffkv *r)
{
- struct roffstr *n, *nn;
+ struct roffkv *n, *nn;
- for (n = *r; n; n = nn) {
- free(n->key);
- free(n->val);
+ for (n = r; n; n = nn) {
+ free(n->key.p);
+ free(n->val.p);
nn = n->next;
free(n);
}
-
- *r = NULL;
}
const struct tbl_span *
char *
roff_strdup(const struct roff *r, const char *p)
{
- const struct roffstr *cp;
+ const struct roffkv *cp;
char *res;
const char *pp;
size_t ssz, sz;
enum mandoc_esc esc;
- if (NULL == r->chrtab)
+ if (NULL == r->xmbtab && NULL == r->xtab)
return(mandoc_strdup(p));
else if ('\0' == *p)
return(mandoc_strdup(""));
ssz = 0;
while ('\0' != *p) {
+ if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) {
+ sz = r->xtab[(int)*p].sz;
+ res = mandoc_realloc(res, ssz + sz + 1);
+ memcpy(res + ssz, r->xtab[(int)*p].p, sz);
+ ssz += sz;
+ p++;
+ continue;
+ } else if ('\\' != *p) {
+ res = mandoc_realloc(res, ssz + 2);
+ res[ssz++] = *p++;
+ continue;
+ }
+
/* Search for term matches. */
- for (cp = r->chrtab; cp; cp = cp->next)
- if (0 == strncmp(p, cp->key, cp->keysz))
+ for (cp = r->xmbtab; cp; cp = cp->next)
+ if (0 == strncmp(p, cp->key.p, cp->key.sz))
break;
if (NULL != cp) {
* Append the match to the array and move
* forward by its keysize.
*/
- res = mandoc_realloc(res, ssz + cp->valsz + 1);
- memcpy(res + ssz, cp->val, cp->valsz);
- ssz += cp->valsz;
- p += (int)cp->keysz;
+ res = mandoc_realloc
+ (res, ssz + cp->val.sz + 1);
+ memcpy(res + ssz, cp->val.p, cp->val.sz);
+ ssz += cp->val.sz;
+ p += (int)cp->key.sz;
continue;
}
- if ('\\' == *p) {
- /*
- * Handle escapes carefully: we need to copy
- * over just the escape itself, or else we might
- * do replacements within the escape itself.
- * Make sure to pass along the bogus string.
- */
- pp = p++;
- esc = mandoc_escape(&p, NULL, NULL);
- if (ESCAPE_ERROR == esc) {
- sz = strlen(pp);
- res = mandoc_realloc(res, ssz + sz + 1);
- memcpy(res + ssz, pp, sz);
- break;
- }
- /*
- * We bail out on bad escapes.
- * No need to warn: we already did so when
- * roff_res() was called.
- */
- sz = (int)(p - pp);
+ /*
+ * Handle escapes carefully: we need to copy
+ * over just the escape itself, or else we might
+ * do replacements within the escape itself.
+ * Make sure to pass along the bogus string.
+ */
+ pp = p++;
+ esc = mandoc_escape(&p, NULL, NULL);
+ if (ESCAPE_ERROR == esc) {
+ sz = strlen(pp);
res = mandoc_realloc(res, ssz + sz + 1);
memcpy(res + ssz, pp, sz);
- ssz += sz;
- continue;
+ break;
}
-
- /* Just append the charater. */
- res = mandoc_realloc(res, ssz + 2);
- res[ssz++] = *p++;
+ /*
+ * We bail out on bad escapes.
+ * No need to warn: we already did so when
+ * roff_res() was called.
+ */
+ sz = (int)(p - pp);
+ res = mandoc_realloc(res, ssz + sz + 1);
+ memcpy(res + ssz, pp, sz);
+ ssz += sz;
}
res[(int)ssz] = '\0';