=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.329 retrieving revision 1.338 diff -u -p -r1.329 -r1.338 --- mandoc/roff.c 2018/08/01 15:40:17 1.329 +++ mandoc/roff.c 2018/08/21 18:15:22 1.338 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.329 2018/08/01 15:40:17 schwarze Exp $ */ +/* $Id: roff.c,v 1.338 2018/08/21 18:15:22 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze @@ -107,7 +107,6 @@ struct roff { int rstacksz; /* current size limit of rstack */ int rstackpos; /* position in rstack */ 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 */ }; @@ -197,6 +196,7 @@ 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_nop(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 *, @@ -326,6 +326,7 @@ const char *__roff_name[MAN_MAX + 1] = { "Dx", "%Q", "%U", "Ta", NULL, "TH", "SH", "SS", "TP", + "TQ", "LP", "PP", "P", "IP", "HP", "SM", "SB", "BI", "IB", "BR", "RB", "R", @@ -333,7 +334,8 @@ const char *__roff_name[MAN_MAX + 1] = { "nf", "fi", "RE", "RS", "DT", "UC", "PD", "AT", "in", - "OP", "EX", "EE", "UR", + "SY", "YS", "OP", + "EX", "EE", "UR", "UE", "MT", "ME", NULL }; const char *const *roff_name = __roff_name; @@ -490,7 +492,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_line_ignore, NULL, NULL, 0 }, /* nhychar */ { roff_unsupp, NULL, NULL, 0 }, /* nm */ { roff_unsupp, NULL, NULL, 0 }, /* nn */ - { roff_unsupp, NULL, NULL, 0 }, /* nop */ + { roff_nop, NULL, NULL, 0 }, /* nop */ { roff_nr, NULL, NULL, 0 }, /* nr */ { roff_unsupp, NULL, NULL, 0 }, /* nrf */ { roff_line_ignore, NULL, NULL, 0 }, /* nroff */ @@ -1202,9 +1204,17 @@ roff_res(struct roff *r, struct buf *buf, int ln, int r->man->next = ROFF_NEXT_SIBLING; } - /* Discard comments. */ + /* Line continuation with comment. */ - while (stesc > start && stesc[-1] == ' ') + if (stesc[1] == '#') { + *stesc = '\0'; + return ROFF_APPEND; + } + + /* Discard normal comments. */ + + while (stesc > start && stesc[-1] == ' ' && + (stesc == start + 1 || stesc[-2] != '\\')) stesc--; *stesc = '\0'; break; @@ -1366,6 +1376,19 @@ roff_res(struct roff *r, struct buf *buf, int ln, int if (arg_complete) { deftype = ROFFDEF_USER | ROFFDEF_PRE; res = roff_getstrn(r, stnam, naml, &deftype); + + /* + * If not overriden, let \*(.T + * through to the formatters. + */ + + if (res == NULL && naml == 2 && + stnam[0] == '.' && stnam[1] == 'T') { + roff_setstrn(&r->strtab, + ".T", 2, NULL, 0, 0); + stesc--; + continue; + } } break; case 'B': @@ -2144,9 +2167,10 @@ out: static int roff_evalcond(struct roff *r, int ln, char *v, int *pos) { - char *cp, *name; - size_t sz; - int deftype, number, savepos, istrue, wanttrue; + const char *start, *end; + char *cp, *name; + size_t sz; + int deftype, len, number, savepos, istrue, wanttrue; if ('!' == v[*pos]) { wanttrue = 0; @@ -2161,12 +2185,50 @@ roff_evalcond(struct roff *r, int ln, char *v, int *po case 'o': (*pos)++; return wanttrue; - case 'c': case 'e': case 't': case 'v': (*pos)++; return !wanttrue; + case 'c': + do { + (*pos)++; + } while (v[*pos] == ' '); + + /* + * Quirk for groff compatibility: + * The horizontal tab is neither available nor unavailable. + */ + + if (v[*pos] == '\t') { + (*pos)++; + return 0; + } + + /* Printable ASCII characters are available. */ + + if (v[*pos] != '\\') { + (*pos)++; + return wanttrue; + } + + end = v + ++*pos; + switch (mandoc_escape(&end, &start, &len)) { + case ESCAPE_SPECIAL: + istrue = mchars_spec2cp(start, len) != -1; + break; + case ESCAPE_UNICODE: + istrue = 1; + break; + case ESCAPE_NUMBERED: + istrue = mchars_num2char(start, len) != -1; + break; + default: + istrue = !wanttrue; + break; + } + *pos = end - v; + return istrue == wanttrue; case 'd': case 'r': cp = v + *pos + 1; @@ -2600,7 +2662,7 @@ roff_getregro(const struct roff *r, const char *name) switch (*name) { case '$': /* Number of arguments of the last macro evaluated. */ - return r->argc; + return 0; case 'A': /* ASCII approximation mode is always off. */ return 0; case 'g': /* Groff compatibility mode is always on. */ @@ -3094,7 +3156,7 @@ roff_als(ROFF_ARGS) if (oldsz == 0) return ROFF_IGN; - valsz = mandoc_asprintf(&value, ".%.*s \\$*\\\"\n", + 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); @@ -3161,6 +3223,15 @@ roff_eo(ROFF_ARGS) } static enum rofferr +roff_nop(ROFF_ARGS) +{ + while (buf->buf[pos] == ' ') + pos++; + *offs = pos; + return ROFF_RERUN; +} + +static enum rofferr roff_tr(ROFF_ARGS) { const char *p, *first, *second; @@ -3309,22 +3380,22 @@ roff_userdef(ROFF_ARGS) { const char *arg[16], *ap; char *cp, *n1, *n2; - int expand_count, i, ib, ie; - size_t asz, rsz; + int argc, expand_count, i, ib, ie, quote_args; + size_t asz, esz, rsz; /* * Collect pointers to macro argument strings * and NUL-terminate them. */ - r->argc = 0; + argc = 0; cp = buf->buf + pos; for (i = 0; i < 16; i++) { if (*cp == '\0') arg[i] = ""; else { arg[i] = mandoc_getarg(r->parse, &cp, ln, &pos); - r->argc = i + 1; + argc = i + 1; } } @@ -3344,13 +3415,21 @@ roff_userdef(ROFF_ARGS) continue; if (*cp++ != '$') continue; - if (*cp == '*') { /* \\$* inserts all arguments */ + + quote_args = 0; + switch (*cp) { + case '@': /* \\$@ inserts all arguments, quoted */ + quote_args = 1; + /* FALLTHROUGH */ + case '*': /* \\$* inserts all arguments, unquoted */ ib = 0; - ie = r->argc - 1; - } else { /* \\$1 .. \\$9 insert one argument */ + ie = argc - 1; + break; + default: /* \\$1 .. \\$9 insert one argument */ ib = ie = *cp - '1'; if (ib < 0 || ib > 8) continue; + break; } cp -= 2; @@ -3376,6 +3455,8 @@ roff_userdef(ROFF_ARGS) asz = ie > ib ? ie - ib : 0; /* for blanks */ for (i = ib; i <= ie; i++) { + if (quote_args) + asz += 2; for (ap = arg[i]; *ap != '\0'; ap++) { asz++; if (*ap == '"') @@ -3422,6 +3503,8 @@ roff_userdef(ROFF_ARGS) n2 = cp; for (i = ib; i <= ie; i++) { + if (quote_args) + *n2++ = '"'; for (ap = arg[i]; *ap != '\0'; ap++) { if (*ap == '"') { memcpy(n2, "\\(dq", 4); @@ -3429,9 +3512,39 @@ roff_userdef(ROFF_ARGS) } else *n2++ = *ap; } + if (quote_args) + *n2++ = '"'; if (i < ie) *n2++ = ' '; } + } + + /* + * Expand the number of arguments, if it is used. + * This never makes the expanded macro longer. + */ + + for (cp = n1; *cp != '\0'; cp++) { + if (cp[0] != '\\') + continue; + if (cp[1] == '\\') { + cp++; + continue; + } + if (strncmp(cp + 1, "n(.$", 4) == 0) + esz = 5; + else if (strncmp(cp + 1, "n[.$]", 5) == 0) + esz = 6; + else + continue; + asz = snprintf(cp, esz, "%d", argc); + assert(asz < esz); + rsz = buf->sz - (cp - n1) - esz; + memmove(cp + asz, cp + esz, rsz); + buf->sz -= esz - asz; + n2 = mandoc_realloc(n1, buf->sz); + cp = n2 + (cp - n1) + asz; + n1 = n2; } /*