=================================================================== RCS file: /cvs/mandoc/mdoc_macro.c,v retrieving revision 1.191 retrieving revision 1.216 diff -u -p -r1.191 -r1.216 --- mandoc/mdoc_macro.c 2015/04/19 14:00:19 1.191 +++ mandoc/mdoc_macro.c 2017/02/16 03:00:23 1.216 @@ -1,7 +1,7 @@ -/* $Id: mdoc_macro.c,v 1.191 2015/04/19 14:00:19 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.216 2017/02/16 03:00:23 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010, 2012-2015 Ingo Schwarze + * Copyright (c) 2010, 2012-2017 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -50,6 +50,8 @@ static int find_pending(struct roff_man *, int, int, struct roff_node *); static int lookup(struct roff_man *, int, int, int, const char *); static int macro_or_word(MACRO_PROT_ARGS, int); +static void break_intermediate(struct roff_node *, + struct roff_node *); static int parse_rest(struct roff_man *, int, int, int *, char *); static int rew_alt(int); static void rew_elem(struct roff_man *, int); @@ -210,13 +212,13 @@ const struct mdoc_macro * const mdoc_macros = __mdoc_m * are errors. */ void -mdoc_macroend(struct roff_man *mdoc) +mdoc_endparse(struct roff_man *mdoc) { struct roff_node *n; /* Scan for open explicit scopes. */ - n = mdoc->last->flags & MDOC_VALID ? + n = mdoc->last->flags & NODE_VALID ? mdoc->last->parent : mdoc->last; for ( ; n; n = n->parent) @@ -228,6 +230,7 @@ mdoc_macroend(struct roff_man *mdoc) /* Rewind to the first. */ rew_last(mdoc, mdoc->first); + mdoc_state_reset(mdoc); } /* @@ -239,17 +242,21 @@ lookup(struct roff_man *mdoc, int from, int line, int { int res; + if (mdoc->flags & MDOC_PHRASEQF) { + mdoc->flags &= ~MDOC_PHRASEQF; + return TOKEN_NONE; + } if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) { res = mdoc_hash_find(p); if (res != TOKEN_NONE) { if (mdoc_macros[res].flags & MDOC_CALLABLE) - return(res); + return res; if (res != MDOC_br && res != MDOC_sp && res != MDOC_ll) mandoc_msg(MANDOCERR_MACRO_CALL, mdoc->parse, line, ppos, p); } } - return(TOKEN_NONE); + return TOKEN_NONE; } /* @@ -258,27 +265,18 @@ lookup(struct roff_man *mdoc, int from, int line, int static void rew_last(struct roff_man *mdoc, const struct roff_node *to) { - struct roff_node *n, *np; - if (to->flags & MDOC_VALID) + if (to->flags & NODE_VALID) return; - mdoc->next = ROFF_NEXT_SIBLING; while (mdoc->last != to) { - /* - * Save the parent here, because we may delete the - * mdoc->last node in the post-validation phase and reset - * it to mdoc->last->parent, causing a step in the closing - * out to be lost. - */ - np = mdoc->last->parent; - mdoc_valid_post(mdoc); - n = mdoc->last; - mdoc->last = np; - assert(mdoc->last); - mdoc->last->last = n; + mdoc_state(mdoc, mdoc->last); + mdoc->last->flags |= NODE_VALID | NODE_ENDED; + mdoc->last = mdoc->last->parent; } - mdoc_valid_post(mdoc); + mdoc_state(mdoc, mdoc->last); + mdoc->last->flags |= NODE_VALID | NODE_ENDED; + mdoc->next = ROFF_NEXT_SIBLING; } /* @@ -291,26 +289,29 @@ rew_pending(struct roff_man *mdoc, const struct roff_n for (;;) { rew_last(mdoc, n); - switch (n->type) { - case ROFFT_HEAD: - roff_body_alloc(mdoc, n->line, n->pos, n->tok); - return; - case ROFFT_BLOCK: - break; - default: - return; - } + if (mdoc->last == n) { + switch (n->type) { + case ROFFT_HEAD: + roff_body_alloc(mdoc, n->line, n->pos, + n->tok); + break; + case ROFFT_BLOCK: + break; + default: + return; + } + if ( ! (n->flags & NODE_BROKEN)) + return; + } else + n = mdoc->last; - if ( ! (n->flags & MDOC_BROKEN)) - return; - for (;;) { if ((n = n->parent) == NULL) return; if (n->type == ROFFT_BLOCK || n->type == ROFFT_HEAD) { - if (n->flags & MDOC_ENDED) + if (n->flags & NODE_ENDED) break; else return; @@ -328,41 +329,40 @@ rew_alt(int tok) { switch (tok) { case MDOC_Ac: - return(MDOC_Ao); + return MDOC_Ao; case MDOC_Bc: - return(MDOC_Bo); + return MDOC_Bo; case MDOC_Brc: - return(MDOC_Bro); + return MDOC_Bro; case MDOC_Dc: - return(MDOC_Do); + return MDOC_Do; case MDOC_Ec: - return(MDOC_Eo); + return MDOC_Eo; case MDOC_Ed: - return(MDOC_Bd); + return MDOC_Bd; case MDOC_Ef: - return(MDOC_Bf); + return MDOC_Bf; case MDOC_Ek: - return(MDOC_Bk); + return MDOC_Bk; case MDOC_El: - return(MDOC_Bl); + return MDOC_Bl; case MDOC_Fc: - return(MDOC_Fo); + return MDOC_Fo; case MDOC_Oc: - return(MDOC_Oo); + return MDOC_Oo; case MDOC_Pc: - return(MDOC_Po); + return MDOC_Po; case MDOC_Qc: - return(MDOC_Qo); + return MDOC_Qo; case MDOC_Re: - return(MDOC_Rs); + return MDOC_Rs; case MDOC_Sc: - return(MDOC_So); + return MDOC_So; case MDOC_Xc: - return(MDOC_Xo); + return MDOC_Xo; default: - return(tok); + return tok; } - /* NOTREACHED */ } static void @@ -378,6 +378,16 @@ rew_elem(struct roff_man *mdoc, int tok) rew_last(mdoc, n); } +static void +break_intermediate(struct roff_node *n, struct roff_node *breaker) +{ + while (n != breaker) { + if ( ! (n->flags & NODE_VALID)) + n->flags |= NODE_BROKEN; + n = n->parent; + } +} + /* * If there is an open sub-block of the target requiring * explicit close-out, postpone closing out the target until @@ -390,30 +400,31 @@ find_pending(struct roff_man *mdoc, int tok, int line, struct roff_node *n; int irc; + if (target->flags & NODE_VALID) + return 0; + irc = 0; for (n = mdoc->last; n != NULL && n != target; n = n->parent) { - if (n->flags & MDOC_ENDED) { - if ( ! (n->flags & MDOC_VALID)) - n->flags |= MDOC_BROKEN; + if (n->flags & NODE_ENDED) continue; - } if (n->type == ROFFT_BLOCK && mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { irc = 1; - n->flags = MDOC_BROKEN; + break_intermediate(mdoc->last, n); + n->flags |= NODE_BROKEN; if (target->type == ROFFT_HEAD) - target->flags = MDOC_ENDED; - else if ( ! (target->flags & MDOC_ENDED)) { + target->flags |= NODE_ENDED; + else if ( ! (target->flags & NODE_ENDED)) { mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[n->tok]); mdoc_endbody_alloc(mdoc, line, ppos, - tok, target, ENDBODY_NOSPACE); + tok, target); } } } - return(irc); + return irc; } /* @@ -432,11 +443,11 @@ dword(struct roff_man *mdoc, int line, int col, const ! (mdoc->flags & (MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF)) && d == DELIM_NONE && mdoc->last->type == ROFFT_TEXT && mdoc_isdelim(mdoc->last->string) == DELIM_NONE) { - mdoc_word_append(mdoc, p); + roff_word_append(mdoc, p); return; } - mdoc_word_alloc(mdoc, line, col, p); + roff_word_alloc(mdoc, line, col, p); /* * If the word consists of a bare delimiter, @@ -446,11 +457,11 @@ dword(struct roff_man *mdoc, int line, int col, const */ if (d == DELIM_OPEN) - mdoc->last->flags |= MDOC_DELIMO; + mdoc->last->flags |= NODE_DELIMO; else if (d == DELIM_CLOSE && ! (mdoc->flags & MDOC_NODELIMC) && mdoc->last->parent->tok != MDOC_Fd) - mdoc->last->flags |= MDOC_DELIMC; + mdoc->last->flags |= NODE_DELIMC; mdoc->flags &= ~MDOC_NODELIMC; } @@ -483,7 +494,7 @@ append_delims(struct roff_man *mdoc, int line, int *po */ if (mandoc_eos(p, strlen(p))) - mdoc->last->flags |= MDOC_EOS; + mdoc->last->flags |= NODE_EOS; } } @@ -508,14 +519,14 @@ macro_or_word(MACRO_PROT_ARGS, int parsed) if (ntok == TOKEN_NONE) { dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE || mdoc_macros[tok].flags & MDOC_JOIN); - return(0); + return 0; } else { if (mdoc_macros[tok].fp == in_line_eoln) rew_elem(mdoc, tok); mdoc_macro(mdoc, ntok, line, ppos, pos, buf); if (tok == TOKEN_NONE) append_delims(mdoc, line, pos, buf); - return(1); + return 1; } } @@ -551,30 +562,46 @@ blk_exp_close(MACRO_PROT_ARGS) break; } + /* Search backwards for the beginning of our own body. */ + + atok = rew_alt(tok); + body = NULL; + for (n = mdoc->last; n; n = n->parent) { + if (n->flags & NODE_ENDED || n->tok != atok || + n->type != ROFFT_BODY || n->end != ENDBODY_NOT) + continue; + body = n; + break; + } + /* * Search backwards for beginnings of blocks, * both of our own and of pending sub-blocks. */ - atok = rew_alt(tok); - body = endbody = itblk = later = NULL; + endbody = itblk = later = NULL; for (n = mdoc->last; n; n = n->parent) { - if (n->flags & MDOC_ENDED) { - if ( ! (n->flags & MDOC_VALID)) - n->flags |= MDOC_BROKEN; + if (n->flags & NODE_ENDED) continue; - } - /* Remember the start of our own body. */ + /* + * Mismatching end macros can never break anything + * and we only care about the breaking of BLOCKs. + */ - if (n->type == ROFFT_BODY && atok == n->tok) { - if (n->end == ENDBODY_NOT) - body = n; + if (body == NULL || n->type != ROFFT_BLOCK) continue; - } - if (n->type != ROFFT_BLOCK || n->tok == MDOC_Nm) + /* + * SYNOPSIS name blocks can not be broken themselves, + * but they do get broken together with a broken child. + */ + + if (n->tok == MDOC_Nm) { + if (later != NULL) + n->flags |= NODE_BROKEN | NODE_ENDED; continue; + } if (n->tok == MDOC_It) { itblk = n; @@ -582,7 +609,6 @@ blk_exp_close(MACRO_PROT_ARGS) } if (atok == n->tok) { - assert(body); /* * Found the start of our own block. @@ -608,10 +634,10 @@ blk_exp_close(MACRO_PROT_ARGS) mdoc_macronames[later->tok]); endbody = mdoc_endbody_alloc(mdoc, line, ppos, - atok, body, ENDBODY_SPACE); + atok, body); if (tok == MDOC_El) - itblk->flags |= MDOC_ENDED | MDOC_BROKEN; + itblk->flags |= NODE_ENDED | NODE_BROKEN; /* * If a block closing macro taking arguments @@ -624,16 +650,23 @@ blk_exp_close(MACRO_PROT_ARGS) break; } - /* Explicit blocks close out description lines. */ + /* + * Explicit blocks close out description lines, but + * even those can get broken together with a child. + */ if (n->tok == MDOC_Nd) { - rew_last(mdoc, n); + if (later != NULL) + n->flags |= NODE_BROKEN | NODE_ENDED; + else + rew_last(mdoc, n); continue; } /* Breaking an open sub block. */ - n->flags |= MDOC_BROKEN; + break_intermediate(mdoc->last, body); + n->flags |= NODE_BROKEN; if (later == NULL) later = n; } @@ -646,7 +679,7 @@ blk_exp_close(MACRO_PROT_ARGS) * Stray .Ec without previous .Eo: * Break the output line, keep the arguments. */ - mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL); + roff_elem_alloc(mdoc, line, ppos, MDOC_br); rew_elem(mdoc, MDOC_br); } } else if (endbody == NULL) { @@ -668,6 +701,8 @@ blk_exp_close(MACRO_PROT_ARGS) if (endbody != NULL) n = endbody; + + ntok = TOKEN_NONE; for (j = 0; ; j++) { lastarg = *pos; @@ -695,15 +730,14 @@ blk_exp_close(MACRO_PROT_ARGS) } if (n != NULL) { - if (n != mdoc->last && n->flags & MDOC_BROKEN) { + pending = 0; + if (ntok != TOKEN_NONE && n->flags & NODE_BROKEN) { target = n; do target = target->parent; - while ( ! (target->flags & MDOC_ENDED)); - pending = find_pending(mdoc, ntok, line, ppos, - target); - } else - pending = 0; + while ( ! (target->flags & NODE_ENDED)); + pending = find_pending(mdoc, ntok, line, ppos, target); + } if ( ! pending) rew_pending(mdoc, n); } @@ -730,15 +764,10 @@ in_line(MACRO_PROT_ARGS) switch (tok) { case MDOC_An: - /* FALLTHROUGH */ case MDOC_Ar: - /* FALLTHROUGH */ case MDOC_Fl: - /* FALLTHROUGH */ case MDOC_Mt: - /* FALLTHROUGH */ case MDOC_Nm: - /* FALLTHROUGH */ case MDOC_Pa: nc = 1; break; @@ -763,7 +792,7 @@ in_line(MACRO_PROT_ARGS) if (ac == ARGS_EOLN) { if (d == DELIM_OPEN) - mdoc->last->flags &= ~MDOC_DELIMO; + mdoc->last->flags &= ~NODE_DELIMO; break; } @@ -857,7 +886,7 @@ in_line(MACRO_PROT_ARGS) */ if (firstarg && d == DELIM_CLOSE && !nc) - mdoc->last->flags &= ~MDOC_DELIMC; + mdoc->last->flags &= ~NODE_DELIMC; firstarg = 0; /* @@ -920,9 +949,9 @@ blk_full(MACRO_PROT_ARGS) blk = NULL; for (n = mdoc->last; n != NULL; n = n->parent) { - if (n->flags & MDOC_ENDED) { - if ( ! (n->flags & MDOC_VALID)) - n->flags |= MDOC_BROKEN; + if (n->flags & NODE_ENDED) { + if ( ! (n->flags & NODE_VALID)) + n->flags |= NODE_BROKEN; continue; } if (n->type != ROFFT_BLOCK) @@ -942,7 +971,6 @@ blk_full(MACRO_PROT_ARGS) if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { switch (tok) { case MDOC_Sh: - /* FALLTHROUGH */ case MDOC_Ss: mandoc_vmsg(MANDOCERR_BLK_BROKEN, mdoc->parse, line, ppos, @@ -982,7 +1010,7 @@ blk_full(MACRO_PROT_ARGS) /* Close out prior implicit scopes. */ - rew_last(mdoc, n); + rew_pending(mdoc, n); } /* Skip items outside lists. */ @@ -990,7 +1018,7 @@ blk_full(MACRO_PROT_ARGS) if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) { mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse, line, ppos, "It %s", buf + *pos); - mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL); + roff_elem_alloc(mdoc, line, ppos, MDOC_br); rew_elem(mdoc, MDOC_br); return; } @@ -1032,26 +1060,39 @@ blk_full(MACRO_PROT_ARGS) if (tok == MDOC_Bk) mdoc->flags |= MDOC_KEEP; - ac = ARGS_PEND; + ac = ARGS_EOLN; for (;;) { + + /* + * If we are right after a tab character, + * do not parse the first word for macros. + */ + + if (mdoc->flags & MDOC_PHRASEQN) { + mdoc->flags &= ~MDOC_PHRASEQN; + mdoc->flags |= MDOC_PHRASEQF; + } + la = *pos; lac = ac; ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ac == ARGS_EOLN) { - if (lac != ARGS_PPHRASE && lac != ARGS_PHRASE) + if (lac != ARGS_PHRASE || + ! (mdoc->flags & MDOC_PHRASEQF)) break; + /* - * This is necessary: if the last token on a - * line is a `Ta' or tab, then we'll get - * ARGS_EOLN, so we must be smart enough to - * reopen our scope if the last parse was a - * phrase or partial phrase. + * This line ends in a tab; start the next + * column now, with a leading blank. */ + if (body != NULL) rew_last(mdoc, body); body = roff_body_alloc(mdoc, line, ppos, tok); + roff_word_alloc(mdoc, line, ppos, "\\&"); break; } + if (tok == MDOC_Bd || tok == MDOC_Bk) { mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, line, la, "%s ... %s", @@ -1072,9 +1113,7 @@ blk_full(MACRO_PROT_ARGS) */ if (head == NULL && - ac != ARGS_PEND && ac != ARGS_PHRASE && - ac != ARGS_PPHRASE && ac != ARGS_QWORD && mdoc_isdelim(p) == DELIM_OPEN) { dword(mdoc, line, la, p, DELIM_OPEN, 0); @@ -1086,9 +1125,7 @@ blk_full(MACRO_PROT_ARGS) if (head == NULL) head = roff_head_alloc(mdoc, line, ppos, tok); - if (ac == ARGS_PHRASE || - ac == ARGS_PEND || - ac == ARGS_PPHRASE) { + if (ac == ARGS_PHRASE) { /* * If we haven't opened a body yet, rewind the @@ -1098,18 +1135,16 @@ blk_full(MACRO_PROT_ARGS) rew_last(mdoc, body == NULL ? head : body); body = roff_body_alloc(mdoc, line, ppos, tok); - /* - * Process phrases: set whether we're in a - * partial-phrase (this effects line handling) - * then call down into the phrase parser. - */ + /* Process to the tab or to the end of the line. */ - if (ac == ARGS_PPHRASE) - mdoc->flags |= MDOC_PPHRASE; - if (ac == ARGS_PEND && lac == ARGS_PPHRASE) - mdoc->flags |= MDOC_PPHRASE; + mdoc->flags |= MDOC_PHRASE; parse_rest(mdoc, TOKEN_NONE, line, &la, buf); - mdoc->flags &= ~MDOC_PPHRASE; + mdoc->flags &= ~MDOC_PHRASE; + + /* There may have been `Ta' macros. */ + + while (body->next != NULL) + body = body->next; continue; } @@ -1117,7 +1152,7 @@ blk_full(MACRO_PROT_ARGS) break; } - if (blk->flags & MDOC_VALID) + if (blk->flags & NODE_VALID) return; if (head == NULL) head = roff_head_alloc(mdoc, line, ppos, tok); @@ -1223,7 +1258,7 @@ blk_part_exp(MACRO_PROT_ARGS) * case of `Eo'); and a body that may be empty. */ - mdoc_block_alloc(mdoc, line, ppos, tok, NULL); + roff_block_alloc(mdoc, line, ppos, tok); head = NULL; for (;;) { la = *pos; @@ -1285,16 +1320,12 @@ in_line_argn(MACRO_PROT_ARGS) switch (tok) { case MDOC_Ap: - /* FALLTHROUGH */ case MDOC_Ns: - /* FALLTHROUGH */ case MDOC_Ux: maxargs = 0; break; case MDOC_Bx: - /* FALLTHROUGH */ case MDOC_Es: - /* FALLTHROUGH */ case MDOC_Xr: maxargs = 2; break; @@ -1392,7 +1423,7 @@ in_line_eoln(MACRO_PROT_ARGS) if (mdoc->next == ROFF_NEXT_SIBLING) n = n->parent; if (n->tok == MDOC_Nm) - rew_last(mdoc, mdoc->last->parent); + rew_last(mdoc, n->parent); } if (buf[*pos] == '\0' && @@ -1422,9 +1453,9 @@ parse_rest(struct roff_man *mdoc, int tok, int line, i for (;;) { la = *pos; if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN) - return(0); + return 0; if (macro_or_word(mdoc, tok, line, la, pos, buf, 1)) - return(1); + return 1; } } @@ -1456,11 +1487,11 @@ phrase_ta(MACRO_PROT_ARGS) body = NULL; for (n = mdoc->last; n != NULL; n = n->parent) { - if (n->flags & MDOC_ENDED) + if (n->flags & NODE_ENDED) continue; if (n->tok == MDOC_It && n->type == ROFFT_BODY) body = n; - if (n->tok == MDOC_Bl) + if (n->tok == MDOC_Bl && n->end == ENDBODY_NOT) break; }