Example #1
0
static void
blk_part_exp(MACRO_PROT_ARGS)
{
	int		  la, nl;
	enum margserr	  ac;
	struct roff_node *head; /* keep track of head */
	char		 *p;

	nl = MDOC_NEWLINE & mdoc->flags;

	/*
	 * The opening of an explicit macro having zero or more leading
	 * punctuation nodes; a head with optional single element (the
	 * case of `Eo'); and a body that may be empty.
	 */

	roff_block_alloc(mdoc, line, ppos, tok);
	head = NULL;
	for (;;) {
		la = *pos;
		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
		if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
			break;

		/* Flush out leading punctuation. */

		if (head == NULL && ac != ARGS_QWORD &&
		    mdoc_isdelim(p) == DELIM_OPEN) {
			dword(mdoc, line, la, p, DELIM_OPEN, 0);
			continue;
		}

		if (head == NULL) {
			head = roff_head_alloc(mdoc, line, ppos, tok);
			if (tok == MDOC_Eo)  /* Not parsed. */
				dword(mdoc, line, la, p, DELIM_MAX, 0);
			rew_last(mdoc, head);
			roff_body_alloc(mdoc, line, ppos, tok);
			if (tok == MDOC_Eo)
				continue;
		}

		if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
			break;
	}

	/* Clean-up to leave in a consistent state. */

	if (head == NULL) {
		rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));
		roff_body_alloc(mdoc, line, ppos, tok);
	}
	if (nl)
		append_delims(mdoc, line, pos, buf);
}
Example #2
0
/*
 * Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
 * They're unusual because they're basically free-form text until a
 * macro is encountered.
 */
static void
phrase_ta(MACRO_PROT_ARGS)
{
	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_ENDED)
			continue;
		if (n->tok == MDOC_It && n->type == ROFFT_BODY)
			body = n;
		if (n->tok == MDOC_Bl)
			break;
	}

	if (n == NULL || n->norm->Bl.type != LIST_column) {
		mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
		    line, ppos, "Ta");
		return;
	}

	/* Advance to the next column. */

	rew_last(mdoc, body);
	roff_body_alloc(mdoc, line, ppos, MDOC_It);
	parse_rest(mdoc, TOKEN_NONE, line, pos, buf);
}
Example #3
0
static void
man_descope(struct roff_man *man, int line, int offs)
{
	/*
	 * Co-ordinate what happens with having a next-line scope open:
	 * first close out the element scope (if applicable), then close
	 * out the block scope (also if applicable).
	 */

	if (man->flags & MAN_ELINE) {
		man->flags &= ~MAN_ELINE;
		man_unscope(man, man->last->parent);
	}
	if ( ! (man->flags & MAN_BLINE))
		return;
	man->flags &= ~MAN_BLINE;
	man_unscope(man, man->last->parent);
	roff_body_alloc(man, line, offs, man->last->tok);
}
Example #4
0
/*
 * Parse an implicit-block macro.  These contain a ROFFT_HEAD and a
 * ROFFT_BODY contained within a ROFFT_BLOCK.  Rules for closing out other
 * scopes, such as `SH' closing out an `SS', are defined in the rew
 * routines.
 */
void
blk_imp(MACRO_PROT_ARGS)
{
	int		 la;
	char		*p;
	struct roff_node *n;

	rew_scope(man, tok);
	n = roff_block_alloc(man, line, ppos, tok);
	if (n->tok == MAN_SH || n->tok == MAN_SS)
		man->flags &= ~MAN_LITERAL;
	n = roff_head_alloc(man, line, ppos, tok);

	/* Add line arguments. */

	for (;;) {
		la = *pos;
		if ( ! man_args(man, line, pos, buf, &p))
			break;
		roff_word_alloc(man, line, la, p);
	}

	/*
	 * For macros having optional next-line scope,
	 * keep the head open if there were no arguments.
	 * For `TP', always keep the head open.
	 */

	if (man_macros[tok].flags & MAN_SCOPED &&
	    (tok == MAN_TP || n == man->last)) {
		man->flags |= MAN_BLINE;
		return;
	}

	/* Close out the head and open the body. */

	man_unscope(man, n);
	roff_body_alloc(man, line, ppos, tok);
}
Example #5
0
void
blk_exp(MACRO_PROT_ARGS)
{
	struct roff_node *head;
	char		*p;
	int		 la;

	rew_scope(man, tok);
	roff_block_alloc(man, line, ppos, tok);
	head = roff_head_alloc(man, line, ppos, tok);

	la = *pos;
	if (man_args(man, line, pos, buf, &p))
		roff_word_alloc(man, line, la, p);

	if (buf[*pos] != '\0')
		mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,
		    *pos, "%s ... %s", roff_name[tok], buf + *pos);

	man_unscope(man, head);
	roff_body_alloc(man, line, ppos, tok);
}
Example #6
0
/*
 * Rewind up to a specific block, including all blocks that broke it.
 */
static void
rew_pending(struct roff_man *mdoc, const struct roff_node *n)
{

	for (;;) {
		rew_last(mdoc, n);

		if (mdoc->last == 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 ( ! (n->flags & MDOC_BROKEN))
				return;
		} else
			n = mdoc->last;

		for (;;) {
			if ((n = n->parent) == NULL)
				return;

			if (n->type == ROFFT_BLOCK ||
			    n->type == ROFFT_HEAD) {
				if (n->flags & MDOC_ENDED)
					break;
				else
					return;
			}
		}
	}
}
Example #7
0
static void
blk_full(MACRO_PROT_ARGS)
{
	int		  la, nl, parsed;
	struct mdoc_arg	 *arg;
	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_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,
					    mdoc->parse, line, ppos,
					    "It breaks %s",
					    mdoc_macronames[blk->tok]);
					rew_pending(mdoc, blk);
				}
				break;
			}

			if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
				switch (tok) {
				case MDOC_Sh:
				case MDOC_Ss:
					mandoc_vmsg(MANDOCERR_BLK_BROKEN,
					    mdoc->parse, line, ppos,
					    "%s breaks %s",
					    mdoc_macronames[tok],
					    mdoc_macronames[n->tok]);
					rew_pending(mdoc, n);
					n = mdoc->last;
					continue;
				case MDOC_It:
					/* Delay in case it's astray. */
					blk = n;
					continue;
				default:
					break;
				}
				break;
			}

			/* Here, n is one of Sh Ss Nm Nd It. */

			if (tok != MDOC_Sh && (n->tok == MDOC_Sh ||
			    (tok != MDOC_Ss && (n->tok == MDOC_Ss ||
			     (tok != MDOC_It && n->tok == MDOC_It)))))
				break;

			/* Item breaking an explicit block. */

			if (blk != NULL) {
				mandoc_vmsg(MANDOCERR_BLK_BROKEN,
				    mdoc->parse, line, ppos,
				    "It breaks %s",
				    mdoc_macronames[blk->tok]);
				rew_pending(mdoc, blk);
				blk = NULL;
			}

			/* Close out prior implicit scopes. */

			rew_last(mdoc, n);
		}

		/* Skip items outside lists. */

		if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
			mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
			    line, ppos, "It %s", buf + *pos);
			roff_elem_alloc(mdoc, line, ppos, MDOC_br);
			rew_elem(mdoc, MDOC_br);
			return;
		}
	}

	/*
	 * This routine accommodates implicitly- and explicitly-scoped
	 * macro openings.  Implicit ones first close out prior scope
	 * (seen above).  Delay opening the head until necessary to
	 * allow leading punctuation to print.  Special consideration
	 * for `It -column', which has phrase-part syntax instead of
	 * regular child nodes.
	 */

	mdoc_argv(mdoc, line, tok, &arg, pos, buf);
	blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg);
	head = body = NULL;

	/*
	 * Exception: Heads of `It' macros in `-diag' lists are not
	 * parsed, even though `It' macros in general are parsed.
	 */

	parsed = tok != MDOC_It ||
	    mdoc->last->parent->tok != MDOC_Bl ||
	    mdoc->last->parent->norm->Bl.type != LIST_diag;

	/*
	 * The `Nd' macro has all arguments in its body: it's a hybrid
	 * of block partial-explicit and full-implicit.  Stupid.
	 */

	if (tok == MDOC_Nd) {
		head = roff_head_alloc(mdoc, line, ppos, tok);
		rew_last(mdoc, head);
		body = roff_body_alloc(mdoc, line, ppos, tok);
	}

	if (tok == MDOC_Bk)
		mdoc->flags |= MDOC_KEEP;

	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_PHRASE ||
			    ! (mdoc->flags & MDOC_PHRASEQF))
				break;

			/*
			 * 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",
			    mdoc_macronames[tok], buf + la);
			break;
		}
		if (tok == MDOC_Rs) {
			mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
			    line, la, "Rs %s", buf + la);
			break;
		}
		if (ac == ARGS_PUNCT)
			break;

		/*
		 * Emit leading punctuation (i.e., punctuation before
		 * the ROFFT_HEAD) for non-phrase types.
		 */

		if (head == NULL &&
		    ac != ARGS_PHRASE &&
		    ac != ARGS_QWORD &&
		    mdoc_isdelim(p) == DELIM_OPEN) {
			dword(mdoc, line, la, p, DELIM_OPEN, 0);
			continue;
		}

		/* Open a head if one hasn't been opened. */

		if (head == NULL)
			head = roff_head_alloc(mdoc, line, ppos, tok);

		if (ac == ARGS_PHRASE) {

			/*
			 * If we haven't opened a body yet, rewind the
			 * head; if we have, rewind that instead.
			 */

			rew_last(mdoc, body == NULL ? head : body);
			body = roff_body_alloc(mdoc, line, ppos, tok);

			/* Process to the tab or to the end of the line. */

			mdoc->flags |= MDOC_PHRASE;
			parse_rest(mdoc, TOKEN_NONE, line, &la, buf);
			mdoc->flags &= ~MDOC_PHRASE;

			/* There may have been `Ta' macros. */

			while (body->next != NULL)
				body = body->next;
			continue;
		}

		if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed))
			break;
	}

	if (blk->flags & MDOC_VALID)
		return;
	if (head == NULL)
		head = roff_head_alloc(mdoc, line, ppos, tok);
	if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs)
		append_delims(mdoc, line, pos, buf);
	if (body != NULL)
		goto out;
	if (find_pending(mdoc, tok, line, ppos, head))
		return;

	/* Close out scopes to remain in a consistent state. */

	rew_last(mdoc, head);
	body = roff_body_alloc(mdoc, line, ppos, tok);
out:
	if (mdoc->flags & MDOC_FREECOL) {
		rew_last(mdoc, body);
		rew_last(mdoc, blk);
		mdoc->flags &= ~MDOC_FREECOL;
	}
}
Example #8
0
static void
blk_part_imp(MACRO_PROT_ARGS)
{
	int		  la, nl;
	enum margserr	  ac;
	char		 *p;
	struct roff_node *blk; /* saved block context */
	struct roff_node *body; /* saved body context */
	struct roff_node *n;

	nl = MDOC_NEWLINE & mdoc->flags;

	/*
	 * A macro that spans to the end of the line.  This is generally
	 * (but not necessarily) called as the first macro.  The block
	 * has a head as the immediate child, which is always empty,
	 * followed by zero or more opening punctuation nodes, then the
	 * body (which may be empty, depending on the macro), then zero
	 * or more closing punctuation nodes.
	 */

	blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
	rew_last(mdoc, roff_head_alloc(mdoc, line, ppos, tok));

	/*
	 * Open the body scope "on-demand", that is, after we've
	 * processed all our the leading delimiters (open parenthesis,
	 * etc.).
	 */

	for (body = NULL; ; ) {
		la = *pos;
		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
		if (ac == ARGS_EOLN || ac == ARGS_PUNCT)
			break;

		if (body == NULL && ac != ARGS_QWORD &&
		    mdoc_isdelim(p) == DELIM_OPEN) {
			dword(mdoc, line, la, p, DELIM_OPEN, 0);
			continue;
		}

		if (body == NULL)
			body = roff_body_alloc(mdoc, line, ppos, tok);

		if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
			break;
	}
	if (body == NULL)
		body = roff_body_alloc(mdoc, line, ppos, tok);

	if (find_pending(mdoc, tok, line, ppos, body))
		return;

	rew_last(mdoc, body);
	if (nl)
		append_delims(mdoc, line, pos, buf);
	rew_pending(mdoc, blk);

	/* Move trailing .Ns out of scope. */

	for (n = body->child; n && n->next; n = n->next)
		/* Do nothing. */ ;
	if (n && n->tok == MDOC_Ns)
		mdoc_node_relink(mdoc, n);
}
Example #9
0
void
man_breakscope(struct roff_man *man, int tok)
{
	struct roff_node *n;

	/*
	 * An element next line scope is open,
	 * and the new macro is not allowed inside elements.
	 * Delete the element that is being broken.
	 */

	if (man->flags & MAN_ELINE && (tok < MAN_TH ||
	    ! (man_macros[tok].flags & MAN_NSCOPED))) {
		n = man->last;
		assert(n->type != ROFFT_TEXT);
		if (man_macros[n->tok].flags & MAN_NSCOPED)
			n = n->parent;

		mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
		    n->line, n->pos, "%s breaks %s",
		    roff_name[tok], roff_name[n->tok]);

		roff_node_delete(man, n);
		man->flags &= ~MAN_ELINE;
	}

	/*
	 * Weird special case:
	 * Switching fill mode closes section headers.
	 */

	if (man->flags & MAN_BLINE &&
	    (tok == MAN_nf || tok == MAN_fi) &&
	    (man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
		n = man->last;
		man_unscope(man, n);
		roff_body_alloc(man, n->line, n->pos, n->tok);
		man->flags &= ~MAN_BLINE;
	}

	/*
	 * A block header next line scope is open,
	 * and the new macro is not allowed inside block headers.
	 * Delete the block that is being broken.
	 */

	if (man->flags & MAN_BLINE && (tok < MAN_TH ||
	    man_macros[tok].flags & MAN_BSCOPE)) {
		n = man->last;
		if (n->type == ROFFT_TEXT)
			n = n->parent;
		if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
			n = n->parent;

		assert(n->type == ROFFT_HEAD);
		n = n->parent;
		assert(n->type == ROFFT_BLOCK);
		assert(man_macros[n->tok].flags & MAN_SCOPED);

		mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
		    n->line, n->pos, "%s breaks %s",
		    roff_name[tok], roff_name[n->tok]);

		roff_node_delete(man, n);
		man->flags &= ~MAN_BLINE;
	}
}
Example #10
0
static int
man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
{
	struct roff_node *n;
	const char	*cp;
	size_t		 sz;
	enum roff_tok	 tok;
	int		 ppos;
	int		 bline;

	/* Determine the line macro. */

	ppos = offs;
	tok = TOKEN_NONE;
	for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
		offs++;
	if (sz > 0 && sz < 4)
		tok = roffhash_find(man->manmac, buf + ppos, sz);
	if (tok == TOKEN_NONE) {
		mandoc_msg(MANDOCERR_MACRO, man->parse,
		    ln, ppos, buf + ppos - 1);
		return 1;
	}

	/* Skip a leading escape sequence or tab. */

	switch (buf[offs]) {
	case '\\':
		cp = buf + offs + 1;
		mandoc_escape(&cp, NULL, NULL);
		offs = cp - buf;
		break;
	case '\t':
		offs++;
		break;
	default:
		break;
	}

	/* Jump to the next non-whitespace word. */

	while (buf[offs] == ' ')
		offs++;

	/*
	 * Trailing whitespace.  Note that tabs are allowed to be passed
	 * into the parser as "text", so we only warn about spaces here.
	 */

	if (buf[offs] == '\0' && buf[offs - 1] == ' ')
		mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
		    ln, offs - 1, NULL);

	/*
	 * Some macros break next-line scopes; otherwise, remember
	 * whether we are in next-line scope for a block head.
	 */

	man_breakscope(man, tok);
	bline = man->flags & MAN_BLINE;

	/*
	 * If the line in next-line scope ends with \c, keep the
	 * next-line scope open for the subsequent input line.
	 * That is not at all portable, only groff >= 1.22.4
	 * does it, but *if* this weird idiom occurs in a manual
	 * page, that's very likely what the author intended.
	 */

	if (bline) {
		cp = strchr(buf + offs, '\0') - 2;
		if (cp >= buf && cp[0] == '\\' && cp[1] == 'c')
			bline = 0;
	}

	/* Call to handler... */

	assert(man_macros[tok].fp);
	(*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);

	/* In quick mode (for mandocdb), abort after the NAME section. */

	if (man->quick && tok == MAN_SH) {
		n = man->last;
		if (n->type == ROFFT_BODY &&
		    strcmp(n->prev->child->string, "NAME"))
			return 2;
	}

	/*
	 * If we are in a next-line scope for a block head,
	 * close it out now and switch to the body,
	 * unless the next-line scope is allowed to continue.
	 */

	if ( ! bline || man->flags & MAN_ELINE ||
	    man_macros[tok].flags & MAN_NSCOPED)
		return 1;

	assert(man->flags & MAN_BLINE);
	man->flags &= ~MAN_BLINE;

	man_unscope(man, man->last->parent);
	roff_body_alloc(man, ln, ppos, man->last->tok);
	return 1;
}
Example #11
0
static int
man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
{
	struct roff_node *n;
	const char	*cp;
	int		 tok;
	int		 i, ppos;
	int		 bline;
	char		 mac[5];

	ppos = offs;

	/*
	 * Copy the first word into a nil-terminated buffer.
	 * Stop when a space, tab, escape, or eoln is encountered.
	 */

	i = 0;
	while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
		mac[i++] = buf[offs++];

	mac[i] = '\0';

	tok = (i > 0 && i < 4) ? man_hash_find(mac) : TOKEN_NONE;

	if (tok == TOKEN_NONE) {
		mandoc_msg(MANDOCERR_MACRO, man->parse,
		    ln, ppos, buf + ppos - 1);
		return 1;
	}

	/* Skip a leading escape sequence or tab. */

	switch (buf[offs]) {
	case '\\':
		cp = buf + offs + 1;
		mandoc_escape(&cp, NULL, NULL);
		offs = cp - buf;
		break;
	case '\t':
		offs++;
		break;
	default:
		break;
	}

	/* Jump to the next non-whitespace word. */

	while (buf[offs] && buf[offs] == ' ')
		offs++;

	/*
	 * Trailing whitespace.  Note that tabs are allowed to be passed
	 * into the parser as "text", so we only warn about spaces here.
	 */

	if (buf[offs] == '\0' && buf[offs - 1] == ' ')
		mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
		    ln, offs - 1, NULL);

	/*
	 * Some macros break next-line scopes; otherwise, remember
	 * whether we are in next-line scope for a block head.
	 */

	man_breakscope(man, tok);
	bline = man->flags & MAN_BLINE;

	/* Call to handler... */

	assert(man_macros[tok].fp);
	(*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);

	/* In quick mode (for mandocdb), abort after the NAME section. */

	if (man->quick && tok == MAN_SH) {
		n = man->last;
		if (n->type == ROFFT_BODY &&
		    strcmp(n->prev->child->string, "NAME"))
			return 2;
	}

	/*
	 * If we are in a next-line scope for a block head,
	 * close it out now and switch to the body,
	 * unless the next-line scope is allowed to continue.
	 */

	if ( ! bline || man->flags & MAN_ELINE ||
	    man_macros[tok].flags & MAN_NSCOPED)
		return 1;

	assert(man->flags & MAN_BLINE);
	man->flags &= ~MAN_BLINE;

	man_unscope(man, man->last->parent);
	roff_body_alloc(man, ln, ppos, man->last->tok);
	return 1;
}