=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.340 retrieving revision 1.345 diff -u -p -r1.340 -r1.345 --- mandoc/roff.c 2018/08/24 23:12:33 1.340 +++ mandoc/roff.c 2018/12/12 21:54:35 1.345 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.340 2018/08/24 23:12:33 schwarze Exp $ */ +/* $Id: roff.c,v 1.345 2018/12/12 21:54:35 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze @@ -28,10 +28,11 @@ #include #include -#include "mandoc.h" #include "mandoc_aux.h" #include "mandoc_ohash.h" +#include "mandoc.h" #include "roff.h" +#include "tbl.h" #include "libmandoc.h" #include "roff_int.h" #include "libroff.h" @@ -176,6 +177,7 @@ static int roff_br(ROFF_ARGS); static int roff_cblock(ROFF_ARGS); static int roff_cc(ROFF_ARGS); static int roff_ccond(struct roff *, int, int); +static int roff_char(ROFF_ARGS); static int roff_cond(ROFF_ARGS); static int roff_cond_text(ROFF_ARGS); static int roff_cond_sub(ROFF_ARGS); @@ -397,7 +399,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_insec, NULL, NULL, 0 }, /* cf */ { roff_line_ignore, NULL, NULL, 0 }, /* cflags */ { roff_line_ignore, NULL, NULL, 0 }, /* ch */ - { roff_unsupp, NULL, NULL, 0 }, /* char */ + { roff_char, NULL, NULL, 0 }, /* char */ { roff_unsupp, NULL, NULL, 0 }, /* chop */ { roff_line_ignore, NULL, NULL, 0 }, /* class */ { roff_insec, NULL, NULL, 0 }, /* close */ @@ -1066,6 +1068,14 @@ roff_node_unlink(struct roff_man *man, struct roff_nod } void +roff_node_relink(struct roff_man *man, struct roff_node *n) +{ + roff_node_unlink(man, n); + n->prev = n->next = NULL; + roff_node_append(man, n); +} + +void roff_node_free(struct roff_node *n) { @@ -2106,7 +2116,10 @@ roff_cond_sub(ROFF_ARGS) if (ep[0] == '\\' && ep[1] == '}') rr = 0; - /* Always check for the closing delimiter `\}'. */ + /* + * The closing delimiter `\}' rewinds the conditional scope + * but is otherwise ignored when interpreting the line. + */ while ((ep = strchr(ep, '\\')) != NULL) { switch (ep[1]) { @@ -2149,15 +2162,34 @@ roff_cond_text(ROFF_ARGS) if (roffnode_cleanscope(r)) irc |= endloop; + /* + * If `\}' occurs on a text line with neither preceding + * nor following characters, drop the line completely. + */ + ep = buf->buf + pos; + if (strcmp(ep, "\\}") == 0) + rr = 0; + + /* + * The closing delimiter `\}' rewinds the conditional scope + * but is otherwise ignored when interpreting the line. + */ + while ((ep = strchr(ep, '\\')) != NULL) { - if (*(++ep) == '}') { - *ep = '&'; - if (roff_ccond(r, ln, ep - buf->buf - 1)) + switch (ep[1]) { + case '}': + memmove(ep, ep + 2, strlen(ep + 2) + 1); + if (roff_ccond(r, ln, ep - buf->buf)) irc |= endloop; - } - if (*ep != '\0') + break; + case '\0': ++ep; + break; + default: + ep += 2; + break; + } } if (rr) irc |= ROFF_CONT; @@ -3318,6 +3350,77 @@ roff_cc(ROFF_ARGS) mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse, ln, p - buf->buf, "cc ... %s", p); + return ROFF_IGN; +} + +static int +roff_char(ROFF_ARGS) +{ + const char *p, *kp, *vp; + size_t ksz, vsz; + int font; + + /* Parse the character to be replaced. */ + + kp = buf->buf + pos; + p = kp + 1; + if (*kp == '\0' || (*kp == '\\' && + mandoc_escape(&p, NULL, NULL) != ESCAPE_SPECIAL) || + (*p != ' ' && *p != '\0')) { + mandoc_vmsg(MANDOCERR_CHAR_ARG, r->parse, + ln, pos, "char %s", kp); + return ROFF_IGN; + } + ksz = p - kp; + while (*p == ' ') + p++; + + /* + * If the replacement string contains a font escape sequence, + * we have to restore the font at the end. + */ + + vp = p; + vsz = strlen(p); + font = 0; + while (*p != '\0') { + if (*p++ != '\\') + continue; + switch (mandoc_escape(&p, NULL, NULL)) { + case ESCAPE_FONT: + case ESCAPE_FONTROMAN: + case ESCAPE_FONTITALIC: + case ESCAPE_FONTBOLD: + case ESCAPE_FONTBI: + case ESCAPE_FONTCW: + case ESCAPE_FONTPREV: + font++; + break; + default: + break; + } + } + if (font > 1) + mandoc_msg(MANDOCERR_CHAR_FONT, r->parse, + ln, vp - buf->buf, vp); + + /* + * Approximate the effect of .char using the .tr tables. + * XXX In groff, .char and .tr interact differently. + */ + + if (ksz == 1) { + if (r->xtab == NULL) + r->xtab = mandoc_calloc(128, sizeof(*r->xtab)); + assert((unsigned int)*kp < 128); + free(r->xtab[(int)*kp].p); + r->xtab[(int)*kp].sz = mandoc_asprintf(&r->xtab[(int)*kp].p, + "%s%s", vp, font ? "\fP" : ""); + } else { + roff_setstrn(&r->xmbtab, kp, ksz, vp, vsz, 0); + if (font) + roff_setstrn(&r->xmbtab, kp, ksz, "\\fP", 3, 1); + } return ROFF_IGN; }