=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.295 retrieving revision 1.312 diff -u -p -r1.295 -r1.312 --- mandoc/roff.c 2017/04/29 12:45:42 1.295 +++ mandoc/roff.c 2017/06/14 22:51:25 1.312 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.295 2017/04/29 12:45:42 schwarze Exp $ */ +/* $Id: roff.c,v 1.312 2017/06/14 22:51:25 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017 Ingo Schwarze @@ -77,11 +77,13 @@ struct roffreq { struct roff { struct mparse *parse; /* parse point */ + struct roff_man *man; /* mdoc or man parser */ struct roffnode *last; /* leaf of stack */ int *rstack; /* stack of inverted `ie' values */ struct ohash *reqtab; /* request lookup table */ struct roffreg *regtab; /* number registers */ struct roffkv *strtab; /* user-defined strings & macros */ + struct roffkv *rentab; /* renamed 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 */ @@ -98,6 +100,7 @@ struct roff { int format; /* current file in mdoc or man format */ int argc; /* number of args of the last macro */ char control; /* control character */ + char escape; /* escape character */ }; struct roffnode { @@ -143,10 +146,11 @@ static void roffnode_cleanscope(struct roff *); static void roffnode_pop(struct roff *); static void roffnode_push(struct roff *, enum roff_tok, const char *, int, int); +static enum rofferr roff_als(ROFF_ARGS); static enum rofferr roff_block(ROFF_ARGS); static enum rofferr roff_block_text(ROFF_ARGS); static enum rofferr roff_block_sub(ROFF_ARGS); -static enum rofferr roff_brp(ROFF_ARGS); +static enum rofferr roff_br(ROFF_ARGS); static enum rofferr roff_cblock(ROFF_ARGS); static enum rofferr roff_cc(ROFF_ARGS); static void roff_ccond(struct roff *, int, int); @@ -154,6 +158,8 @@ 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_ds(ROFF_ARGS); +static enum rofferr roff_ec(ROFF_ARGS); +static enum rofferr roff_eo(ROFF_ARGS); static enum rofferr roff_eqndelim(struct roff *, struct buf *, int); static int roff_evalcond(struct roff *r, int, char *, int *); static int roff_evalnum(struct roff *, int, @@ -171,6 +177,8 @@ static int roff_getregn(const struct roff *, const char *, size_t); static int roff_getregro(const struct roff *, const char *name); +static const char *roff_getrenn(const struct roff *, + const char *, size_t); static const char *roff_getstrn(const struct roff *, const char *, size_t); static int roff_hasregn(const struct roff *, @@ -180,12 +188,17 @@ static enum rofferr roff_it(ROFF_ARGS); static enum rofferr roff_line_ignore(ROFF_ARGS); static void roff_man_alloc1(struct roff_man *); static void roff_man_free1(struct roff_man *); +static enum rofferr roff_manyarg(ROFF_ARGS); static enum rofferr roff_nr(ROFF_ARGS); +static enum rofferr roff_onearg(ROFF_ARGS); static enum roff_tok roff_parse(struct roff *, char *, int *, int, int); -static enum rofferr roff_parsetext(struct buf *, int, int *); +static enum rofferr roff_parsetext(struct roff *, struct buf *, + int, int *); +static enum rofferr roff_renamed(ROFF_ARGS); static enum rofferr roff_res(struct roff *, struct buf *, int, int); static enum rofferr roff_rm(ROFF_ARGS); +static enum rofferr roff_rn(ROFF_ARGS); static enum rofferr roff_rr(ROFF_ARGS); static void roff_setstr(struct roff *, const char *, const char *, int); @@ -209,13 +222,16 @@ static enum rofferr roff_userdef(ROFF_ARGS); #define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */ const char *__roff_name[MAN_MAX + 1] = { + "br", "ce", "ft", "ll", + "mc", "po", "rj", "sp", + "ta", "ti", NULL, "ab", "ad", "af", "aln", "als", "am", "am1", "ami", "ami1", "as", "as1", "asciify", "backtrace", "bd", "bleedat", "blm", "box", "boxa", "bp", "BP", "break", "breakchar", "brnl", "brp", - "brpnl", "c2", "cc", "ce", + "brpnl", "c2", "cc", "cf", "cflags", "ch", "char", "chop", "class", "close", "CL", "color", "composite", "continue", "cp", @@ -241,7 +257,7 @@ const char *__roff_name[MAN_MAX + 1] = { "lc", "lc_ctype", "lds", "length", "letadj", "lf", "lg", "lhang", "linetabs", "lnr", "lnrf", "lpfx", - "ls", "lsm", "lt", "mc", + "ls", "lsm", "lt", "mediasize", "minss", "mk", "mso", "na", "ne", "nh", "nhychar", "nm", "nn", "nop", "nr", @@ -249,17 +265,17 @@ const char *__roff_name[MAN_MAX + 1] = { "open", "opena", "os", "output", "padj", "papersize", "pc", "pev", "pi", "PI", "pl", "pm", - "pn", "pnr", "po", "ps", + "pn", "pnr", "ps", "psbb", "pshape", "pso", "ptr", "pvs", "rchar", "rd", "recursionlimit", - "return", "rfschar", "rhang", "rj", + "return", "rfschar", "rhang", "rm", "rn", "rnn", "rr", "rs", "rt", "schar", "sentchar", "shc", "shift", "sizes", "so", "spacewidth", "special", "spreadwarn", "ss", "sty", "substring", "sv", "sy", - "T&", "ta", "tc", "TE", - "TH", "ti", "tkf", "tl", + "T&", "tc", "TE", + "TH", "tkf", "tl", "tm", "tm1", "tmc", "tr", "track", "transchar", "trf", "trimat", "trin", "trnt", "troff", "TS", @@ -268,7 +284,7 @@ const char *__roff_name[MAN_MAX + 1] = { "warnscale", "watch", "watchlength", "watchn", "wh", "while", "write", "writec", "writem", "xflag", ".", NULL, - "text", + NULL, "text", "Dd", "Dt", "Os", "Sh", "Ss", "Pp", "D1", "Dl", "Bd", "Ed", "Bl", "El", @@ -298,27 +314,38 @@ const char *__roff_name[MAN_MAX + 1] = { "Fr", "Ud", "Lb", "Lp", "Lk", "Mt", "Brq", "Bro", "Brc", "%C", "Es", "En", - "Dx", "%Q", "br", "sp", - "%U", "Ta", "ll", NULL, + "Dx", "%Q", "%U", "Ta", + NULL, "TH", "SH", "SS", "TP", "LP", "PP", "P", "IP", "HP", "SM", "SB", "BI", "IB", "BR", "RB", "R", "B", "I", "IR", "RI", - "br", "sp", "nf", "fi", + "nf", "fi", "RE", "RS", "DT", "UC", - "PD", "AT", "in", "ft", + "PD", "AT", "in", "OP", "EX", "EE", "UR", - "UE", "ll", NULL + "UE", NULL }; const char *const *roff_name = __roff_name; static struct roffmac roffs[TOKEN_NONE] = { + { roff_br, NULL, NULL, 0 }, /* br */ + { roff_onearg, NULL, NULL, 0 }, /* ce */ + { roff_onearg, NULL, NULL, 0 }, /* ft */ + { roff_onearg, NULL, NULL, 0 }, /* ll */ + { roff_onearg, NULL, NULL, 0 }, /* mc */ + { roff_onearg, NULL, NULL, 0 }, /* po */ + { roff_onearg, NULL, NULL, 0 }, /* rj */ + { roff_onearg, NULL, NULL, 0 }, /* sp */ + { roff_manyarg, NULL, NULL, 0 }, /* ta */ + { roff_onearg, NULL, NULL, 0 }, /* ti */ + { NULL, NULL, NULL, 0 }, /* ROFF_MAX */ { roff_unsupp, NULL, NULL, 0 }, /* ab */ { roff_line_ignore, NULL, NULL, 0 }, /* ad */ { roff_line_ignore, NULL, NULL, 0 }, /* af */ { roff_unsupp, NULL, NULL, 0 }, /* aln */ - { roff_unsupp, NULL, NULL, 0 }, /* als */ + { roff_als, NULL, NULL, 0 }, /* als */ { roff_block, roff_block_text, roff_block_sub, 0 }, /* am */ { roff_block, roff_block_text, roff_block_sub, 0 }, /* am1 */ { roff_block, roff_block_text, roff_block_sub, 0 }, /* ami */ @@ -337,11 +364,10 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_unsupp, NULL, NULL, 0 }, /* break */ { roff_line_ignore, NULL, NULL, 0 }, /* breakchar */ { roff_line_ignore, NULL, NULL, 0 }, /* brnl */ - { roff_brp, NULL, NULL, 0 }, /* brp */ + { roff_br, NULL, NULL, 0 }, /* brp */ { roff_line_ignore, NULL, NULL, 0 }, /* brpnl */ { roff_unsupp, NULL, NULL, 0 }, /* c2 */ { roff_cc, NULL, NULL, 0 }, /* cc */ - { roff_line_ignore, NULL, NULL, 0 }, /* ce */ { roff_insec, NULL, NULL, 0 }, /* cf */ { roff_line_ignore, NULL, NULL, 0 }, /* cflags */ { roff_line_ignore, NULL, NULL, 0 }, /* ch */ @@ -373,13 +399,13 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_ds, NULL, NULL, 0 }, /* ds1 */ { roff_unsupp, NULL, NULL, 0 }, /* dwh */ { roff_unsupp, NULL, NULL, 0 }, /* dt */ - { roff_unsupp, NULL, NULL, 0 }, /* ec */ + { roff_ec, NULL, NULL, 0 }, /* ec */ { roff_unsupp, NULL, NULL, 0 }, /* ecr */ { roff_unsupp, NULL, NULL, 0 }, /* ecs */ { roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT }, /* el */ { roff_unsupp, NULL, NULL, 0 }, /* em */ { roff_EN, NULL, NULL, 0 }, /* EN */ - { roff_unsupp, NULL, NULL, 0 }, /* eo */ + { roff_eo, NULL, NULL, 0 }, /* eo */ { roff_unsupp, NULL, NULL, 0 }, /* EP */ { roff_EQ, NULL, NULL, 0 }, /* EQ */ { roff_line_ignore, NULL, NULL, 0 }, /* errprint */ @@ -445,7 +471,6 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_line_ignore, NULL, NULL, 0 }, /* ls */ { roff_unsupp, NULL, NULL, 0 }, /* lsm */ { roff_line_ignore, NULL, NULL, 0 }, /* lt */ - { roff_line_ignore, NULL, NULL, 0 }, /* mc */ { roff_line_ignore, NULL, NULL, 0 }, /* mediasize */ { roff_line_ignore, NULL, NULL, 0 }, /* minss */ { roff_line_ignore, NULL, NULL, 0 }, /* mk */ @@ -476,7 +501,6 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_line_ignore, NULL, NULL, 0 }, /* pm */ { roff_line_ignore, NULL, NULL, 0 }, /* pn */ { roff_line_ignore, NULL, NULL, 0 }, /* pnr */ - { roff_line_ignore, NULL, NULL, 0 }, /* po */ { roff_line_ignore, NULL, NULL, 0 }, /* ps */ { roff_unsupp, NULL, NULL, 0 }, /* psbb */ { roff_unsupp, NULL, NULL, 0 }, /* pshape */ @@ -489,9 +513,8 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_unsupp, NULL, NULL, 0 }, /* return */ { roff_unsupp, NULL, NULL, 0 }, /* rfschar */ { roff_line_ignore, NULL, NULL, 0 }, /* rhang */ - { roff_line_ignore, NULL, NULL, 0 }, /* rj */ { roff_rm, NULL, NULL, 0 }, /* rm */ - { roff_unsupp, NULL, NULL, 0 }, /* rn */ + { roff_rn, NULL, NULL, 0 }, /* rn */ { roff_unsupp, NULL, NULL, 0 }, /* rnn */ { roff_rr, NULL, NULL, 0 }, /* rr */ { roff_line_ignore, NULL, NULL, 0 }, /* rs */ @@ -511,11 +534,9 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_line_ignore, NULL, NULL, 0 }, /* sv */ { roff_insec, NULL, NULL, 0 }, /* sy */ { roff_T_, NULL, NULL, 0 }, /* T& */ - { roff_unsupp, NULL, NULL, 0 }, /* ta */ { roff_unsupp, NULL, NULL, 0 }, /* tc */ { roff_TE, NULL, NULL, 0 }, /* TE */ { roff_TH, NULL, NULL, 0 }, /* TH */ - { roff_unsupp, NULL, NULL, 0 }, /* ti */ { roff_line_ignore, NULL, NULL, 0 }, /* tkf */ { roff_unsupp, NULL, NULL, 0 }, /* tl */ { roff_line_ignore, NULL, NULL, 0 }, /* tm */ @@ -549,6 +570,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_insec, NULL, NULL, 0 }, /* writem */ { roff_line_ignore, NULL, NULL, 0 }, /* xflag */ { roff_cblock, NULL, NULL, 0 }, /* . */ + { roff_renamed, NULL, NULL, 0 }, { roff_userdef, NULL, NULL, 0 } }; @@ -591,6 +613,8 @@ static const struct predef predefs[PREDEFS_MAX] = { #include "predefs.in" }; +static int roffce_lines; /* number of input lines to center */ +static struct roff_node *roffce_node; /* active request */ static int roffit_lines; /* number of lines to delay */ static char *roffit_macro; /* nil-terminated macro line */ @@ -610,6 +634,8 @@ roffhash_alloc(enum roff_tok mintok, enum roff_tok max mandoc_ohash_init(htab, 8, offsetof(struct roffreq, name)); for (tok = mintok; tok < maxtok; tok++) { + if (roff_name[tok] == NULL) + continue; sz = strlen(roff_name[tok]); req = mandoc_malloc(sizeof(*req) + sz + 1); req->tok = tok; @@ -724,8 +750,9 @@ roff_free1(struct roff *r) r->regtab = NULL; roff_freestr(r->strtab); + roff_freestr(r->rentab); roff_freestr(r->xmbtab); - r->strtab = r->xmbtab = NULL; + r->strtab = r->rentab = r->xmbtab = NULL; if (r->xtab) for (i = 0; i < 128; i++) @@ -739,7 +766,12 @@ roff_reset(struct roff *r) { roff_free1(r); r->format = r->options & (MPARSE_MDOC | MPARSE_MAN); - r->control = 0; + r->control = '\0'; + r->escape = '\\'; + roffce_lines = 0; + roffce_node = NULL; + roffit_lines = 0; + roffit_macro = NULL; } void @@ -761,6 +793,7 @@ roff_alloc(struct mparse *parse, int options) r->options = options; r->format = options & (MPARSE_MDOC | MPARSE_MAN); r->rstackpos = -1; + r->escape = '\\'; return r; } @@ -824,6 +857,7 @@ roff_man_alloc(struct roff *roff, struct mparse *parse man->defos = defos; man->quick = quick; roff_man_alloc1(man); + roff->man = man; return man; } @@ -996,7 +1030,7 @@ roff_addtbl(struct roff_man *man, const struct tbl_spa struct roff_node *n; if (man->macroset == MACROSET_MAN) - man_breakscope(man, TOKEN_NONE); + man_breakscope(man, ROFF_TS); n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE); n->span = tbl; roff_node_append(man, n); @@ -1136,27 +1170,80 @@ roff_res(struct roff *r, struct buf *buf, int ln, int int expand_count; /* to avoid infinite loops */ int npos; /* position in numeric expression */ int arg_complete; /* argument not interrupted by eol */ + int done; /* no more input available */ char term; /* character terminating the escape */ - expand_count = 0; + /* Search forward for comments. */ + + done = 0; start = buf->buf + pos; - stesc = strchr(start, '\0') - 1; - while (stesc-- > start) { + for (stesc = buf->buf + pos; *stesc != '\0'; stesc++) { + if (stesc[0] != r->escape || stesc[1] == '\0') + continue; + stesc++; + if (*stesc != '"' && *stesc != '#') + continue; + cp = strchr(stesc--, '\0') - 1; + if (*cp == '\n') { + done = 1; + cp--; + } + if (*cp == ' ' || *cp == '\t') + mandoc_msg(MANDOCERR_SPACE_EOL, r->parse, + ln, cp - buf->buf, NULL); + while (stesc > start && stesc[-1] == ' ') + stesc--; + *stesc = '\0'; + break; + } + if (stesc == start) + return ROFF_CONT; + stesc--; + /* Notice the end of the input. */ + + if (*stesc == '\n') { + *stesc-- = '\0'; + done = 1; + } + + expand_count = 0; + while (stesc >= start) { + /* Search backwards for the next backslash. */ - if (*stesc != '\\') + if (*stesc != r->escape) { + if (*stesc == '\\') { + *stesc = '\0'; + buf->sz = mandoc_asprintf(&nbuf, "%s\\e%s", + buf->buf, stesc + 1) + 1; + start = nbuf + pos; + stesc = nbuf + (stesc - buf->buf); + free(buf->buf); + buf->buf = nbuf; + } + stesc--; continue; + } /* If it is escaped, skip it. */ for (cp = stesc - 1; cp >= start; cp--) - if (*cp != '\\') + if (*cp != r->escape) break; if ((stesc - cp) % 2 == 0) { - stesc = (char *)cp; + while (stesc > cp) + *stesc-- = '\\'; continue; + } else if (stesc[1] != '\0') { + *stesc = '\\'; + } else { + *stesc-- = '\0'; + if (done) + continue; + else + return ROFF_APPEND; } /* Decide whether to expand or to check only. */ @@ -1182,6 +1269,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int mandoc_vmsg(MANDOCERR_ESC_BAD, r->parse, ln, (int)(stesc - buf->buf), "%.*s", (int)(cp - stesc), stesc); + stesc--; continue; } @@ -1315,7 +1403,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int * Process text streams. */ static enum rofferr -roff_parsetext(struct buf *buf, int pos, int *offs) +roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs) { size_t sz; const char *start; @@ -1337,6 +1425,16 @@ roff_parsetext(struct buf *buf, int pos, int *offs) } else if (roffit_lines > 1) --roffit_lines; + if (roffce_node != NULL && buf->buf[pos] != '\0') { + if (roffce_lines < 1) { + r->man->last = roffce_node; + r->man->next = ROFF_NEXT_SIBLING; + roffce_lines = 0; + roffce_node = NULL; + } else + roffce_lines--; + } + /* Convert all breakable hyphens into ASCII_HYPH. */ start = p = buf->buf + pos; @@ -1396,7 +1494,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, /* Expand some escape sequences. */ e = roff_res(r, buf, ln, pos); - if (e == ROFF_IGN) + if (e == ROFF_IGN || e == ROFF_APPEND) return e; assert(e == ROFF_CONT); @@ -1422,7 +1520,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, if (r->tbl != NULL && ( ! ctl || buf->buf[pos] == '\0')) return tbl_read(r->tbl, ln, buf->buf, ppos); if ( ! ctl) - return roff_parsetext(buf, pos, offs); + return roff_parsetext(r, buf, pos, offs); /* Skip empty request lines. */ @@ -1451,10 +1549,11 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, /* Tables ignore most macros. */ - if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS)) { + if (r->tbl != NULL && (t == TOKEN_NONE || t == ROFF_TS || + t == ROFF_br || t == ROFF_ce || t == ROFF_rj || t == ROFF_sp)) { mandoc_msg(MANDOCERR_TBLMACRO, r->parse, ln, pos, buf->buf + spos); - if (t == ROFF_TS) + if (t != TOKEN_NONE) return ROFF_IGN; while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ') pos++; @@ -1463,6 +1562,16 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, return tbl_read(r->tbl, ln, buf->buf, pos); } + /* For now, let high level macros abort .ce mode. */ + + if (ctl && roffce_node != NULL && + (t == TOKEN_NONE || t == ROFF_EQ || t == ROFF_TS)) { + r->man->last = roffce_node; + r->man->next = ROFF_NEXT_SIBLING; + roffce_lines = 0; + roffce_node = NULL; + } + /* * This is neither a roff request nor a user-defined macro. * Let the standard macro set parsers handle it. @@ -1473,7 +1582,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, /* Execute a roff request or a user defined macro. */ - return (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); + return (*roffs[t].proc)(r, t, buf, ln, spos, pos, offs); } void @@ -1518,8 +1627,10 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln mac = cp; maclen = roff_getname(r, &cp, ln, ppos); - t = (r->current_string = roff_getstrn(r, mac, maclen)) - ? ROFF_USERDEF : roffhash_find(r->reqtab, mac, maclen); + t = (r->current_string = roff_getstrn(r, mac, maclen)) ? + ROFF_USERDEF : + (r->current_string = roff_getrenn(r, mac, maclen)) ? + ROFF_RENAMED : roffhash_find(r->reqtab, mac, maclen); if (t != TOKEN_NONE) *pos = cp - buf; @@ -1669,8 +1780,10 @@ roff_block(ROFF_ARGS) * appended from roff_block_text() in multiline mode. */ - if (tok == ROFF_de || tok == ROFF_dei) + if (tok == ROFF_de || tok == ROFF_dei) { roff_setstrn(&r->strtab, name, namesz, "", 0, 0); + roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); + } if (*cp == '\0') return ROFF_IGN; @@ -1955,7 +2068,7 @@ roff_evalcond(struct roff *r, int ln, char *v, int *po { char *cp, *name; size_t sz; - int number, savepos, wanttrue; + int number, savepos, istrue, wanttrue; if ('!' == v[*pos]) { wanttrue = 0; @@ -1971,17 +2084,23 @@ roff_evalcond(struct roff *r, int ln, char *v, int *po (*pos)++; return wanttrue; case 'c': - case 'd': case 'e': case 't': case 'v': (*pos)++; return !wanttrue; + case 'd': case 'r': - cp = name = v + ++*pos; - sz = roff_getname(r, &cp, ln, *pos); + cp = v + *pos + 1; + while (*cp == ' ') + cp++; + name = cp; + sz = roff_getname(r, &cp, ln, cp - v); + istrue = sz && (v[*pos] == 'r' ? roff_hasregn(r, name, sz) : + (roff_getstrn(r, name, sz) != NULL || + roff_getrenn(r, name, sz) != NULL)); *pos = cp - v; - return (sz && roff_hasregn(r, name, sz)) == wanttrue; + return istrue == wanttrue; default: break; } @@ -2133,6 +2252,7 @@ roff_ds(ROFF_ARGS) /* The rest is the value. */ roff_setstrn(&r->strtab, name, namesz, string, strlen(string), ROFF_as == tok); + roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); return ROFF_IGN; } @@ -2544,6 +2664,7 @@ roff_rm(ROFF_ARGS) name = cp; namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf)); roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0); + roff_setstrn(&r->rentab, name, namesz, NULL, 0, 0); if (name[namesz] == '\\') break; } @@ -2633,7 +2754,7 @@ roff_T_(ROFF_ARGS) mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "T&"); else - tbl_restart(ppos, ln, r->tbl); + tbl_restart(ln, ppos, r->tbl); return ROFF_IGN; } @@ -2760,14 +2881,128 @@ roff_TS(ROFF_ARGS) } static enum rofferr -roff_brp(ROFF_ARGS) +roff_onearg(ROFF_ARGS) { + struct roff_node *n; + char *cp; + int npos; - buf->buf[pos - 1] = '\0'; - return ROFF_CONT; + if (r->man->flags & (MAN_BLINE | MAN_ELINE) && + (tok == ROFF_sp || tok == ROFF_ti)) + man_breakscope(r->man, tok); + + if (roffce_node != NULL && (tok == ROFF_ce || tok == ROFF_rj)) { + r->man->last = roffce_node; + r->man->next = ROFF_NEXT_SIBLING; + } + + roff_elem_alloc(r->man, ln, ppos, tok); + n = r->man->last; + + cp = buf->buf + pos; + if (*cp != '\0') { + while (*cp != '\0' && *cp != ' ') + cp++; + while (*cp == ' ') + *cp++ = '\0'; + if (*cp != '\0') + mandoc_vmsg(MANDOCERR_ARG_EXCESS, + r->parse, ln, cp - buf->buf, + "%s ... %s", roff_name[tok], cp); + roff_word_alloc(r->man, ln, pos, buf->buf + pos); + } + + if (tok == ROFF_ce || tok == ROFF_rj) { + if (r->man->last->type == ROFFT_ELEM) { + roff_word_alloc(r->man, ln, pos, "1"); + r->man->last->flags |= NODE_NOSRC; + } + npos = 0; + if (roff_evalnum(r, ln, r->man->last->string, &npos, + &roffce_lines, 0) == 0) { + mandoc_vmsg(MANDOCERR_CE_NONUM, + r->parse, ln, pos, "ce %s", buf->buf + pos); + roffce_lines = 1; + } + if (roffce_lines < 1) { + r->man->last = r->man->last->parent; + roffce_node = NULL; + roffce_lines = 0; + } else + roffce_node = r->man->last->parent; + } else { + n->flags |= NODE_VALID | NODE_ENDED; + r->man->last = n; + } + n->flags |= NODE_LINE; + r->man->next = ROFF_NEXT_SIBLING; + return ROFF_IGN; } static enum rofferr +roff_manyarg(ROFF_ARGS) +{ + struct roff_node *n; + char *sp, *ep; + + roff_elem_alloc(r->man, ln, ppos, tok); + n = r->man->last; + + for (sp = ep = buf->buf + pos; *sp != '\0'; sp = ep) { + while (*ep != '\0' && *ep != ' ') + ep++; + while (*ep == ' ') + *ep++ = '\0'; + roff_word_alloc(r->man, ln, sp - buf->buf, sp); + } + + n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; + r->man->last = n; + r->man->next = ROFF_NEXT_SIBLING; + return ROFF_IGN; +} + +static enum rofferr +roff_als(ROFF_ARGS) +{ + char *oldn, *newn, *end, *value; + size_t oldsz, newsz, valsz; + + newn = oldn = buf->buf + pos; + if (*newn == '\0') + return ROFF_IGN; + + newsz = roff_getname(r, &oldn, ln, pos); + if (newn[newsz] == '\\' || *oldn == '\0') + return ROFF_IGN; + + end = oldn; + oldsz = roff_getname(r, &end, ln, oldn - buf->buf); + if (oldsz == 0) + return ROFF_IGN; + + valsz = mandoc_asprintf(&value, ".%.*s \\$*\n", (int)oldsz, oldn); + roff_setstrn(&r->strtab, newn, newsz, value, valsz, 0); + roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); + free(value); + return ROFF_IGN; +} + +static enum rofferr +roff_br(ROFF_ARGS) +{ + if (r->man->flags & (MAN_BLINE | MAN_ELINE)) + man_breakscope(r->man, ROFF_br); + roff_elem_alloc(r->man, ln, ppos, ROFF_br); + if (buf->buf[pos] != '\0') + mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos, + "%s %s", roff_name[tok], buf->buf + pos); + r->man->last->flags |= NODE_LINE | NODE_VALID | NODE_ENDED; + r->man->next = ROFF_NEXT_SIBLING; + return ROFF_IGN; +} + +static enum rofferr roff_cc(ROFF_ARGS) { const char *p; @@ -2775,7 +3010,7 @@ roff_cc(ROFF_ARGS) p = buf->buf + pos; if (*p == '\0' || (r->control = *p++) == '.') - r->control = 0; + r->control = '\0'; if (*p != '\0') mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, @@ -2785,6 +3020,33 @@ roff_cc(ROFF_ARGS) } static enum rofferr +roff_ec(ROFF_ARGS) +{ + const char *p; + + p = buf->buf + pos; + if (*p == '\0') + r->escape = '\\'; + else { + r->escape = *p; + if (*++p != '\0') + mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, + ln, p - buf->buf, "ec ... %s", p); + } + return ROFF_IGN; +} + +static enum rofferr +roff_eo(ROFF_ARGS) +{ + r->escape = '\0'; + if (buf->buf[pos] != '\0') + mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, + ln, pos, "eo %s", buf->buf + pos); + return ROFF_IGN; +} + +static enum rofferr roff_tr(ROFF_ARGS) { const char *p, *first, *second; @@ -2847,6 +3109,56 @@ roff_tr(ROFF_ARGS) } static enum rofferr +roff_rn(ROFF_ARGS) +{ + const char *value; + char *oldn, *newn, *end; + size_t oldsz, newsz; + + oldn = newn = buf->buf + pos; + if (*oldn == '\0') + return ROFF_IGN; + + oldsz = roff_getname(r, &newn, ln, pos); + if (oldn[oldsz] == '\\' || *newn == '\0') + return ROFF_IGN; + + end = newn; + newsz = roff_getname(r, &end, ln, newn - buf->buf); + if (newsz == 0) + return ROFF_IGN; + + /* + * Rename a user-defined macro bearing the old name, + * overriding an existing renamed high-level macro + * bearing the new name, if that exists. + */ + + if ((value = roff_getstrn(r, oldn, oldsz)) != NULL) { + roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0); + roff_setstrn(&r->strtab, oldn, oldsz, NULL, 0, 0); + roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0); + return ROFF_IGN; + } + + /* + * Rename a high-level macro bearing the old name, + * either renaming it a second time if it was already + * renamed before, or renaming it for the first time. + * In both cases, override an existing user-defined + * macro bearing the new name, if that exists. + */ + + if ((value = roff_getrenn(r, oldn, oldsz)) != NULL) { + roff_setstrn(&r->rentab, newn, newsz, value, strlen(value), 0); + roff_setstrn(&r->rentab, oldn, oldsz, NULL, 0, 0); + } else + roff_setstrn(&r->rentab, newn, newsz, oldn, oldsz, 0); + roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0); + return ROFF_IGN; +} + +static enum rofferr roff_so(ROFF_ARGS) { char *name, *cp; @@ -2881,7 +3193,7 @@ roff_so(ROFF_ARGS) static enum rofferr roff_userdef(ROFF_ARGS) { - const char *arg[9], *ap; + const char *arg[16], *ap; char *cp, *n1, *n2; int expand_count, i, ib, ie; size_t asz, rsz; @@ -2893,7 +3205,7 @@ roff_userdef(ROFF_ARGS) r->argc = 0; cp = buf->buf + pos; - for (i = 0; i < 9; i++) { + for (i = 0; i < 16; i++) { if (*cp == '\0') arg[i] = ""; else { @@ -3020,6 +3332,22 @@ roff_userdef(ROFF_ARGS) ROFF_REPARSE : ROFF_APPEND; } +/* + * Calling a high-level macro that was renamed with .rn. + * r->current_string has already been set up by roff_parse(). + */ +static enum rofferr +roff_renamed(ROFF_ARGS) +{ + char *nbuf; + + buf->sz = mandoc_asprintf(&nbuf, ".%s %s", r->current_string, + buf->buf + pos) + 1; + free(buf->buf); + buf->buf = nbuf; + return ROFF_CONT; +} + static size_t roff_getname(struct roff *r, char **cpp, int ln, int pos) { @@ -3165,6 +3493,23 @@ roff_getstrn(const struct roff *r, const char *name, s return NULL; } +/* + * Check whether *name is the renamed name of a high-level macro. + * Return the standard name, or NULL if it is not. + */ +static const char * +roff_getrenn(const struct roff *r, const char *name, size_t len) +{ + const struct roffkv *n; + + for (n = r->rentab; n; n = n->next) + 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 roffkv *r) { @@ -3311,9 +3656,9 @@ roff_getcontrol(const struct roff *r, const char *cp, pos = *ppos; - if (0 != r->control && cp[pos] == r->control) + if (r->control != '\0' && cp[pos] == r->control) pos++; - else if (0 != r->control) + else if (r->control != '\0') return 0; else if ('\\' == cp[pos] && '.' == cp[pos + 1]) pos += 2;