1  | 
     | 
     | 
    /*	$OpenBSD: man_macro.c,v 1.85 2017/06/25 07:23:53 bentley Exp $ */  | 
    
    
    2  | 
     | 
     | 
    /*  | 
    
    
    3  | 
     | 
     | 
     * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>  | 
    
    
    4  | 
     | 
     | 
     * Copyright (c) 2012-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>  | 
    
    
    5  | 
     | 
     | 
     * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>  | 
    
    
    6  | 
     | 
     | 
     *  | 
    
    
    7  | 
     | 
     | 
     * Permission to use, copy, modify, and distribute this software for any  | 
    
    
    8  | 
     | 
     | 
     * purpose with or without fee is hereby granted, provided that the above  | 
    
    
    9  | 
     | 
     | 
     * copyright notice and this permission notice appear in all copies.  | 
    
    
    10  | 
     | 
     | 
     *  | 
    
    
    11  | 
     | 
     | 
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES  | 
    
    
    12  | 
     | 
     | 
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF  | 
    
    
    13  | 
     | 
     | 
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR  | 
    
    
    14  | 
     | 
     | 
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES  | 
    
    
    15  | 
     | 
     | 
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN  | 
    
    
    16  | 
     | 
     | 
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  | 
    
    
    17  | 
     | 
     | 
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  | 
    
    
    18  | 
     | 
     | 
     */  | 
    
    
    19  | 
     | 
     | 
    #include <sys/types.h>  | 
    
    
    20  | 
     | 
     | 
     | 
    
    
    21  | 
     | 
     | 
    #include <assert.h>  | 
    
    
    22  | 
     | 
     | 
    #include <ctype.h>  | 
    
    
    23  | 
     | 
     | 
    #include <stdlib.h>  | 
    
    
    24  | 
     | 
     | 
    #include <string.h>  | 
    
    
    25  | 
     | 
     | 
     | 
    
    
    26  | 
     | 
     | 
    #include "mandoc.h"  | 
    
    
    27  | 
     | 
     | 
    #include "roff.h"  | 
    
    
    28  | 
     | 
     | 
    #include "man.h"  | 
    
    
    29  | 
     | 
     | 
    #include "libmandoc.h"  | 
    
    
    30  | 
     | 
     | 
    #include "roff_int.h"  | 
    
    
    31  | 
     | 
     | 
    #include "libman.h"  | 
    
    
    32  | 
     | 
     | 
     | 
    
    
    33  | 
     | 
     | 
    static	void		 blk_close(MACRO_PROT_ARGS);  | 
    
    
    34  | 
     | 
     | 
    static	void		 blk_exp(MACRO_PROT_ARGS);  | 
    
    
    35  | 
     | 
     | 
    static	void		 blk_imp(MACRO_PROT_ARGS);  | 
    
    
    36  | 
     | 
     | 
    static	void		 in_line_eoln(MACRO_PROT_ARGS);  | 
    
    
    37  | 
     | 
     | 
    static	int		 man_args(struct roff_man *, int,  | 
    
    
    38  | 
     | 
     | 
    				int *, char *, char **);  | 
    
    
    39  | 
     | 
     | 
    static	void		 rew_scope(struct roff_man *, enum roff_tok);  | 
    
    
    40  | 
     | 
     | 
     | 
    
    
    41  | 
     | 
     | 
    const	struct man_macro __man_macros[MAN_MAX - MAN_TH] = { | 
    
    
    42  | 
     | 
     | 
    	{ in_line_eoln, MAN_BSCOPE }, /* TH */ | 
    
    
    43  | 
     | 
     | 
    	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */ | 
    
    
    44  | 
     | 
     | 
    	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */ | 
    
    
    45  | 
     | 
     | 
    	{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* TP */ | 
    
    
    46  | 
     | 
     | 
    	{ blk_imp, MAN_BSCOPE }, /* LP */ | 
    
    
    47  | 
     | 
     | 
    	{ blk_imp, MAN_BSCOPE }, /* PP */ | 
    
    
    48  | 
     | 
     | 
    	{ blk_imp, MAN_BSCOPE }, /* P */ | 
    
    
    49  | 
     | 
     | 
    	{ blk_imp, MAN_BSCOPE }, /* IP */ | 
    
    
    50  | 
     | 
     | 
    	{ blk_imp, MAN_BSCOPE }, /* HP */ | 
    
    
    51  | 
     | 
     | 
    	{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SM */ | 
    
    
    52  | 
     | 
     | 
    	{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */ | 
    
    
    53  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* BI */ | 
    
    
    54  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* IB */ | 
    
    
    55  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* BR */ | 
    
    
    56  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* RB */ | 
    
    
    57  | 
     | 
     | 
    	{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* R */ | 
    
    
    58  | 
     | 
     | 
    	{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */ | 
    
    
    59  | 
     | 
     | 
    	{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */ | 
    
    
    60  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* IR */ | 
    
    
    61  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* RI */ | 
    
    
    62  | 
     | 
     | 
    	{ in_line_eoln, MAN_NSCOPED }, /* nf */ | 
    
    
    63  | 
     | 
     | 
    	{ in_line_eoln, MAN_NSCOPED }, /* fi */ | 
    
    
    64  | 
     | 
     | 
    	{ blk_close, MAN_BSCOPE }, /* RE */ | 
    
    
    65  | 
     | 
     | 
    	{ blk_exp, MAN_BSCOPE }, /* RS */ | 
    
    
    66  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* DT */ | 
    
    
    67  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* UC */ | 
    
    
    68  | 
     | 
     | 
    	{ in_line_eoln, MAN_NSCOPED }, /* PD */ | 
    
    
    69  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* AT */ | 
    
    
    70  | 
     | 
     | 
    	{ in_line_eoln, MAN_NSCOPED }, /* in */ | 
    
    
    71  | 
     | 
     | 
    	{ in_line_eoln, 0 }, /* OP */ | 
    
    
    72  | 
     | 
     | 
    	{ in_line_eoln, MAN_BSCOPE }, /* EX */ | 
    
    
    73  | 
     | 
     | 
    	{ in_line_eoln, MAN_BSCOPE }, /* EE */ | 
    
    
    74  | 
     | 
     | 
    	{ blk_exp, MAN_BSCOPE }, /* UR */ | 
    
    
    75  | 
     | 
     | 
    	{ blk_close, MAN_BSCOPE }, /* UE */ | 
    
    
    76  | 
     | 
     | 
    	{ blk_exp, MAN_BSCOPE }, /* MT */ | 
    
    
    77  | 
     | 
     | 
    	{ blk_close, MAN_BSCOPE }, /* ME */ | 
    
    
    78  | 
     | 
     | 
    };  | 
    
    
    79  | 
     | 
     | 
    const	struct man_macro *const man_macros = __man_macros - MAN_TH;  | 
    
    
    80  | 
     | 
     | 
     | 
    
    
    81  | 
     | 
     | 
     | 
    
    
    82  | 
     | 
     | 
    void  | 
    
    
    83  | 
     | 
     | 
    man_unscope(struct roff_man *man, const struct roff_node *to)  | 
    
    
    84  | 
     | 
     | 
    { | 
    
    
    85  | 
     | 
     | 
    	struct roff_node *n;  | 
    
    
    86  | 
     | 
     | 
     | 
    
    
    87  | 
     | 
    321890  | 
    	to = to->parent;  | 
    
    
    88  | 
     | 
    160945  | 
    	n = man->last;  | 
    
    
    89  | 
    ✓✓ | 
    1066890  | 
    	while (n != to) { | 
    
    
    90  | 
     | 
     | 
     | 
    
    
    91  | 
     | 
     | 
    		/* Reached the end of the document? */  | 
    
    
    92  | 
     | 
     | 
     | 
    
    
    93  | 
    ✓✓✓✓
  | 
    383626  | 
    		if (to == NULL && ! (n->flags & NODE_VALID)) { | 
    
    
    94  | 
    ✓✓✓✗
  | 
    8938  | 
    			if (man->flags & (MAN_BLINE | MAN_ELINE) &&  | 
    
    
    95  | 
     | 
    48  | 
    			    man_macros[n->tok].flags & MAN_SCOPED) { | 
    
    
    96  | 
     | 
    48  | 
    				mandoc_vmsg(MANDOCERR_BLK_LINE,  | 
    
    
    97  | 
     | 
    48  | 
    				    man->parse, n->line, n->pos,  | 
    
    
    98  | 
     | 
    48  | 
    				    "EOF breaks %s", roff_name[n->tok]);  | 
    
    
    99  | 
    ✓✓ | 
    48  | 
    				if (man->flags & MAN_ELINE)  | 
    
    
    100  | 
     | 
    18  | 
    					man->flags &= ~MAN_ELINE;  | 
    
    
    101  | 
     | 
     | 
    				else { | 
    
    
    102  | 
    ✗✓ | 
    30  | 
    					assert(n->type == ROFFT_HEAD);  | 
    
    
    103  | 
     | 
    30  | 
    					n = n->parent;  | 
    
    
    104  | 
     | 
     | 
    					man->flags &= ~MAN_BLINE;  | 
    
    
    105  | 
     | 
     | 
    				}  | 
    
    
    106  | 
     | 
    48  | 
    				man->last = n;  | 
    
    
    107  | 
     | 
    48  | 
    				n = n->parent;  | 
    
    
    108  | 
     | 
    48  | 
    				roff_node_delete(man, man->last);  | 
    
    
    109  | 
     | 
    48  | 
    				continue;  | 
    
    
    110  | 
     | 
     | 
    			}  | 
    
    
    111  | 
    ✓✓✓✓
  | 
    12130  | 
    			if (n->type == ROFFT_BLOCK &&  | 
    
    
    112  | 
     | 
    3288  | 
    			    man_macros[n->tok].fp == blk_exp)  | 
    
    
    113  | 
     | 
    18  | 
    				mandoc_msg(MANDOCERR_BLK_NOEND,  | 
    
    
    114  | 
     | 
    18  | 
    				    man->parse, n->line, n->pos,  | 
    
    
    115  | 
     | 
    18  | 
    				    roff_name[n->tok]);  | 
    
    
    116  | 
     | 
     | 
    		}  | 
    
    
    117  | 
     | 
     | 
     | 
    
    
    118  | 
     | 
     | 
    		/*  | 
    
    
    119  | 
     | 
     | 
    		 * We might delete the man->last node  | 
    
    
    120  | 
     | 
     | 
    		 * in the post-validation phase.  | 
    
    
    121  | 
     | 
     | 
    		 * Save a pointer to the parent such that  | 
    
    
    122  | 
     | 
     | 
    		 * we know where to continue the iteration.  | 
    
    
    123  | 
     | 
     | 
    		 */  | 
    
    
    124  | 
     | 
     | 
     | 
    
    
    125  | 
     | 
    372476  | 
    		man->last = n;  | 
    
    
    126  | 
     | 
    372476  | 
    		n = n->parent;  | 
    
    
    127  | 
     | 
    372476  | 
    		man->last->flags |= NODE_VALID;  | 
    
    
    128  | 
     | 
     | 
    	}  | 
    
    
    129  | 
     | 
     | 
     | 
    
    
    130  | 
     | 
     | 
    	/*  | 
    
    
    131  | 
     | 
     | 
    	 * If we ended up at the parent of the node we were  | 
    
    
    132  | 
     | 
     | 
    	 * supposed to rewind to, that means the target node  | 
    
    
    133  | 
     | 
     | 
    	 * got deleted, so add the next node we parse as a child  | 
    
    
    134  | 
     | 
     | 
    	 * of the parent instead of as a sibling of the target.  | 
    
    
    135  | 
     | 
     | 
    	 */  | 
    
    
    136  | 
     | 
     | 
     | 
    
    
    137  | 
     | 
    160945  | 
    	man->next = (man->last == to) ?  | 
    
    
    138  | 
     | 
     | 
    	    ROFF_NEXT_CHILD : ROFF_NEXT_SIBLING;  | 
    
    
    139  | 
     | 
    160945  | 
    }  | 
    
    
    140  | 
     | 
     | 
     | 
    
    
    141  | 
     | 
     | 
    /*  | 
    
    
    142  | 
     | 
     | 
     * Rewinding entails ascending the parse tree until a coherent point,  | 
    
    
    143  | 
     | 
     | 
     * for example, the `SH' macro will close out any intervening `SS'  | 
    
    
    144  | 
     | 
     | 
     * scopes.  When a scope is closed, it must be validated and actioned.  | 
    
    
    145  | 
     | 
     | 
     */  | 
    
    
    146  | 
     | 
     | 
    static void  | 
    
    
    147  | 
     | 
     | 
    rew_scope(struct roff_man *man, enum roff_tok tok)  | 
    
    
    148  | 
     | 
     | 
    { | 
    
    
    149  | 
     | 
     | 
    	struct roff_node *n;  | 
    
    
    150  | 
     | 
     | 
     | 
    
    
    151  | 
     | 
     | 
    	/* Preserve empty paragraphs before RS. */  | 
    
    
    152  | 
     | 
     | 
     | 
    
    
    153  | 
     | 
    164002  | 
    	n = man->last;  | 
    
    
    154  | 
    ✓✓✓✓ ✗✓ | 
    87143  | 
    	if (tok == MAN_RS && n->child == NULL &&  | 
    
    
    155  | 
    ✓✓✓✓
  | 
    5461  | 
    	    (n->tok == MAN_P || n->tok == MAN_PP || n->tok == MAN_LP))  | 
    
    
    156  | 
     | 
    36  | 
    		return;  | 
    
    
    157  | 
     | 
     | 
     | 
    
    
    158  | 
     | 
    155478  | 
    	for (;;) { | 
    
    
    159  | 
    ✓✓ | 
    445052  | 
    		if (n->type == ROFFT_ROOT)  | 
    
    
    160  | 
     | 
    9754  | 
    			return;  | 
    
    
    161  | 
    ✓✓ | 
    435298  | 
    		if (n->flags & NODE_VALID) { | 
    
    
    162  | 
     | 
    143815  | 
    			n = n->parent;  | 
    
    
    163  | 
     | 
    143815  | 
    			continue;  | 
    
    
    164  | 
     | 
     | 
    		}  | 
    
    
    165  | 
    ✓✓ | 
    291483  | 
    		if (n->type != ROFFT_BLOCK) { | 
    
    
    166  | 
    ✗✓ | 
    145759  | 
    			if (n->parent->type == ROFFT_ROOT) { | 
    
    
    167  | 
     | 
     | 
    				man_unscope(man, n);  | 
    
    
    168  | 
     | 
     | 
    				return;  | 
    
    
    169  | 
     | 
     | 
    			} else { | 
    
    
    170  | 
     | 
     | 
    				n = n->parent;  | 
    
    
    171  | 
     | 
    145759  | 
    				continue;  | 
    
    
    172  | 
     | 
     | 
    			}  | 
    
    
    173  | 
     | 
     | 
    		}  | 
    
    
    174  | 
    ✓✓✓✓ ✓✓ | 
    340914  | 
    		if (tok != MAN_SH && (n->tok == MAN_SH ||  | 
    
    
    175  | 
    ✓✓✓✓
  | 
    201583  | 
    		    (tok != MAN_SS && (n->tok == MAN_SS ||  | 
    
    
    176  | 
     | 
    60612  | 
    		     man_macros[n->tok].fp == blk_exp))))  | 
    
    
    177  | 
     | 
    72211  | 
    			return;  | 
    
    
    178  | 
     | 
    73513  | 
    		man_unscope(man, n);  | 
    
    
    179  | 
     | 
    73513  | 
    		n = man->last;  | 
    
    
    180  | 
     | 
     | 
    	}  | 
    
    
    181  | 
     | 
    82001  | 
    }  | 
    
    
    182  | 
     | 
     | 
     | 
    
    
    183  | 
     | 
     | 
     | 
    
    
    184  | 
     | 
     | 
    /*  | 
    
    
    185  | 
     | 
     | 
     * Close out a generic explicit macro.  | 
    
    
    186  | 
     | 
     | 
     */  | 
    
    
    187  | 
     | 
     | 
    void  | 
    
    
    188  | 
     | 
     | 
    blk_close(MACRO_PROT_ARGS)  | 
    
    
    189  | 
     | 
     | 
    { | 
    
    
    190  | 
     | 
     | 
    	enum roff_tok		 ntok;  | 
    
    
    191  | 
     | 
     | 
    	const struct roff_node	*nn;  | 
    
    
    192  | 
     | 
    6866  | 
    	char			*p;  | 
    
    
    193  | 
     | 
     | 
    	int			 nrew, target;  | 
    
    
    194  | 
     | 
     | 
     | 
    
    
    195  | 
     | 
     | 
    	nrew = 1;  | 
    
    
    196  | 
    ✓✓✓✗
  | 
    3433  | 
    	switch (tok) { | 
    
    
    197  | 
     | 
     | 
    	case MAN_RE:  | 
    
    
    198  | 
     | 
     | 
    		ntok = MAN_RS;  | 
    
    
    199  | 
    ✓✓ | 
    3349  | 
    		if ( ! man_args(man, line, pos, buf, &p))  | 
    
    
    200  | 
     | 
     | 
    			break;  | 
    
    
    201  | 
    ✓✓ | 
    408  | 
    		for (nn = man->last->parent; nn; nn = nn->parent)  | 
    
    
    202  | 
    ✓✓✓✓
  | 
    258  | 
    			if (nn->tok == ntok && nn->type == ROFFT_BLOCK)  | 
    
    
    203  | 
     | 
    42  | 
    				nrew++;  | 
    
    
    204  | 
     | 
    30  | 
    		target = strtol(p, &p, 10);  | 
    
    
    205  | 
    ✓✗ | 
    30  | 
    		if (*p != '\0')  | 
    
    
    206  | 
     | 
    60  | 
    			mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,  | 
    
    
    207  | 
     | 
    30  | 
    			    line, p - buf, "RE ... %s", p);  | 
    
    
    208  | 
    ✓✓ | 
    30  | 
    		if (target == 0)  | 
    
    
    209  | 
     | 
    6  | 
    			target = 1;  | 
    
    
    210  | 
     | 
    30  | 
    		nrew -= target;  | 
    
    
    211  | 
    ✓✓ | 
    30  | 
    		if (nrew < 1) { | 
    
    
    212  | 
     | 
    6  | 
    			mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse,  | 
    
    
    213  | 
     | 
     | 
    			    line, ppos, "RE %d", target);  | 
    
    
    214  | 
     | 
    6  | 
    			return;  | 
    
    
    215  | 
     | 
     | 
    		}  | 
    
    
    216  | 
     | 
     | 
    		break;  | 
    
    
    217  | 
     | 
     | 
    	case MAN_UE:  | 
    
    
    218  | 
     | 
     | 
    		ntok = MAN_UR;  | 
    
    
    219  | 
     | 
    48  | 
    		break;  | 
    
    
    220  | 
     | 
     | 
    	case MAN_ME:  | 
    
    
    221  | 
     | 
     | 
    		ntok = MAN_MT;  | 
    
    
    222  | 
     | 
    36  | 
    		break;  | 
    
    
    223  | 
     | 
     | 
    	default:  | 
    
    
    224  | 
     | 
     | 
    		abort();  | 
    
    
    225  | 
     | 
     | 
    	}  | 
    
    
    226  | 
     | 
     | 
     | 
    
    
    227  | 
    ✓✓ | 
    16350  | 
    	for (nn = man->last->parent; nn; nn = nn->parent)  | 
    
    
    228  | 
    ✓✓✓✓ ✓✓ | 
    17061  | 
    		if (nn->tok == ntok && nn->type == ROFFT_BLOCK && ! --nrew)  | 
    
    
    229  | 
     | 
     | 
    			break;  | 
    
    
    230  | 
     | 
     | 
     | 
    
    
    231  | 
    ✓✓ | 
    3427  | 
    	if (nn == NULL) { | 
    
    
    232  | 
     | 
    108  | 
    		mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,  | 
    
    
    233  | 
     | 
    54  | 
    		    line, ppos, roff_name[tok]);  | 
    
    
    234  | 
     | 
    54  | 
    		rew_scope(man, MAN_PP);  | 
    
    
    235  | 
     | 
    54  | 
    	} else { | 
    
    
    236  | 
     | 
    3373  | 
    		line = man->last->line;  | 
    
    
    237  | 
     | 
    3373  | 
    		ppos = man->last->pos;  | 
    
    
    238  | 
     | 
    3373  | 
    		ntok = man->last->tok;  | 
    
    
    239  | 
     | 
    3373  | 
    		man_unscope(man, nn);  | 
    
    
    240  | 
     | 
     | 
     | 
    
    
    241  | 
    ✓✓✓✓
  | 
    6686  | 
    		if (tok == MAN_RE && nn->head->aux > 0)  | 
    
    
    242  | 
     | 
    2978  | 
    			roff_setreg(man->roff, "an-margin",  | 
    
    
    243  | 
     | 
     | 
    			    nn->head->aux, '-');  | 
    
    
    244  | 
     | 
     | 
     | 
    
    
    245  | 
     | 
     | 
    		/* Move a trailing paragraph behind the block. */  | 
    
    
    246  | 
     | 
     | 
     | 
    
    
    247  | 
    ✓✓ | 
    3373  | 
    		if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) { | 
    
    
    248  | 
     | 
    15  | 
    			*pos = strlen(buf);  | 
    
    
    249  | 
     | 
    15  | 
    			blk_imp(man, ntok, line, ppos, pos, buf);  | 
    
    
    250  | 
     | 
    15  | 
    		}  | 
    
    
    251  | 
     | 
     | 
    	}  | 
    
    
    252  | 
     | 
    6860  | 
    }  | 
    
    
    253  | 
     | 
     | 
     | 
    
    
    254  | 
     | 
     | 
    void  | 
    
    
    255  | 
     | 
     | 
    blk_exp(MACRO_PROT_ARGS)  | 
    
    
    256  | 
     | 
     | 
    { | 
    
    
    257  | 
     | 
     | 
    	struct roff_node *head;  | 
    
    
    258  | 
     | 
    6854  | 
    	char		*p;  | 
    
    
    259  | 
     | 
     | 
    	int		 la;  | 
    
    
    260  | 
     | 
     | 
     | 
    
    
    261  | 
     | 
    3427  | 
    	rew_scope(man, tok);  | 
    
    
    262  | 
     | 
    3427  | 
    	roff_block_alloc(man, line, ppos, tok);  | 
    
    
    263  | 
     | 
    3427  | 
    	head = roff_head_alloc(man, line, ppos, tok);  | 
    
    
    264  | 
     | 
     | 
     | 
    
    
    265  | 
     | 
    3427  | 
    	la = *pos;  | 
    
    
    266  | 
    ✓✓ | 
    3427  | 
    	if (man_args(man, line, pos, buf, &p)) { | 
    
    
    267  | 
     | 
    3291  | 
    		roff_word_alloc(man, line, la, p);  | 
    
    
    268  | 
    ✓✓ | 
    3291  | 
    		if (tok == MAN_RS) { | 
    
    
    269  | 
    ✓✓ | 
    3219  | 
    			if (roff_getreg(man->roff, "an-margin") == 0)  | 
    
    
    270  | 
     | 
    263  | 
    				roff_setreg(man->roff, "an-margin",  | 
    
    
    271  | 
     | 
     | 
    				    7 * 24, '=');  | 
    
    
    272  | 
    ✓✓ | 
    3219  | 
    			if ((head->aux = strtod(p, NULL) * 24.0) > 0)  | 
    
    
    273  | 
     | 
    3008  | 
    				roff_setreg(man->roff, "an-margin",  | 
    
    
    274  | 
     | 
     | 
    				    head->aux, '+');  | 
    
    
    275  | 
     | 
     | 
    		}  | 
    
    
    276  | 
     | 
     | 
    	}  | 
    
    
    277  | 
     | 
     | 
     | 
    
    
    278  | 
    ✓✓ | 
    3427  | 
    	if (buf[*pos] != '\0')  | 
    
    
    279  | 
     | 
    60  | 
    		mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,  | 
    
    
    280  | 
     | 
    30  | 
    		    *pos, "%s ... %s", roff_name[tok], buf + *pos);  | 
    
    
    281  | 
     | 
     | 
     | 
    
    
    282  | 
     | 
    3427  | 
    	man_unscope(man, head);  | 
    
    
    283  | 
     | 
    3427  | 
    	roff_body_alloc(man, line, ppos, tok);  | 
    
    
    284  | 
     | 
    3427  | 
    }  | 
    
    
    285  | 
     | 
     | 
     | 
    
    
    286  | 
     | 
     | 
    /*  | 
    
    
    287  | 
     | 
     | 
     * Parse an implicit-block macro.  These contain a ROFFT_HEAD and a  | 
    
    
    288  | 
     | 
     | 
     * ROFFT_BODY contained within a ROFFT_BLOCK.  Rules for closing out other  | 
    
    
    289  | 
     | 
     | 
     * scopes, such as `SH' closing out an `SS', are defined in the rew  | 
    
    
    290  | 
     | 
     | 
     * routines.  | 
    
    
    291  | 
     | 
     | 
     */  | 
    
    
    292  | 
     | 
     | 
    void  | 
    
    
    293  | 
     | 
     | 
    blk_imp(MACRO_PROT_ARGS)  | 
    
    
    294  | 
     | 
     | 
    { | 
    
    
    295  | 
     | 
     | 
    	int		 la;  | 
    
    
    296  | 
     | 
    157040  | 
    	char		*p;  | 
    
    
    297  | 
     | 
     | 
    	struct roff_node *n;  | 
    
    
    298  | 
     | 
     | 
     | 
    
    
    299  | 
     | 
    78520  | 
    	rew_scope(man, tok);  | 
    
    
    300  | 
     | 
    78520  | 
    	n = roff_block_alloc(man, line, ppos, tok);  | 
    
    
    301  | 
    ✓✓✓✓
  | 
    147355  | 
    	if (n->tok == MAN_SH || n->tok == MAN_SS)  | 
    
    
    302  | 
     | 
    15395  | 
    		man->flags &= ~MAN_LITERAL;  | 
    
    
    303  | 
     | 
    78520  | 
    	n = roff_head_alloc(man, line, ppos, tok);  | 
    
    
    304  | 
     | 
     | 
     | 
    
    
    305  | 
     | 
     | 
    	/* Add line arguments. */  | 
    
    
    306  | 
     | 
     | 
     | 
    
    
    307  | 
     | 
    164691  | 
    	for (;;) { | 
    
    
    308  | 
     | 
    164691  | 
    		la = *pos;  | 
    
    
    309  | 
    ✓✓ | 
    164691  | 
    		if ( ! man_args(man, line, pos, buf, &p))  | 
    
    
    310  | 
     | 
     | 
    			break;  | 
    
    
    311  | 
     | 
    86171  | 
    		roff_word_alloc(man, line, la, p);  | 
    
    
    312  | 
     | 
     | 
    	}  | 
    
    
    313  | 
     | 
     | 
     | 
    
    
    314  | 
     | 
     | 
    	/*  | 
    
    
    315  | 
     | 
     | 
    	 * For macros having optional next-line scope,  | 
    
    
    316  | 
     | 
     | 
    	 * keep the head open if there were no arguments.  | 
    
    
    317  | 
     | 
     | 
    	 * For `TP', always keep the head open.  | 
    
    
    318  | 
     | 
     | 
    	 */  | 
    
    
    319  | 
     | 
     | 
     | 
    
    
    320  | 
    ✓✓✓✓
  | 
    93915  | 
    	if (man_macros[tok].flags & MAN_SCOPED &&  | 
    
    
    321  | 
    ✓✓ | 
    33270  | 
    	    (tok == MAN_TP || n == man->last)) { | 
    
    
    322  | 
     | 
    2699  | 
    		man->flags |= MAN_BLINE;  | 
    
    
    323  | 
     | 
    2699  | 
    		return;  | 
    
    
    324  | 
     | 
     | 
    	}  | 
    
    
    325  | 
     | 
     | 
     | 
    
    
    326  | 
     | 
     | 
    	/* Close out the head and open the body. */  | 
    
    
    327  | 
     | 
     | 
     | 
    
    
    328  | 
     | 
    75821  | 
    	man_unscope(man, n);  | 
    
    
    329  | 
     | 
    75821  | 
    	roff_body_alloc(man, line, ppos, tok);  | 
    
    
    330  | 
     | 
    154341  | 
    }  | 
    
    
    331  | 
     | 
     | 
     | 
    
    
    332  | 
     | 
     | 
    void  | 
    
    
    333  | 
     | 
     | 
    in_line_eoln(MACRO_PROT_ARGS)  | 
    
    
    334  | 
     | 
     | 
    { | 
    
    
    335  | 
     | 
     | 
    	int		 la;  | 
    
    
    336  | 
     | 
    66998  | 
    	char		*p;  | 
    
    
    337  | 
     | 
     | 
    	struct roff_node *n;  | 
    
    
    338  | 
     | 
     | 
     | 
    
    
    339  | 
     | 
    33499  | 
    	roff_elem_alloc(man, line, ppos, tok);  | 
    
    
    340  | 
     | 
    33499  | 
    	n = man->last;  | 
    
    
    341  | 
     | 
     | 
     | 
    
    
    342  | 
     | 
    51507  | 
    	for (;;) { | 
    
    
    343  | 
    ✓✓✓✓
  | 
    69533  | 
    		if (buf[*pos] != '\0' && (tok == MAN_fi || tok == MAN_nf)) { | 
    
    
    344  | 
     | 
    12  | 
    			mandoc_vmsg(MANDOCERR_ARG_SKIP,  | 
    
    
    345  | 
     | 
    12  | 
    			    man->parse, line, *pos, "%s %s",  | 
    
    
    346  | 
     | 
    12  | 
    			    roff_name[tok], buf + *pos);  | 
    
    
    347  | 
     | 
    12  | 
    			break;  | 
    
    
    348  | 
     | 
     | 
    		}  | 
    
    
    349  | 
    ✓✓✓✓
  | 
    69509  | 
    		if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) { | 
    
    
    350  | 
     | 
    6  | 
    			mandoc_vmsg(MANDOCERR_ARG_EXCESS,  | 
    
    
    351  | 
     | 
    6  | 
    			    man->parse, line, *pos, "%s ... %s",  | 
    
    
    352  | 
     | 
    6  | 
    			    roff_name[tok], buf + *pos);  | 
    
    
    353  | 
     | 
    6  | 
    			break;  | 
    
    
    354  | 
     | 
     | 
    		}  | 
    
    
    355  | 
     | 
    51489  | 
    		la = *pos;  | 
    
    
    356  | 
    ✓✓ | 
    51489  | 
    		if ( ! man_args(man, line, pos, buf, &p))  | 
    
    
    357  | 
     | 
     | 
    			break;  | 
    
    
    358  | 
    ✓✓✓✓
  | 
    21418  | 
    		if (man_macros[tok].flags & MAN_JOIN &&  | 
    
    
    359  | 
     | 
    3410  | 
    		    man->last->type == ROFFT_TEXT)  | 
    
    
    360  | 
     | 
    1065  | 
    			roff_word_append(man, p);  | 
    
    
    361  | 
     | 
     | 
    		else  | 
    
    
    362  | 
     | 
    16943  | 
    			roff_word_alloc(man, line, la, p);  | 
    
    
    363  | 
     | 
     | 
    	}  | 
    
    
    364  | 
     | 
     | 
     | 
    
    
    365  | 
     | 
     | 
    	/*  | 
    
    
    366  | 
     | 
     | 
    	 * Append NODE_EOS in case the last snipped argument  | 
    
    
    367  | 
     | 
     | 
    	 * ends with a dot, e.g. `.IR syslog (3).'  | 
    
    
    368  | 
     | 
     | 
    	 */  | 
    
    
    369  | 
     | 
     | 
     | 
    
    
    370  | 
    ✓✓✓✓
  | 
    41938  | 
    	if (n != man->last &&  | 
    
    
    371  | 
     | 
    8439  | 
    	    mandoc_eos(man->last->string, strlen(man->last->string)))  | 
    
    
    372  | 
     | 
    177  | 
    		man->last->flags |= NODE_EOS;  | 
    
    
    373  | 
     | 
     | 
     | 
    
    
    374  | 
     | 
     | 
    	/*  | 
    
    
    375  | 
     | 
     | 
    	 * If no arguments are specified and this is MAN_SCOPED (i.e.,  | 
    
    
    376  | 
     | 
     | 
    	 * next-line scoped), then set our mode to indicate that we're  | 
    
    
    377  | 
     | 
     | 
    	 * waiting for terms to load into our context.  | 
    
    
    378  | 
     | 
     | 
    	 */  | 
    
    
    379  | 
     | 
     | 
     | 
    
    
    380  | 
    ✓✓✓✓
  | 
    58559  | 
    	if (n == man->last && man_macros[tok].flags & MAN_SCOPED) { | 
    
    
    381  | 
    ✗✓ | 
    71  | 
    		assert( ! (man_macros[tok].flags & MAN_NSCOPED));  | 
    
    
    382  | 
     | 
    71  | 
    		man->flags |= MAN_ELINE;  | 
    
    
    383  | 
     | 
    71  | 
    		return;  | 
    
    
    384  | 
     | 
     | 
    	}  | 
    
    
    385  | 
     | 
     | 
     | 
    
    
    386  | 
    ✗✓ | 
    33428  | 
    	assert(man->last->type != ROFFT_ROOT);  | 
    
    
    387  | 
     | 
    33428  | 
    	man->next = ROFF_NEXT_SIBLING;  | 
    
    
    388  | 
     | 
     | 
     | 
    
    
    389  | 
     | 
     | 
    	/* Rewind our element scope. */  | 
    
    
    390  | 
     | 
     | 
     | 
    
    
    391  | 
    ✓✗ | 
    83734  | 
    	for ( ; man->last; man->last = man->last->parent) { | 
    
    
    392  | 
     | 
    41867  | 
    		man_state(man, man->last);  | 
    
    
    393  | 
    ✓✓ | 
    41867  | 
    		if (man->last == n)  | 
    
    
    394  | 
     | 
     | 
    			break;  | 
    
    
    395  | 
     | 
     | 
    	}  | 
    
    
    396  | 
     | 
    66927  | 
    }  | 
    
    
    397  | 
     | 
     | 
     | 
    
    
    398  | 
     | 
     | 
    void  | 
    
    
    399  | 
     | 
     | 
    man_endparse(struct roff_man *man)  | 
    
    
    400  | 
     | 
     | 
    { | 
    
    
    401  | 
     | 
     | 
     | 
    
    
    402  | 
     | 
    4530  | 
    	man_unscope(man, man->first);  | 
    
    
    403  | 
     | 
    2265  | 
    	man->flags &= ~MAN_LITERAL;  | 
    
    
    404  | 
     | 
    2265  | 
    }  | 
    
    
    405  | 
     | 
     | 
     | 
    
    
    406  | 
     | 
     | 
    static int  | 
    
    
    407  | 
     | 
     | 
    man_args(struct roff_man *man, int line, int *pos, char *buf, char **v)  | 
    
    
    408  | 
     | 
     | 
    { | 
    
    
    409  | 
     | 
     | 
    	char	 *start;  | 
    
    
    410  | 
     | 
     | 
     | 
    
    
    411  | 
    ✗✓ | 
    445912  | 
    	assert(*pos);  | 
    
    
    412  | 
     | 
    222956  | 
    	*v = start = buf + *pos;  | 
    
    
    413  | 
    ✗✓ | 
    222956  | 
    	assert(' ' != *start); | 
    
    
    414  | 
     | 
     | 
     | 
    
    
    415  | 
    ✓✓ | 
    222956  | 
    	if ('\0' == *start) | 
    
    
    416  | 
     | 
    115456  | 
    		return 0;  | 
    
    
    417  | 
     | 
     | 
     | 
    
    
    418  | 
     | 
    107500  | 
    	*v = mandoc_getarg(man->parse, v, line, pos);  | 
    
    
    419  | 
     | 
    107500  | 
    	return 1;  | 
    
    
    420  | 
     | 
    222956  | 
    }  |