371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov/* $Id: mdoc_macro.c,v 1.206 2015/10/20 02:01:32 schwarze Exp $ */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * copyright notice and this permission notice appear in all copies.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void append_delims(struct roff_man *, int, int *, char *);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void dword(struct roff_man *, int, int, const char *,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int find_pending(struct roff_man *, int, int, int,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int lookup(struct roff_man *, int, int, int, const char *);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int parse_rest(struct roff_man *, int, int, int *, char *);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic int rew_alt(int);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovstatic void rew_last(struct roff_man *, const struct roff_node *);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov const struct roff_node *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreconst struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Sh */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Ss */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* D1 */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* Dl */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ed */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* El */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Cd */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ic */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Li */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ot */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Aq */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Bq */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Dq */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ec */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ef */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Em */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* No */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Pq */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ql */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Qq */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Re */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sq */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sx */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sy */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ux */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fr */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Brq */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Es */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* En */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreconst struct mdoc_macro * const mdoc_macros = __mdoc_macros;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * This is called at the end of parsing. It must traverse up the tree,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * closing out open [implicit] scopes. Obviously, open explicit scopes
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * are errors.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Scan for open explicit scopes. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore for ( ; n; n = n->parent)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Rewind to the first. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Look up the macro at *p called by "from",
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * or as a line macro if from == TOKEN_NONE.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovlookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (res != MDOC_br && res != MDOC_sp && res != MDOC_ll)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Rewind up to and including a specific node.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovrew_last(struct roff_man *mdoc, const struct roff_node *to)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Rewind up to a specific block, including all blocks that broke it.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovrew_pending(struct roff_man *mdoc, const struct roff_node *n)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov switch (n->type) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * For a block closing macro, return the corresponding opening one.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Otherwise, return the macro itself.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * If there is an open sub-block of the target requiring
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * explicit close-out, postpone closing out the target until
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * the rew_pending() call closing out the sub-block.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovfind_pending(struct roff_man *mdoc, int tok, int line, int ppos,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov for (n = mdoc->last; n != NULL && n != target; n = n->parent) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Allocate a word and check whether it's punctuation or not.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Punctuation consists of those tokens found in mdoc_isdelim().
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovdword(struct roff_man *mdoc, int line, int col, const char *p,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ! (mdoc->flags & (MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF)) &&
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov d == DELIM_NONE && mdoc->last->type == ROFFT_TEXT &&
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mdoc_isdelim(mdoc->last->string) == DELIM_NONE) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If the word consists of a bare delimiter,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * flag the new node accordingly,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * unless doing so was vetoed by the invoking macro.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Always clear the veto, it is only valid for one word.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (d == DELIM_CLOSE &&
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovappend_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p) ==
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we encounter end-of-sentence symbols, then trigger
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the double-space.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * XXX: it's easy to allow this to propagate outward to
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the last symbol, such that `. )' will cause the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * correct double-spacing. However, (1) groff isn't
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * smart enough to do this and (2) it would require
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * knowing which symbols break this behaviour, for
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * example, `. ;' shouldn't propagate the double-space.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Parse one word.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If it is a macro, call it and return 1.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Otherwise, allocate it and return 0.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (*p == '"')
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT))
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Close out block partial/full explicit.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *endbody; /* Our own end marker. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *itblk; /* An It block starting later. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *later; /* A sub-block starting later. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *n; /* Search back to our block. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *target; /* For find_pending(). */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Search backwards for beginnings of blocks,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * both of our own and of pending sub-blocks.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Remember the start of our own body. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (n->type != ROFFT_BLOCK || n->tok == MDOC_Nm)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Found the start of our own block.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * When there is no pending sub block,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * just proceed to closing out.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * When there is a pending sub block, postpone
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * closing out the current block until the
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * rew_pending() closing out the sub-block.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Mark the place where the formatting - but not
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the scope - of the current block ends.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If a block closing macro taking arguments
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * breaks another block, put the arguments
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * into the end marker.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Explicit blocks close out description lines. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Breaking an open sub block. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Stray .Ec without previous .Eo:
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Break the output line, keep the arguments.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (j = 0; ; j++) {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov if (ntok != TOKEN_NONE && n->flags & MDOC_BROKEN) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Whether we allow ignored elements (those without content,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * usually because of reserved words) to squeak by.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * At the end of a macro line,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * opening delimiters do not suppress spacing.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * The rest of the macro line is only punctuation,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * to be handled by append_delims().
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If there were no other arguments,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * do not allow the first one to suppress spacing,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * even if it turns out to be a closing one.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ?
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * In this case, we've located a submacro and must
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * execute it. Close out scope, if open. If no
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * elements have been generated, either create one (nc)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * or raise a warning.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Non-quote-enclosed punctuation. Set up our scope, if
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * a word; rewind the scope, if a delimiter; then append
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov d = ac == ARGS_QWORD ? DELIM_NONE : mdoc_isdelim(p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we encounter closing punctuation, no word
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * has been emitted, no scope is open, and we're
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * allowed to have an empty element, then start
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * a new scope.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Close out our scope, if one is open, before
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * any punctuation.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * If the first argument is a closing delimiter,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * do not suppress spacing before it.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * `Fl' macros have their scope re-opened with each new
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * word so that the `-' can be added to each one without
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * having to parse out spaces.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If no elements have been collected and we're allowed to have
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * empties (nc), open a scope and close it out. Otherwise,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * raise a warning.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *blk; /* Our own or a broken block. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Here, tok is one of Sh Ss Nm Nd It. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (n = mdoc->last; n != NULL; n = n->parent) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "It breaks %s",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "%s breaks %s",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Delay in case it's astray. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Here, n is one of Sh Ss Nm Nd It. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Item breaking an explicit block. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov "It breaks %s",
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Close out prior implicit scopes. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Skip items outside lists. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * This routine accommodates implicitly- and explicitly-scoped
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * macro openings. Implicit ones first close out prior scope
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * (seen above). Delay opening the head until necessary to
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * allow leading punctuation to print. Special consideration
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * for `It -column', which has phrase-part syntax instead of
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * regular child nodes.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Exception: Heads of `It' macros in `-diag' lists are not
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * parsed, even though `It' macros in general are parsed.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * The `Nd' macro has all arguments in its body: it's a hybrid
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * of block partial-explicit and full-implicit. Stupid.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * If we are right after a tab character,
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * do not parse the first word for macros.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * This line ends in a tab; start the next
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * column now, with a leading blank.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Emit leading punctuation (i.e., punctuation before
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov * the ROFFT_HEAD) for non-phrase types.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Open a head if one hasn't been opened. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we haven't opened a body yet, rewind the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * head; if we have, rewind that instead.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* Process to the tab or to the end of the line. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov /* There may have been `Ta' macros. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Close out scopes to remain in a consistent state. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *blk; /* saved block context */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *body; /* saved body context */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * A macro that spans to the end of the line. This is generally
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * (but not necessarily) called as the first macro. The block
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * has a head as the immediate child, which is always empty,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * followed by zero or more opening punctuation nodes, then the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * body (which may be empty, depending on the macro), then zero
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * or more closing punctuation nodes.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Open the body scope "on-demand", that is, after we've
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * processed all our the leading delimiters (open parenthesis,
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* Move trailing .Ns out of scope. */
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore for (n = body->child; n && n->next; n = n->next)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* Do nothing. */ ;
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov struct roff_node *head; /* keep track of head */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * The opening of an explicit macro having zero or more leading
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * punctuation nodes; a head with optional single element (the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * case of `Eo'); and a body that may be empty.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Flush out leading punctuation. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Clean-up to leave in a consistent state. */
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankov rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov int state; /* arg#; -1: not yet open; -2: closed */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * A line macro that has a fixed number of arguments (maxargs).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Only open the scope once the first non-leading-punctuation is
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * keep it open until the maximum number of arguments are
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && state == 0)) ?
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if (state >= 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov } else if (state >= 0) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (tok == MDOC_Fd || mdoc_macronames[tok][0] == '%')) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * The simplest argument parser available: Parse the remaining
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * words until the end of the phrase or line and return 0
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * or until the next macro, call that macro, and return 1.
371584c2eae4cf827fd406ba26c14f021adaaa70Yuri Pankovparse_rest(struct roff_man *mdoc, int tok, int line, int *pos, char *buf)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (~mdoc->flags & (MDOC_SYNOPSIS | MDOC_NEWLINE))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * They're unusual because they're basically free-form text until a
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * macro is encountered.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Make sure we are in a column list or ignore this macro. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (n = mdoc->last; n != NULL; n = n->parent) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (n == NULL || n->norm->Bl.type != LIST_column) {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* Advance to the next column. */