=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.177 retrieving revision 1.180 diff -u -p -r1.177 -r1.180 --- mandoc/roff.c 2013/06/27 09:49:47 1.177 +++ mandoc/roff.c 2013/10/05 22:08:12 1.180 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.177 2013/06/27 09:49:47 schwarze Exp $ */ +/* $Id: roff.c,v 1.180 2013/10/05 22:08:12 schwarze Exp $ */ /* * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -78,16 +79,6 @@ enum roffrule { }; /* - * A single register entity. If "set" is zero, the value of the - * register should be the default one, which is per-register. - * Registers are assumed to be unsigned ints for now. - */ -struct reg { - int set; /* whether set or not */ - unsigned int u; /* unsigned integer */ -}; - -/* * An incredibly-simple string buffer. */ struct roffstr { @@ -104,6 +95,16 @@ struct roffkv { struct roffkv *next; /* next in list */ }; +/* + * 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; + struct roffreg *next; +}; + struct roff { enum mparset parsetype; /* requested parse type */ struct mparse *parse; /* parse point */ @@ -111,7 +112,7 @@ struct roff { enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ char control; /* control character */ int rstackpos; /* position in rstack */ - struct reg regs[REG__MAX]; + struct roffreg *regtab; /* number registers */ struct roffkv *strtab; /* user-defined strings & macros */ struct roffkv *xmbtab; /* multi-byte trans table (`tr') */ struct roffstr *xtab; /* single-byte trans table (`tr') */ @@ -182,16 +183,18 @@ static enum rofferr roff_cond_sub(ROFF_ARGS); static enum rofferr roff_ds(ROFF_ARGS); static enum roffrule roff_evalcond(const char *, int *); 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 const char *roff_getstrn(const struct roff *, const char *, size_t); +static enum rofferr roff_it(ROFF_ARGS); static enum rofferr roff_line_ignore(ROFF_ARGS); 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 rofferr roff_parsetext(char *); +static enum rofferr roff_parsetext(char **, size_t *, int, int *); static enum rofferr roff_res(struct roff *, char **, size_t *, int, int); static enum rofferr roff_rm(ROFF_ARGS); @@ -233,7 +236,7 @@ static struct roffmac roffs[ROFF_MAX] = { { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL }, - { "it", roff_line_ignore, NULL, NULL, 0, NULL }, + { "it", roff_it, NULL, NULL, 0, NULL }, { "ne", roff_line_ignore, NULL, NULL, 0, NULL }, { "nh", roff_line_ignore, NULL, NULL, 0, NULL }, { "nr", roff_nr, NULL, NULL, 0, NULL }, @@ -295,6 +298,9 @@ static const struct predef predefs[PREDEFS_MAX] = { /* See roffhash_find() */ #define ROFF_HASH(p) (p[0] - ASCII_LO) +static int roffit_lines; /* number of lines to delay */ +static char *roffit_macro; /* nil-terminated macro line */ + static void roffhash_init(void) { @@ -419,6 +425,10 @@ roff_free1(struct roff *r) r->strtab = r->xmbtab = NULL; + roff_freereg(r->regtab); + + r->regtab = NULL; + if (r->xtab) for (i = 0; i < 128; i++) free(r->xtab[i].p); @@ -435,7 +445,6 @@ roff_reset(struct roff *r) roff_free1(r); r->control = 0; - memset(&r->regs, 0, sizeof(struct reg) * REG__MAX); for (i = 0; i < PREDEFS_MAX; i++) roff_setstr(r, predefs[i].name, predefs[i].str, 0); @@ -596,16 +605,20 @@ again: } /* - * Process text streams: convert all breakable hyphens into ASCII_HYPH. + * Process text streams: + * Convert all breakable hyphens into ASCII_HYPH. + * Decrement and spring input line trap. */ static enum rofferr -roff_parsetext(char *p) +roff_parsetext(char **bufp, size_t *szp, int pos, int *offs) { size_t sz; const char *start; + char *p; + int isz; enum mandoc_esc esc; - start = p; + start = p = *bufp + pos; while ('\0' != *p) { sz = strcspn(p, "-\\"); @@ -618,7 +631,7 @@ roff_parsetext(char *p) /* Skip over escapes. */ p++; esc = mandoc_escape - ((const char **)&p, NULL, NULL); + ((const char const **)&p, NULL, NULL); if (ESCAPE_ERROR == esc) break; continue; @@ -633,6 +646,22 @@ roff_parsetext(char *p) p++; } + /* Spring the input line trap. */ + if (1 == roffit_lines) { + isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro); + if (-1 == isz) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + free(*bufp); + *bufp = p; + *szp = isz + 1; + *offs = 0; + free(roffit_macro); + roffit_lines = 0; + return(ROFF_REPARSE); + } else if (1 < roffit_lines) + --roffit_lines; return(ROFF_CONT); } @@ -677,13 +706,13 @@ roff_parseln(struct roff *r, int ln, char **bufp, return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); if (r->tbl) return(tbl_read(r->tbl, ln, *bufp, pos)); - return(roff_parsetext(*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->tbl) return(tbl_read(r->tbl, ln, *bufp, pos)); - return(roff_parsetext(*bufp + pos)); + return(roff_parsetext(bufp, szp, pos, offs)); } else if (r->eqn) return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); @@ -1120,9 +1149,6 @@ static enum rofferr roff_line_ignore(ROFF_ARGS) { - if (ROFF_it == tok) - mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it"); - return(ROFF_IGN); } @@ -1236,25 +1262,52 @@ roff_ds(ROFF_ARGS) return(ROFF_IGN); } -int -roff_regisset(const struct roff *r, enum regs reg) +void +roff_setreg(struct roff *r, const char *name, unsigned int val) { + struct roffreg *reg; - return(r->regs[(int)reg].set); + /* Search for an existing register with the same name. */ + reg = r->regtab; + + while (reg && strcmp(name, reg->key.p)) + reg = reg->next; + + if (NULL == reg) { + /* Create a new register. */ + reg = mandoc_malloc(sizeof(struct roffreg)); + reg->key.p = mandoc_strdup(name); + reg->key.sz = strlen(name); + reg->next = r->regtab; + r->regtab = reg; + } + + reg->u = val; } unsigned int -roff_regget(const struct roff *r, enum regs reg) +roff_getreg(const struct roff *r, const char *name) { + struct roffreg *reg; - return(r->regs[(int)reg].u); + for (reg = r->regtab; reg; reg = reg->next) + if (0 == strcmp(name, reg->key.p)) + return(reg->u); + + return(0); } -void -roff_regunset(struct roff *r, enum regs reg) +static void +roff_freereg(struct roffreg *reg) { + struct roffreg *old_reg; - r->regs[(int)reg].set = 0; + while (NULL != reg) { + free(reg->key.p); + old_reg = reg; + reg = reg->next; + free(old_reg); + } } /* ARGSUSED */ @@ -1268,14 +1321,12 @@ roff_nr(ROFF_ARGS) val = *bufp + pos; key = roff_getname(r, &val, ln, pos); - if (0 == strcmp(key, "nS")) { - r->regs[(int)REG_nS].set = 1; - if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0) - r->regs[(int)REG_nS].u = (unsigned)iv; - else - r->regs[(int)REG_nS].u = 0u; - } + iv = mandoc_strntoi(val, strlen(val), 10); + if (0 > iv) + iv = 0; + roff_setreg(r, key, (unsigned)iv); + return(ROFF_IGN); } @@ -1292,6 +1343,31 @@ roff_rm(ROFF_ARGS) if ('\0' != *name) roff_setstr(r, name, NULL, 0); } + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr +roff_it(ROFF_ARGS) +{ + char *cp; + size_t len; + int iv; + + /* Parse the number of lines. */ + cp = *bufp + pos; + len = strcspn(cp, " \t"); + cp[len] = '\0'; + if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) { + mandoc_msg(MANDOCERR_NUMERIC, r->parse, + ln, ppos, *bufp + 1); + return(ROFF_IGN); + } + cp += len + 1; + + /* Arm the input line trap. */ + roffit_lines = iv; + roffit_macro = mandoc_strdup(cp); return(ROFF_IGN); }