*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
struct roffnode *last; /* leaf of stack */
enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
char control; /* control character */
struct roffnode *last; /* leaf of stack */
enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
char control; /* control character */
static enum rofferr roff_block_sub(ROFF_ARGS);
static enum rofferr roff_cblock(ROFF_ARGS);
static enum rofferr roff_cc(ROFF_ARGS);
static enum rofferr roff_block_sub(ROFF_ARGS);
static enum rofferr roff_cblock(ROFF_ARGS);
static enum rofferr roff_cc(ROFF_ARGS);
static enum rofferr roff_cond(ROFF_ARGS);
static enum rofferr roff_cond_text(ROFF_ARGS);
static enum rofferr roff_cond_sub(ROFF_ARGS);
static enum rofferr roff_cond(ROFF_ARGS);
static enum rofferr roff_cond_text(ROFF_ARGS);
static enum rofferr roff_cond_sub(ROFF_ARGS);
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
static char *roff_getname(struct roff *, char **, int, int);
static void roff_freereg(struct roffreg *);
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_it(ROFF_ARGS);
static const char *roff_getstrn(const struct roff *,
const char *, size_t);
static enum rofferr roff_it(ROFF_ARGS);
{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "cc", roff_cc, NULL, NULL, 0, NULL },
{ "cc", roff_cc, NULL, NULL, 0, NULL },
{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "ds", roff_ds, NULL, NULL, 0, NULL },
{ "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "ds", roff_ds, NULL, NULL, 0, NULL },
{ "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
+ { "fam", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hw", roff_line_ignore, NULL, NULL, 0, NULL },
{ "hy", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "hy", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "EQ", roff_EQ, NULL, NULL, 0, NULL },
{ "EN", roff_EN, NULL, NULL, 0, NULL },
{ ".", roff_cblock, NULL, NULL, 0, NULL },
{ "EQ", roff_EQ, NULL, NULL, 0, NULL },
{ "EN", roff_EN, NULL, NULL, 0, NULL },
{ ".", roff_cblock, NULL, NULL, 0, NULL },
{ NULL, roff_userdef, NULL, NULL, 0, NULL },
};
{ NULL, roff_userdef, NULL, NULL, 0, NULL },
};
- if (r->eqn)
- return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
- if (r->tbl)
- return(tbl_read(r->tbl, ln, *bufp, pos));
- return(roff_parsetext(bufp, szp, pos, offs));
- } else if ( ! ctl) {
- if (r->eqn)
- return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
+ }
+ if (r->eqn)
+ return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
+ if ( ! ctl) {
if (r->tbl)
return(tbl_read(r->tbl, ln, *bufp, pos));
return(roff_parsetext(bufp, szp, pos, offs));
if (r->tbl)
return(tbl_read(r->tbl, ln, *bufp, pos));
return(roff_parsetext(bufp, szp, pos, offs));
- /*
- * 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.
- */
+ /* We stop the macro parse at an escape, tab, space, or nil. */
t = (r->current_string = roff_getstrn(r, mac, maclen))
? ROFF_USERDEF : roffhash_find(mac, maclen);
t = (r->current_string = roff_getstrn(r, mac, maclen))
? ROFF_USERDEF : roffhash_find(mac, maclen);
{
if (NULL == r->last) {
mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
{
if (NULL == r->last) {
mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
break;
default:
mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
break;
default:
mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
}
if (r->last->endspan > -1) {
mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
}
if (r->last->endspan > -1) {
mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
/*
* At the beginning of a `de' macro, clear the existing string
* with the same name, if there is one. New content will be
/*
* At the beginning of a `de' macro, clear the existing string
* with the same name, if there is one. New content will be
- roff_setstr(r, r->last->name, *bufp + ppos, 1);
+ roff_setstr(r, r->last->name, *bufp + ppos, 2);
- roff_setstr(r, r->last->name, *bufp + pos, 1);
+ roff_setstr(r, r->last->name, *bufp + pos, 2);
ROFFMAC_STRUCT & roffs[t].flags)) {
assert(roffs[t].proc);
return((*roffs[t].proc)(r, t, bufp, szp,
ROFFMAC_STRUCT & roffs[t].flags)) {
assert(roffs[t].proc);
return((*roffs[t].proc)(r, t, bufp, szp,
- roff_ccond(r, ROFF_ccond, bufp, szp,
- ln, pos, pos + 2, offs);
- break;
+ roff_ccond(r, ln, pos);
- roff_ccond(r, ROFF_ccond, bufp, szp,
- ln, pos, pos + 2, offs);
+ roff_ccond(r, ln, pos);
+static int
+roff_getnum(const char *v, int *pos, int *res)
+{
+ int p, n;
+
+ p = *pos;
+ n = v[p] == '-';
+ if (n)
+ p++;
+
+ for (*res = 0; isdigit((unsigned char)v[p]); p++)
+ *res += 10 * *res + v[p] - '0';
+ if (p == *pos + n)
+ return 0;
+
+ if (n)
+ *res = -*res;
+
+ *pos = p;
+ return 1;
+}
+
+static int
+roff_getop(const char *v, int *pos, char *res)
+{
+ int e;
+
+ *res = v[*pos];
+ e = v[*pos + 1] == '=';
+
+ switch (*res) {
+ case '=':
+ break;
+ case '>':
+ if (e)
+ *res = 'g';
+ break;
+ case '<':
+ if (e)
+ *res = 'l';
+ break;
+ default:
+ return(0);
+ }
+
+ *pos += 1 + e;
+
+ return(*res);
+}
+
- while (v[*pos] && ' ' != v[*pos])
- (*pos)++;
- return(ROFFRULE_DENY);
+ if (!roff_getnum(v, pos, &lh))
+ return ROFFRULE_DENY;
+ if (!roff_getop(v, pos, &op)) {
+ if (lh < 0)
+ lh = 0;
+ goto out;
+ }
+ if (!roff_getnum(v, pos, &rh))
+ return ROFFRULE_DENY;
+ switch (op) {
+ case 'g':
+ lh = lh >= rh;
+ break;
+ case 'l':
+ lh = lh <= rh;
+ break;
+ case '=':
+ lh = lh == rh;
+ break;
+ case '>':
+ lh = lh > rh;
+ break;
+ case '<':
+ lh = lh < rh;
+ break;
+ default:
+ return ROFFRULE_DENY;
+ }
+out:
+ if (not)
+ lh = !lh;
+ return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
- roff_setstr(r, name, string, 0);
+ roff_setstr(r, name, string, ROFF_as == tok);
-roff_setreg(struct roff *r, const char *name, int val)
+roff_setreg(struct roff *r, const char *name, int val, char sign)
reg = mandoc_malloc(sizeof(struct roffreg));
reg->key.p = mandoc_strdup(name);
reg->key.sz = strlen(name);
reg = mandoc_malloc(sizeof(struct roffreg));
reg->key.p = mandoc_strdup(name);
reg->key.sz = strlen(name);
+ if ('+' == sign)
+ reg->val += val;
+ else if ('-' == sign)
+ reg->val -= val;
+ else
+ reg->val = val;
+}
+
+/*
+ * Handle some predefined read-only number registers.
+ * For now, return -1 if the requested register is not predefined;
+ * in case a predefined read-only register having the value -1
+ * were to turn up, another special value would have to be chosen.
+ */
+static int
+roff_getregro(const char *name)
+{
+
+ switch (*name) {
+ case ('A'): /* ASCII approximation mode is always off. */
+ return(0);
+ case ('g'): /* Groff compatibility mode is always on. */
+ return(1);
+ case ('H'): /* Fixed horizontal resolution. */
+ return (24);
+ case ('j'): /* Always adjust left margin only. */
+ return(0);
+ case ('T'): /* Some output device is always defined. */
+ return(1);
+ case ('V'): /* Fixed vertical resolution. */
+ return (40);
+ default:
+ return (-1);
+ }
for (reg = r->regtab; reg; reg = reg->next)
if (0 == strcmp(name, reg->key.p))
for (reg = r->regtab; reg; reg = reg->next)
if (0 == strcmp(name, reg->key.p))
val = *bufp + pos;
key = roff_getname(r, &val, ln, pos);
val = *bufp + pos;
key = roff_getname(r, &val, ln, pos);
- roff_setreg(r, key, iv);
+ sz = strspn(val, "0123456789");
+ iv = sz ? mandoc_strntoi(val, sz, 10) : 0;
+
+ roff_setreg(r, key, iv, sign);
for (cp = __mdoc_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
for (cp = __mdoc_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
for (cp = __man_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
for (cp = __man_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
* To clear an existing entry, call with (*r, *name, NULL, 0).
* To clear an existing entry, call with (*r, *name, NULL, 0).
*/
static void
roff_setstr(struct roff *r, const char *name, const char *string,
*/
static void
roff_setstr(struct roff *r, const char *name, const char *string,
{
roff_setstrn(&r->strtab, name, strlen(name), string,
{
roff_setstrn(&r->strtab, name, strlen(name), string,
}
static void
roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
}
static void
roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
* One additional byte for the '\n' in multiline mode,
* and one for the terminating '\0'.
*/
* One additional byte for the '\n' in multiline mode,
* and one for the terminating '\0'.
*/
for (n = r->strtab; n; n = n->next)
if (0 == strncmp(name, n->key.p, len) &&
'\0' == n->key.p[(int)len])
return(n->val.p);
for (n = r->strtab; n; n = n->next)
if (0 == strncmp(name, n->key.p, len) &&
'\0' == n->key.p[(int)len])
return(n->val.p);
+ for (i = 0; i < PREDEFS_MAX; i++)
+ if (0 == strncmp(name, predefs[i].name, len) &&
+ '\0' == predefs[i].name[(int)len])
+ return(predefs[i].str);
+