=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.88 retrieving revision 1.91 diff -u -p -r1.88 -r1.91 --- mandoc/roff.c 2010/06/10 21:42:02 1.88 +++ mandoc/roff.c 2010/06/27 16:36:22 1.91 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.88 2010/06/10 21:42:02 kristaps Exp $ */ +/* $Id: roff.c,v 1.91 2010/06/27 16:36:22 kristaps Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons * @@ -19,12 +19,15 @@ #endif #include +#include #include +#include #include #include #include #include "mandoc.h" +#include "regs.h" #include "roff.h" #define RSTACK_MAX 128 @@ -56,6 +59,7 @@ enum rofft { ROFF_tr, ROFF_cblock, ROFF_ccond, + ROFF_nr, ROFF_MAX }; @@ -70,6 +74,7 @@ struct roff { void *data; /* privdata for messages */ enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ int rstackpos; /* position in rstack */ + struct regset *regs; /* read/writable registers */ }; struct roffnode { @@ -111,8 +116,9 @@ static enum rofferr roff_ccond(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 roffrule roff_evalcond(const char *, int *); static enum rofferr roff_line(ROFF_ARGS); +static enum rofferr roff_nr(ROFF_ARGS); +static enum roffrule roff_evalcond(const char *, int *); /* See roff_hash_find() */ @@ -138,6 +144,7 @@ static struct roffmac roffs[ROFF_MAX] = { { "tr", roff_line, NULL, NULL, 0, NULL }, { ".", roff_cblock, NULL, NULL, 0, NULL }, { "\\}", roff_ccond, NULL, NULL, 0, NULL }, + { "nr", roff_nr, NULL, NULL, 0, NULL }, }; static void roff_free1(struct roff *); @@ -148,6 +155,7 @@ static int roffnode_push(struct roff *, enum rofft, int, int); static void roffnode_pop(struct roff *); static enum rofft roff_parse(const char *, int *); +static int roff_parse_nat(const char *, unsigned int *); /* See roff_hash_find() */ #define ROFF_HASH(p) (p[0] - ASCII_LO) @@ -281,7 +289,7 @@ roff_free(struct roff *r) struct roff * -roff_alloc(const mandocmsg msg, void *data) +roff_alloc(struct regset *regs, const mandocmsg msg, void *data) { struct roff *r; @@ -290,6 +298,7 @@ roff_alloc(const mandocmsg msg, void *data) return(0); } + r->regs = regs; r->msg = msg; r->data = data; r->rstackpos = -1; @@ -300,8 +309,8 @@ roff_alloc(const mandocmsg msg, void *data) enum rofferr -roff_parseln(struct roff *r, int ln, - char **bufp, size_t *szp, int pos, int *offs) +roff_parseln(struct roff *r, int ln, char **bufp, + size_t *szp, int pos, int *offs) { enum rofft t; int ppos; @@ -318,7 +327,8 @@ roff_parseln(struct roff *r, int ln, ROFF_DEBUG("roff: intercept scoped text: %s, [%s]\n", roffs[t].name, &(*bufp)[pos]); return((*roffs[t].text) - (r, t, bufp, szp, ln, pos, pos, offs)); + (r, t, bufp, szp, + ln, pos, pos, offs)); } else if ( ! ROFF_CTL((*bufp)[pos])) { ROFF_DEBUG("roff: pass non-scoped text: [%s]\n", &(*bufp)[pos]); @@ -336,7 +346,8 @@ roff_parseln(struct roff *r, int ln, ROFF_DEBUG("roff: intercept scoped context: %s\n", roffs[t].name); return((*roffs[t].sub) - (r, t, bufp, szp, ln, pos, pos, offs)); + (r, t, bufp, szp, + ln, pos, pos, offs)); } /* @@ -356,7 +367,8 @@ roff_parseln(struct roff *r, int ln, roffs[t].name, &(*bufp)[pos]); assert(roffs[t].proc); return((*roffs[t].proc) - (r, t, bufp, szp, ln, ppos, pos, offs)); + (r, t, bufp, szp, + ln, ppos, pos, offs)); } @@ -412,6 +424,26 @@ roff_parse(const char *buf, int *pos) } +static int +roff_parse_nat(const char *buf, unsigned int *res) +{ + char *ep; + long lval; + + errno = 0; + lval = strtol(buf, &ep, 10); + if (buf[0] == '\0' || *ep != '\0') + return(0); + if ((errno == ERANGE && + (lval == LONG_MAX || lval == LONG_MIN)) || + (lval > INT_MAX || lval < 0)) + return(0); + + *res = (unsigned int)lval; + return(1); +} + + /* ARGSUSED */ static enum rofferr roff_cblock(ROFF_ARGS) @@ -622,8 +654,8 @@ roff_block_sub(ROFF_ARGS) return(ROFF_IGN); assert(roffs[t].proc); - return((*roffs[t].proc)(r, t, bufp, - szp, ln, ppos, pos, offs)); + return((*roffs[t].proc)(r, t, bufp, szp, + ln, ppos, pos, offs)); } @@ -672,8 +704,8 @@ roff_cond_sub(ROFF_ARGS) return(ROFF_IGN); assert(roffs[t].proc); - return((*roffs[t].proc) - (r, t, bufp, szp, ln, ppos, pos, offs)); + return((*roffs[t].proc)(r, t, bufp, szp, + ln, ppos, pos, offs)); } @@ -732,6 +764,15 @@ roff_evalcond(const char *v, int *pos) /* ARGSUSED */ static enum rofferr +roff_line(ROFF_ARGS) +{ + + return(ROFF_IGN); +} + + +/* ARGSUSED */ +static enum rofferr roff_cond(ROFF_ARGS) { int sv; @@ -838,8 +879,42 @@ roff_cond(ROFF_ARGS) /* ARGSUSED */ static enum rofferr -roff_line(ROFF_ARGS) +roff_nr(ROFF_ARGS) { + const char *key, *val; + struct reg *rg; + + key = &(*bufp)[pos]; + rg = r->regs->regs; + + /* Parse register request. */ + while ((*bufp)[pos] && ' ' != (*bufp)[pos]) + pos++; + + /* + * Set our nil terminator. Because this line is going to be + * ignored anyway, we can munge it as we please. + */ + if ((*bufp)[pos]) + (*bufp)[pos++] = '\0'; + + /* Skip whitespace to register token. */ + while ((*bufp)[pos] && ' ' == (*bufp)[pos]) + pos++; + + val = &(*bufp)[pos]; + + /* Process register token. */ + + if (0 == strcmp(key, "nS")) { + rg[(int)REG_nS].set = 1; + if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u)) + rg[(int)REG_nS].v.u = 0; + + ROFF_DEBUG("roff: register nS: %u\n", + rg[(int)REG_nS].v.u); + } else + ROFF_DEBUG("roff: ignoring register: %s\n", key); return(ROFF_IGN); }