=================================================================== RCS file: /cvs/mandoc/mdoc_macro.c,v retrieving revision 1.176 retrieving revision 1.185 diff -u -p -r1.176 -r1.185 --- mandoc/mdoc_macro.c 2015/02/05 01:46:56 1.176 +++ mandoc/mdoc_macro.c 2015/04/02 22:48:17 1.185 @@ -1,4 +1,4 @@ -/* $Id: mdoc_macro.c,v 1.176 2015/02/05 01:46:56 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.185 2015/04/02 22:48:17 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010, 2012-2015 Ingo Schwarze @@ -7,9 +7,9 @@ * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF @@ -26,10 +26,11 @@ #include #include -#include "mdoc.h" #include "mandoc.h" -#include "libmdoc.h" +#include "roff.h" +#include "mdoc.h" #include "libmandoc.h" +#include "libmdoc.h" static void blk_full(MACRO_PROT_ARGS); static void blk_exp_close(MACRO_PROT_ARGS); @@ -44,17 +45,13 @@ static void phrase_ta(MACRO_PROT_ARGS); static void dword(struct mdoc *, int, int, const char *, enum mdelim, int); static void append_delims(struct mdoc *, int, int *, char *); -static enum mdoct lookup(struct mdoc *, enum mdoct, - int, int, const char *); +static int lookup(struct mdoc *, int, int, int, const char *); static int macro_or_word(MACRO_PROT_ARGS, int); -static void make_pending(struct mdoc *, struct mdoc_node *, - struct mdoc_node *, int, int); -static int parse_rest(struct mdoc *, enum mdoct, - int, int *, char *); -static enum mdoct rew_alt(enum mdoct); -static void rew_elem(struct mdoc *, enum mdoct); -static void rew_last(struct mdoc *, const struct mdoc_node *); -static void rew_pending(struct mdoc *, const struct mdoc_node *); +static int parse_rest(struct mdoc *, int, int, int *, char *); +static int rew_alt(int); +static void rew_elem(struct mdoc *, int); +static void rew_last(struct mdoc *, const struct roff_node *); +static void rew_pending(struct mdoc *, const struct roff_node *); const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */ @@ -211,7 +208,7 @@ const struct mdoc_macro * const mdoc_macros = __mdoc_m void mdoc_macroend(struct mdoc *mdoc) { - struct mdoc_node *n; + struct roff_node *n; /* Scan for open explicit scopes. */ @@ -219,7 +216,7 @@ mdoc_macroend(struct mdoc *mdoc) mdoc->last->parent : mdoc->last; for ( ; n; n = n->parent) - if (n->type == MDOC_BLOCK && + if (n->type == ROFFT_BLOCK && mdoc_macros[n->tok].flags & MDOC_EXPLICIT) mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse, n->line, n->pos, mdoc_macronames[n->tok]); @@ -233,10 +230,10 @@ mdoc_macroend(struct mdoc *mdoc) * Look up the macro at *p called by "from", * or as a line macro if from == MDOC_MAX. */ -static enum mdoct -lookup(struct mdoc *mdoc, enum mdoct from, int line, int ppos, const char *p) +static int +lookup(struct mdoc *mdoc, int from, int line, int ppos, const char *p) { - enum mdoct res; + int res; if (from == MDOC_MAX || mdoc_macros[from].flags & MDOC_PARSED) { res = mdoc_hash_find(p); @@ -255,9 +252,9 @@ lookup(struct mdoc *mdoc, enum mdoct from, int line, i * Rewind up to and including a specific node. */ static void -rew_last(struct mdoc *mdoc, const struct mdoc_node *to) +rew_last(struct mdoc *mdoc, const struct roff_node *to) { - struct mdoc_node *n, *np; + struct roff_node *n, *np; assert(to); mdoc->next = MDOC_NEXT_SIBLING; @@ -282,18 +279,37 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to * Rewind up to a specific block, including all blocks that broke it. */ static void -rew_pending(struct mdoc *mdoc, const struct mdoc_node *n) +rew_pending(struct mdoc *mdoc, const struct roff_node *n) { - rew_last(mdoc, n); - - if (n->type != MDOC_BLOCK) - return; - - while ((n = n->pending) != NULL) { + for (;;) { rew_last(mdoc, n); - if (n->type == MDOC_HEAD) + + switch (n->type) { + case ROFFT_HEAD: mdoc_body_alloc(mdoc, n->line, n->pos, n->tok); + return; + case ROFFT_BLOCK: + break; + default: + return; + } + + 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) + break; + else + return; + } + } } } @@ -301,8 +317,8 @@ rew_pending(struct mdoc *mdoc, const struct mdoc_node * For a block closing macro, return the corresponding opening one. * Otherwise, return the macro itself. */ -static enum mdoct -rew_alt(enum mdoct tok) +static int +rew_alt(int tok) { switch (tok) { case MDOC_Ac: @@ -344,91 +360,19 @@ rew_alt(enum mdoct tok) } static void -rew_elem(struct mdoc *mdoc, enum mdoct tok) +rew_elem(struct mdoc *mdoc, int tok) { - struct mdoc_node *n; + struct roff_node *n; n = mdoc->last; - if (MDOC_ELEM != n->type) + if (n->type != ROFFT_ELEM) n = n->parent; - assert(MDOC_ELEM == n->type); + assert(n->type == ROFFT_ELEM); assert(tok == n->tok); rew_last(mdoc, n); } /* - * We are trying to close the block *breaker, - * but the child block *broken is still open. - * Thus, postpone closing the *breaker - * until the rew_pending() call closing *broken. - */ -static void -make_pending(struct mdoc *mdoc, struct mdoc_node *breaker, - struct mdoc_node *broken, int line, int ppos) -{ - struct mdoc_node *n; - - mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos, - "%s breaks %s", mdoc_macronames[breaker->tok], - mdoc_macronames[broken->tok]); - - /* - * If the *broken block (Z) is already broken by a block (B) - * contained in the breaker (A), make the breaker pending - * on that inner breaker (B). Graphically, - * - * breaker=[A! broken=n=[B!->A (old broken=)[Z->B B] A] Z] - * - * In these graphics, "->" indicates the "pending" pointer and - * "!" indicates the MDOC_BREAK flag. Each of the cases gets - * one additional pointer (B->A) and one additional flag (A!). - */ - - for (n = broken->parent; ; n = n->parent) - if (n == broken->pending) - broken = n; - else if (n == breaker) - break; - - /* - * Found the breaker. - * - * If another, outer breaker (X) is already pending on - * the *broken block (B), we must not clobber the link - * to the outer breaker, but make it pending on the new, - * now inner breaker (A). Graphically, - * - * [X! n=breaker=[A!->X broken=[B(->X)->A X] A] B]. - */ - - if (broken->pending != NULL) { - n = breaker; - - /* - * If the inner breaker (A) is already broken, too, - * it cannot take on the outer breaker (X) but must - * hand it on to its own breakers (Y). Graphically, - * - * [X! n=[Y!->X breaker=[A!->Y Y] broken=[B(->X)->A X] A] B] - */ - - while (n->pending) - n = n->pending; - n->pending = broken->pending; - } - - /* - * Now we have reduced the situation to the simplest case: - * breaker=[A! broken=[B->A A] B]. - */ - - broken->pending = breaker; - breaker->flags |= MDOC_BREAK; - if (breaker->body != NULL) - breaker->body->flags |= MDOC_BREAK; -} - -/* * Allocate a word and check whether it's punctuation or not. * Punctuation consists of those tokens found in mdoc_isdelim(). */ @@ -442,7 +386,7 @@ dword(struct mdoc *mdoc, int line, int col, const char if (may_append && ! (mdoc->flags & (MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF)) && - d == DELIM_NONE && mdoc->last->type == MDOC_TEXT && + d == DELIM_NONE && mdoc->last->type == ROFFT_TEXT && mdoc_isdelim(mdoc->last->string) == DELIM_NONE) { mdoc_word_append(mdoc, p); return; @@ -507,7 +451,7 @@ static int macro_or_word(MACRO_PROT_ARGS, int parsed) { char *p; - enum mdoct ntok; + int ntok; p = buf + ppos; ntok = MDOC_MAX; @@ -536,15 +480,15 @@ macro_or_word(MACRO_PROT_ARGS, int parsed) static void blk_exp_close(MACRO_PROT_ARGS) { - struct mdoc_node *body; /* Our own body. */ - struct mdoc_node *endbody; /* Our own end marker. */ - struct mdoc_node *itblk; /* An It block starting later. */ - struct mdoc_node *later; /* A sub-block starting later. */ - struct mdoc_node *n; /* Search back to our block. */ + struct roff_node *body; /* Our own body. */ + struct roff_node *endbody; /* Our own end marker. */ + struct roff_node *itblk; /* An It block starting later. */ + struct roff_node *later; /* A sub-block starting later. */ + struct roff_node *n; /* Search back to our block. */ int j, lastarg, maxargs, nl; enum margserr ac; - enum mdoct atok, ntok; + int atok, ntok; char *p; nl = MDOC_NEWLINE & mdoc->flags; @@ -569,18 +513,21 @@ blk_exp_close(MACRO_PROT_ARGS) atok = rew_alt(tok); body = endbody = itblk = later = NULL; for (n = mdoc->last; n; n = n->parent) { - if (n->flags & (MDOC_VALID | MDOC_BREAK)) + if (n->flags & MDOC_ENDED) { + if ( ! (n->flags & MDOC_VALID)) + n->flags |= MDOC_BROKEN; continue; + } /* Remember the start of our own body. */ - if (n->type == MDOC_BODY && atok == n->tok) { + if (n->type == ROFFT_BODY && atok == n->tok) { if (n->end == ENDBODY_NOT) body = n; continue; } - if (n->type != MDOC_BLOCK || n->tok == MDOC_Nm) + if (n->type != ROFFT_BLOCK || n->tok == MDOC_Nm) continue; if (n->tok == MDOC_It) { @@ -605,20 +552,21 @@ blk_exp_close(MACRO_PROT_ARGS) * When there is a pending sub block, postpone * closing out the current block until the * rew_pending() closing out the sub-block. - */ - - make_pending(mdoc, n, later, line, ppos); - if (tok == MDOC_El) - itblk->flags |= MDOC_BREAK; - - /* * Mark the place where the formatting - but not * the scope - of the current block ends. */ + mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, + line, ppos, "%s breaks %s", + mdoc_macronames[atok], + mdoc_macronames[later->tok]); + endbody = mdoc_endbody_alloc(mdoc, line, ppos, atok, body, ENDBODY_SPACE); + if (tok == MDOC_El) + itblk->flags |= MDOC_ENDED | MDOC_BROKEN; + /* * If a block closing macro taking arguments * breaks another block, put the arguments @@ -630,14 +578,17 @@ blk_exp_close(MACRO_PROT_ARGS) break; } - /* - * When finding an open sub block, remember the last - * open explicit block, or, in case there are only - * implicit ones, the first open implicit block. - */ + /* Explicit blocks close out description lines. */ - if (later == NULL || - ! (mdoc_macros[later->tok].flags & MDOC_EXPLICIT)) + if (n->tok == MDOC_Nd) { + rew_last(mdoc, n); + continue; + } + + /* Breaking an open sub block. */ + + n->flags |= MDOC_BROKEN; + if (later == NULL) later = n; } @@ -711,7 +662,7 @@ static void in_line(MACRO_PROT_ARGS) { int la, scope, cnt, firstarg, mayopen, nc, nl; - enum mdoct ntok; + int ntok; enum margserr ac; enum mdelim d; struct mdoc_arg *arg; @@ -895,24 +846,35 @@ blk_full(MACRO_PROT_ARGS) { int la, nl, parsed; struct mdoc_arg *arg; - struct mdoc_node *blk; /* Our own or a broken block. */ - struct mdoc_node *head; /* Our own head. */ - struct mdoc_node *body; /* Our own body. */ - struct mdoc_node *n; + struct roff_node *blk; /* Our own or a broken block. */ + struct roff_node *head; /* Our own head. */ + struct roff_node *body; /* Our own body. */ + struct roff_node *n; enum margserr ac, lac; char *p; nl = MDOC_NEWLINE & mdoc->flags; + if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) { + mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, + line, ppos, mdoc_macronames[tok]); + return; + } + if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) { /* Here, tok is one of Sh Ss Nm Nd It. */ blk = NULL; for (n = mdoc->last; n != NULL; n = n->parent) { - if (n->flags & (MDOC_VALID | MDOC_BREAK) || - n->type != MDOC_BLOCK) + if (n->flags & MDOC_ENDED) { + if ( ! (n->flags & MDOC_VALID)) + n->flags |= MDOC_BROKEN; continue; + } + if (n->type != ROFFT_BLOCK) + continue; + if (tok == MDOC_It && n->tok == MDOC_Bl) { if (blk != NULL) { mandoc_vmsg(MANDOCERR_BLK_BROKEN, @@ -935,6 +897,7 @@ blk_full(MACRO_PROT_ARGS) mdoc_macronames[tok], mdoc_macronames[n->tok]); rew_pending(mdoc, n); + n = mdoc->last; continue; case MDOC_It: /* Delay in case it's astray. */ @@ -1052,7 +1015,7 @@ blk_full(MACRO_PROT_ARGS) /* * Emit leading punctuation (i.e., punctuation before - * the MDOC_HEAD) for non-phrase types. + * the ROFFT_HEAD) for non-phrase types. */ if (head == NULL && @@ -1117,13 +1080,19 @@ blk_full(MACRO_PROT_ARGS) * sub-block. */ for (n = mdoc->last; n && n != head; n = n->parent) { - if (n->type == MDOC_BLOCK && - mdoc_macros[n->tok].flags & MDOC_EXPLICIT && - ! (n->flags & MDOC_VALID)) { - n->pending = head; - return; + if (n->flags & MDOC_ENDED) { + if ( ! (n->flags & MDOC_VALID)) + n->flags |= MDOC_BROKEN; + continue; } + if (n->type == ROFFT_BLOCK && + mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { + n->flags = MDOC_BROKEN; + head->flags = MDOC_ENDED; + } } + if (head->flags & MDOC_ENDED) + return; /* Close out scopes to remain in a consistent state. */ @@ -1143,9 +1112,9 @@ blk_part_imp(MACRO_PROT_ARGS) int la, nl; enum margserr ac; char *p; - struct mdoc_node *blk; /* saved block context */ - struct mdoc_node *body; /* saved body context */ - struct mdoc_node *n; + struct roff_node *blk; /* saved block context */ + struct roff_node *body; /* saved body context */ + struct roff_node *n; nl = MDOC_NEWLINE & mdoc->flags; @@ -1196,16 +1165,28 @@ blk_part_imp(MACRO_PROT_ARGS) for (n = mdoc->last; n && n != body && n != blk->parent; n = n->parent) { - if (n->type == MDOC_BLOCK && - mdoc_macros[n->tok].flags & MDOC_EXPLICIT && - ! (n->flags & MDOC_VALID)) { - make_pending(mdoc, blk, n, line, ppos); - mdoc_endbody_alloc(mdoc, line, ppos, - tok, body, ENDBODY_NOSPACE); - return; + if (n->flags & MDOC_ENDED) { + if ( ! (n->flags & MDOC_VALID)) + n->flags |= MDOC_BROKEN; + continue; } + if (n->type == ROFFT_BLOCK && + mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { + n->flags |= MDOC_BROKEN; + if ( ! (body->flags & MDOC_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, body, ENDBODY_NOSPACE); + } + } } assert(n == body); + if (body->flags & MDOC_ENDED) + return; + rew_last(mdoc, body); if (nl) append_delims(mdoc, line, pos, buf); @@ -1224,7 +1205,7 @@ blk_part_exp(MACRO_PROT_ARGS) { int la, nl; enum margserr ac; - struct mdoc_node *head; /* keep track of head */ + struct roff_node *head; /* keep track of head */ char *p; nl = MDOC_NEWLINE & mdoc->flags; @@ -1278,11 +1259,12 @@ blk_part_exp(MACRO_PROT_ARGS) static void in_line_argn(MACRO_PROT_ARGS) { - int la, flushed, j, maxargs, nl; - enum margserr ac; struct mdoc_arg *arg; char *p; - enum mdoct ntok; + enum margserr ac; + int ntok; + int state; /* arg#; -1: not yet open; -2: closed */ + int la, maxargs, nl; nl = mdoc->flags & MDOC_NEWLINE; @@ -1316,62 +1298,76 @@ in_line_argn(MACRO_PROT_ARGS) mdoc_argv(mdoc, line, tok, &arg, pos, buf); + state = -1; p = NULL; - flushed = j = 0; for (;;) { la = *pos; ac = mdoc_args(mdoc, line, pos, buf, tok, &p); + + if (ac == ARGS_WORD && state == -1 && + ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) && + mdoc_isdelim(p) == DELIM_OPEN) { + dword(mdoc, line, la, p, DELIM_OPEN, 0); + continue; + } + + if (state == -1 && tok != MDOC_In && + tok != MDOC_St && tok != MDOC_Xr) { + mdoc_elem_alloc(mdoc, line, ppos, tok, arg); + state = 0; + } + if (ac == ARGS_PUNCT || ac == ARGS_EOLN) { - if (j < 2 && tok == MDOC_Pf) + if (abs(state) < 2 && tok == MDOC_Pf) mandoc_vmsg(MANDOCERR_PF_SKIP, mdoc->parse, line, ppos, "Pf %s", p == NULL ? "at eol" : p); break; } - if ( ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) && - ac != ARGS_QWORD && j == 0 && - mdoc_isdelim(p) == DELIM_OPEN) { - dword(mdoc, line, la, p, DELIM_OPEN, 0); - continue; - } else if (j == 0) - mdoc_elem_alloc(mdoc, line, ppos, tok, arg); - - if (j == maxargs && ! flushed) { + if (state == maxargs) { rew_elem(mdoc, tok); - flushed = 1; + state = -2; } - ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && j == 0)) ? + ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && state == 0)) ? MDOC_MAX : lookup(mdoc, tok, line, la, p); if (ntok != MDOC_MAX) { - if ( ! flushed) + if (state >= 0) { rew_elem(mdoc, tok); - flushed = 1; + state = -2; + } mdoc_macro(mdoc, ntok, line, la, pos, buf); - j++; break; } - if ( ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) && - ac != ARGS_QWORD && ! flushed && - mdoc_isdelim(p) != DELIM_NONE) { + if (ac == ARGS_QWORD || + mdoc_macros[tok].flags & MDOC_IGNDELIM || + mdoc_isdelim(p) == DELIM_NONE) { + if (state == -1) { + mdoc_elem_alloc(mdoc, line, ppos, tok, arg); + state = 1; + } else if (state >= 0) + state++; + } else if (state >= 0) { rew_elem(mdoc, tok); - flushed = 1; + state = -2; } dword(mdoc, line, la, p, DELIM_MAX, MDOC_JOIN & mdoc_macros[tok].flags); - j++; } - if (j == 0) { - mdoc_elem_alloc(mdoc, line, ppos, tok, arg); - if (ac == ARGS_PUNCT && tok == MDOC_Pf) - append_delims(mdoc, line, pos, buf); + if (state == -1) { + mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, + line, ppos, mdoc_macronames[tok]); + return; } - if ( ! flushed) + + if (state == 0 && tok == MDOC_Pf) + append_delims(mdoc, line, pos, buf); + if (state >= 0) rew_elem(mdoc, tok); if (nl) append_delims(mdoc, line, pos, buf); @@ -1380,7 +1376,7 @@ in_line_argn(MACRO_PROT_ARGS) static void in_line_eoln(MACRO_PROT_ARGS) { - struct mdoc_node *n; + struct roff_node *n; struct mdoc_arg *arg; if ((tok == MDOC_Pp || tok == MDOC_Lp) && @@ -1392,6 +1388,13 @@ in_line_eoln(MACRO_PROT_ARGS) rew_last(mdoc, mdoc->last->parent); } + if (buf[*pos] == '\0' && + (tok == MDOC_Fd || mdoc_macronames[tok][0] == '%')) { + mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, + line, ppos, mdoc_macronames[tok]); + return; + } + mdoc_argv(mdoc, line, tok, &arg, pos, buf); mdoc_elem_alloc(mdoc, line, ppos, tok, arg); if (parse_rest(mdoc, tok, line, pos, buf)) @@ -1405,7 +1408,7 @@ in_line_eoln(MACRO_PROT_ARGS) * or until the next macro, call that macro, and return 1. */ static int -parse_rest(struct mdoc *mdoc, enum mdoct tok, int line, int *pos, char *buf) +parse_rest(struct mdoc *mdoc, int tok, int line, int *pos, char *buf) { int la; @@ -1440,15 +1443,15 @@ ctx_synopsis(MACRO_PROT_ARGS) static void phrase_ta(MACRO_PROT_ARGS) { - struct mdoc_node *body, *n; + struct roff_node *body, *n; /* Make sure we are in a column list or ignore this macro. */ body = NULL; for (n = mdoc->last; n != NULL; n = n->parent) { - if (n->flags & (MDOC_VALID | MDOC_BREAK)) + if (n->flags & MDOC_ENDED) continue; - if (n->tok == MDOC_It && n->type == MDOC_BODY) + if (n->tok == MDOC_It && n->type == ROFFT_BODY) body = n; if (n->tok == MDOC_Bl) break;