=================================================================== RCS file: /cvs/mandoc/man_macro.c,v retrieving revision 1.106 retrieving revision 1.141 diff -u -p -r1.106 -r1.141 --- mandoc/man_macro.c 2015/04/19 13:50:25 1.106 +++ mandoc/man_macro.c 2018/12/31 08:03:46 1.141 @@ -1,7 +1,7 @@ -/* $Id: man_macro.c,v 1.106 2015/04/19 13:50:25 schwarze Exp $ */ +/* $Id: man_macro.c,v 1.141 2018/12/31 08:03:46 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2012, 2013, 2014, 2015 Ingo Schwarze + * Copyright (c) 2012-2015, 2017, 2018 Ingo Schwarze * Copyright (c) 2013 Franco Fichtner * * Permission to use, copy, modify, and distribute this software for any @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -38,51 +39,55 @@ static void blk_imp(MACRO_PROT_ARGS); static void in_line_eoln(MACRO_PROT_ARGS); static int man_args(struct roff_man *, int, int *, char *, char **); -static void rew_scope(struct roff_man *, int); +static void rew_scope(struct roff_man *, enum roff_tok); -const struct man_macro __man_macros[MAN_MAX] = { - { in_line_eoln, MAN_NSCOPED }, /* br */ - { in_line_eoln, MAN_BSCOPE }, /* TH */ - { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */ - { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */ - { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* TP */ - { blk_imp, MAN_BSCOPE }, /* LP */ - { blk_imp, MAN_BSCOPE }, /* PP */ - { blk_imp, MAN_BSCOPE }, /* P */ - { blk_imp, MAN_BSCOPE }, /* IP */ - { blk_imp, MAN_BSCOPE }, /* HP */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SM */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */ +static const struct man_macro man_macros[MAN_MAX - MAN_TH] = { + { in_line_eoln, MAN_XSCOPE }, /* TH */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SH */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SS */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TP */ + { blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TQ */ + { blk_imp, MAN_XSCOPE }, /* LP */ + { blk_imp, MAN_XSCOPE }, /* PP */ + { blk_imp, MAN_XSCOPE }, /* P */ + { blk_imp, MAN_XSCOPE }, /* IP */ + { blk_imp, MAN_XSCOPE }, /* HP */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SM */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SB */ { in_line_eoln, 0 }, /* BI */ { in_line_eoln, 0 }, /* IB */ { in_line_eoln, 0 }, /* BR */ { in_line_eoln, 0 }, /* RB */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* R */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */ - { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* R */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* B */ + { in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* I */ { in_line_eoln, 0 }, /* IR */ { in_line_eoln, 0 }, /* RI */ - { in_line_eoln, MAN_NSCOPED }, /* sp */ - { in_line_eoln, MAN_BSCOPE }, /* nf */ - { in_line_eoln, MAN_BSCOPE }, /* fi */ - { blk_close, MAN_BSCOPE }, /* RE */ - { blk_exp, MAN_BSCOPE }, /* RS */ + { blk_close, MAN_XSCOPE }, /* RE */ + { blk_exp, MAN_XSCOPE }, /* RS */ { in_line_eoln, 0 }, /* DT */ { in_line_eoln, 0 }, /* UC */ { in_line_eoln, MAN_NSCOPED }, /* PD */ { in_line_eoln, 0 }, /* AT */ - { in_line_eoln, 0 }, /* in */ - { in_line_eoln, 0 }, /* ft */ + { in_line_eoln, MAN_NSCOPED }, /* in */ + { blk_imp, MAN_XSCOPE }, /* SY */ + { blk_close, MAN_XSCOPE }, /* YS */ { in_line_eoln, 0 }, /* OP */ - { in_line_eoln, MAN_BSCOPE }, /* EX */ - { in_line_eoln, MAN_BSCOPE }, /* EE */ - { blk_exp, MAN_BSCOPE }, /* UR */ - { blk_close, MAN_BSCOPE }, /* UE */ - { in_line_eoln, 0 }, /* ll */ + { in_line_eoln, MAN_XSCOPE }, /* EX */ + { in_line_eoln, MAN_XSCOPE }, /* EE */ + { blk_exp, MAN_XSCOPE }, /* UR */ + { blk_close, MAN_XSCOPE }, /* UE */ + { blk_exp, MAN_XSCOPE }, /* MT */ + { blk_close, MAN_XSCOPE }, /* ME */ }; -const struct man_macro * const man_macros = __man_macros; +const struct man_macro * +man_macro(enum roff_tok tok) +{ + assert(tok >= MAN_TH && tok <= MAN_MAX); + return man_macros + (tok - MAN_TH); +} void man_unscope(struct roff_man *man, const struct roff_node *to) @@ -95,13 +100,13 @@ man_unscope(struct roff_man *man, const struct roff_no /* Reached the end of the document? */ - if (to == NULL && ! (n->flags & MAN_VALID)) { + if (to == NULL && ! (n->flags & NODE_VALID)) { if (man->flags & (MAN_BLINE | MAN_ELINE) && - man_macros[n->tok].flags & MAN_SCOPED) { - mandoc_vmsg(MANDOCERR_BLK_LINE, - man->parse, n->line, n->pos, - "EOF breaks %s", - man_macronames[n->tok]); + man_macro(n->tok)->flags & + (MAN_BSCOPED | MAN_NSCOPED)) { + mandoc_msg(MANDOCERR_BLK_LINE, + n->line, n->pos, + "EOF breaks %s", roff_name[n->tok]); if (man->flags & MAN_ELINE) man->flags &= ~MAN_ELINE; else { @@ -115,10 +120,10 @@ man_unscope(struct roff_man *man, const struct roff_no continue; } if (n->type == ROFFT_BLOCK && - man_macros[n->tok].fp == blk_exp) + man_macro(n->tok)->fp == blk_exp) mandoc_msg(MANDOCERR_BLK_NOEND, - man->parse, n->line, n->pos, - man_macronames[n->tok]); + n->line, n->pos, "%s", + roff_name[n->tok]); } /* @@ -130,7 +135,7 @@ man_unscope(struct roff_man *man, const struct roff_no man->last = n; n = n->parent; - man_valid_post(man); + man->last->flags |= NODE_VALID; } /* @@ -150,21 +155,21 @@ man_unscope(struct roff_man *man, const struct roff_no * scopes. When a scope is closed, it must be validated and actioned. */ static void -rew_scope(struct roff_man *man, int tok) +rew_scope(struct roff_man *man, enum roff_tok tok) { struct roff_node *n; /* Preserve empty paragraphs before RS. */ n = man->last; - if (tok == MAN_RS && n->nchild == 0 && + if (tok == MAN_RS && n->child == NULL && (n->tok == MAN_P || n->tok == MAN_PP || n->tok == MAN_LP)) return; for (;;) { if (n->type == ROFFT_ROOT) return; - if (n->flags & MAN_VALID) { + if (n->flags & NODE_VALID) { n = n->parent; continue; } @@ -179,7 +184,7 @@ rew_scope(struct roff_man *man, int tok) } if (tok != MAN_SH && (n->tok == MAN_SH || (tok != MAN_SS && (n->tok == MAN_SS || - man_macros[n->tok].fp == blk_exp)))) + man_macro(n->tok)->fp == blk_exp)))) return; man_unscope(man, n); n = man->last; @@ -193,39 +198,47 @@ rew_scope(struct roff_man *man, int tok) void blk_close(MACRO_PROT_ARGS) { - int ntok; + enum roff_tok ctok, ntok; const struct roff_node *nn; - char *p; - int nrew, target; + char *p, *ep; + int cline, cpos, la, nrew, target; nrew = 1; switch (tok) { case MAN_RE: ntok = MAN_RS; + la = *pos; if ( ! man_args(man, line, pos, buf, &p)) break; for (nn = man->last->parent; nn; nn = nn->parent) if (nn->tok == ntok && nn->type == ROFFT_BLOCK) nrew++; - target = strtol(p, &p, 10); - if (*p != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, - line, p - buf, "RE ... %s", p); + target = strtol(p, &ep, 10); + if (*ep != '\0') + mandoc_msg(MANDOCERR_ARG_EXCESS, line, + la + (buf[la] == '"') + (int)(ep - p), + "RE ... %s", ep); + free(p); if (target == 0) target = 1; nrew -= target; if (nrew < 1) { - mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse, + mandoc_msg(MANDOCERR_RE_NOTOPEN, line, ppos, "RE %d", target); return; } break; + case MAN_YS: + ntok = MAN_SY; + break; case MAN_UE: ntok = MAN_UR; break; + case MAN_ME: + ntok = MAN_MT; + break; default: abort(); - /* NOTREACHED */ } for (nn = man->last->parent; nn; nn = nn->parent) @@ -233,22 +246,48 @@ blk_close(MACRO_PROT_ARGS) break; if (nn == NULL) { - mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse, - line, ppos, man_macronames[tok]); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, + line, ppos, "%s", roff_name[tok]); rew_scope(man, MAN_PP); - } else { - line = man->last->line; - ppos = man->last->pos; - ntok = man->last->tok; - man_unscope(man, nn); + if (tok == MAN_RE) { + roff_elem_alloc(man, line, ppos, ROFF_br); + man->last->flags |= NODE_LINE | + NODE_VALID | NODE_ENDED; + man->next = ROFF_NEXT_SIBLING; + } + return; + } - /* Move a trailing paragraph behind the block. */ + cline = man->last->line; + cpos = man->last->pos; + ctok = man->last->tok; + man_unscope(man, nn); - if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) { - *pos = strlen(buf); - blk_imp(man, ntok, line, ppos, pos, buf); - } + if (tok == MAN_RE && nn->head->aux > 0) + roff_setreg(man->roff, "an-margin", nn->head->aux, '-'); + + /* Trailing text. */ + + if (buf[*pos] != '\0') { + roff_word_alloc(man, line, ppos, buf + *pos); + man->last->flags |= NODE_DELIMC; + if (mandoc_eos(man->last->string, strlen(man->last->string))) + man->last->flags |= NODE_EOS; } + + /* Move a trailing paragraph behind the block. */ + + if (ctok == MAN_LP || ctok == MAN_PP || ctok == MAN_P) { + *pos = strlen(buf); + blk_imp(man, ctok, cline, cpos, pos, buf); + } + + /* Synopsis blocks need an explicit end marker for spacing. */ + + if (tok == MAN_YS && man->last == nn) { + roff_elem_alloc(man, line, ppos, tok); + man_unscope(man, man->last); + } } void @@ -258,18 +297,28 @@ blk_exp(MACRO_PROT_ARGS) char *p; int la; - rew_scope(man, tok); - man_block_alloc(man, line, ppos, tok); + if (tok == MAN_RS) + rew_scope(man, tok); + roff_block_alloc(man, line, ppos, tok); head = roff_head_alloc(man, line, ppos, tok); la = *pos; - if (man_args(man, line, pos, buf, &p)) - man_word_alloc(man, line, la, p); + if (man_args(man, line, pos, buf, &p)) { + roff_word_alloc(man, line, la, p); + if (tok == MAN_RS) { + if (roff_getreg(man->roff, "an-margin") == 0) + roff_setreg(man->roff, "an-margin", + 7 * 24, '='); + if ((head->aux = strtod(p, NULL) * 24.0) > 0) + roff_setreg(man->roff, "an-margin", + head->aux, '+'); + } + free(p); + } if (buf[*pos] != '\0') - mandoc_vmsg(MANDOCERR_ARG_EXCESS, - man->parse, line, *pos, "%s ... %s", - man_macronames[tok], buf + *pos); + mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos, + "%s ... %s", roff_name[tok], buf + *pos); man_unscope(man, head); roff_body_alloc(man, line, ppos, tok); @@ -289,10 +338,9 @@ blk_imp(MACRO_PROT_ARGS) struct roff_node *n; rew_scope(man, tok); - man_block_alloc(man, line, ppos, tok); - n = man->last; - if (n->tok == MAN_SH || n->tok == MAN_SS) - man->flags &= ~MAN_LITERAL; + if (tok == MAN_SH || tok == MAN_SS) + man->flags &= ~ROFF_NOFILL; + roff_block_alloc(man, line, ppos, tok); n = roff_head_alloc(man, line, ppos, tok); /* Add line arguments. */ @@ -301,17 +349,18 @@ blk_imp(MACRO_PROT_ARGS) la = *pos; if ( ! man_args(man, line, pos, buf, &p)) break; - man_word_alloc(man, line, la, p); + roff_word_alloc(man, line, la, p); + free(p); } /* * For macros having optional next-line scope, * keep the head open if there were no arguments. - * For `TP', always keep the head open. + * For `TP' and `TQ', always keep the head open. */ - if (man_macros[tok].flags & MAN_SCOPED && - (tok == MAN_TP || n == man->last)) { + if (man_macro(tok)->flags & MAN_BSCOPED && + (tok == MAN_TP || tok == MAN_TQ || n == man->last)) { man->flags |= MAN_BLINE; return; } @@ -329,51 +378,47 @@ in_line_eoln(MACRO_PROT_ARGS) char *p; struct roff_node *n; - man_elem_alloc(man, line, ppos, tok); + roff_elem_alloc(man, line, ppos, tok); n = man->last; + if (tok == MAN_EX) + man->flags |= ROFF_NOFILL; + else if (tok == MAN_EE) + man->flags &= ~ROFF_NOFILL; + for (;;) { - if (buf[*pos] != '\0' && (tok == MAN_br || - tok == MAN_fi || tok == MAN_nf)) { - mandoc_vmsg(MANDOCERR_ARG_SKIP, - man->parse, line, *pos, "%s %s", - man_macronames[tok], buf + *pos); + if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) { + mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos, + "%s ... %s", roff_name[tok], buf + *pos); break; } - if (buf[*pos] != '\0' && man->last != n && - (tok == MAN_PD || tok == MAN_ft || tok == MAN_sp)) { - mandoc_vmsg(MANDOCERR_ARG_EXCESS, - man->parse, line, *pos, "%s ... %s", - man_macronames[tok], buf + *pos); - break; - } la = *pos; if ( ! man_args(man, line, pos, buf, &p)) break; - if (man_macros[tok].flags & MAN_JOIN && + if (man_macro(tok)->flags & MAN_JOIN && man->last->type == ROFFT_TEXT) - man_word_append(man, p); + roff_word_append(man, p); else - man_word_alloc(man, line, la, p); + roff_word_alloc(man, line, la, p); + free(p); } /* - * Append MAN_EOS in case the last snipped argument + * Append NODE_EOS in case the last snipped argument * ends with a dot, e.g. `.IR syslog (3).' */ if (n != man->last && mandoc_eos(man->last->string, strlen(man->last->string))) - man->last->flags |= MAN_EOS; + man->last->flags |= NODE_EOS; /* - * If no arguments are specified and this is MAN_SCOPED (i.e., + * If no arguments are specified and this is MAN_ESCOPED (i.e., * next-line scoped), then set our mode to indicate that we're * waiting for terms to load into our context. */ - if (n == man->last && man_macros[tok].flags & MAN_SCOPED) { - assert( ! (man_macros[tok].flags & MAN_NSCOPED)); + if (n == man->last && man_macro(tok)->flags & MAN_ESCOPED) { man->flags |= MAN_ELINE; return; } @@ -381,36 +426,24 @@ in_line_eoln(MACRO_PROT_ARGS) assert(man->last->type != ROFFT_ROOT); man->next = ROFF_NEXT_SIBLING; - /* - * Rewind our element scope. Note that when TH is pruned, we'll - * be back at the root, so make sure that we don't clobber as - * its sibling. - */ + /* Rewind our element scope. */ for ( ; man->last; man->last = man->last->parent) { + man_state(man, man->last); if (man->last == n) break; - if (man->last->type == ROFFT_ROOT) - break; - man_valid_post(man); } - assert(man->last); + /* Rewind next-line scoped ancestors, if any. */ - /* - * Same here regarding whether we're back at the root. - */ - - if (man->last->type != ROFFT_ROOT) - man_valid_post(man); + if (man_macro(tok)->flags & MAN_ESCOPED) + man_descope(man, line, ppos, NULL); } - void -man_macroend(struct roff_man *man) +man_endparse(struct roff_man *man) { - - man_unscope(man, man->first); + man_unscope(man, man->meta.first); } static int @@ -423,8 +456,8 @@ man_args(struct roff_man *man, int line, int *pos, cha assert(' ' != *start); if ('\0' == *start) - return(0); + return 0; - *v = mandoc_getarg(man->parse, v, line, pos); - return(1); + *v = roff_getarg(man->roff, v, line, pos); + return 1; }