예제 #1
0
파일: mdoc_macro.c 프로젝트: UNGLinux/Obase
/*
 * 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 int
phrase(struct mdoc *m, int line, int ppos, char *buf)
{
	int		 la, pos;
	enum margserr	 ac;
	enum mdoct	 ntok;
	char		*p;

	for (pos = ppos; ; ) {
		la = pos;

		ac = mdoc_zargs(m, line, &pos, buf, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_EOLN == ac)
			break;

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);

		if (MDOC_MAX == ntok) {
			if ( ! dword(m, line, la, p, DELIM_MAX))
				return(0);
			continue;
		}

		if ( ! mdoc_macro(m, ntok, line, la, &pos, buf))
			return(0);
		return(append_delims(m, line, &pos, buf));
	}

	return(1);
}
예제 #2
0
/*
 * Parse one word.
 * If it is a macro, call it and return 1.
 * Otherwise, allocate it and return 0.
 */
static int
macro_or_word(MACRO_PROT_ARGS, int parsed)
{
	char		*p;
	int		 ntok;

	p = buf + ppos;
	ntok = TOKEN_NONE;
	if (*p == '"')
		p++;
	else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT))
		ntok = lookup(mdoc, tok, line, ppos, p);

	if (ntok == TOKEN_NONE) {
		dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE ||
		    mdoc_macros[tok].flags & MDOC_JOIN);
		return 0;
	} else {
		if (mdoc_macros[tok].fp == in_line_eoln)
			rew_elem(mdoc, tok);
		mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
		if (tok == TOKEN_NONE)
			append_delims(mdoc, line, pos, buf);
		return 1;
	}
}
/* ARGSUSED */
static int
phrase_ta(MACRO_PROT_ARGS)
{
	struct mdoc_node *n;
	int		  la;
	enum mdoct	  ntok;
	enum margserr	  ac;
	char		 *p;

	/* Make sure we are in a column list or ignore this macro. */
	n = mdoc->last;
	while (NULL != n && MDOC_Bl != n->tok)
		n = n->parent;
	if (NULL == n || LIST_column != n->norm->Bl.type) {
		mdoc_pmsg(mdoc, line, ppos, MANDOCERR_STRAYTA);
		return(1);
	}

	/* Advance to the next column. */
	if ( ! rew_sub(MDOC_BODY, mdoc, MDOC_It, line, ppos))
		return(0);
	if ( ! mdoc_body_alloc(mdoc, line, ppos, MDOC_It))
		return(0);

	for (;;) {
		la = *pos;
		ac = mdoc_zargs(mdoc, line, pos, buf, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_EOLN == ac)
			break;

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);

		if (MDOC_MAX == ntok) {
			if ( ! dword(mdoc, line, la, p, DELIM_MAX,
			    MDOC_JOIN & mdoc_macros[tok].flags))
				return(0);
			continue;
		}

		if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
			return(0);
		return(append_delims(mdoc, line, pos, buf));
	}

	return(1);
}
예제 #4
0
파일: mdoc_macro.c 프로젝트: UNGLinux/Obase
/* ARGSUSED */
static int
phrase_ta(MACRO_PROT_ARGS)
{
	int		  la;
	enum mdoct	  ntok;
	enum margserr	  ac;
	char		 *p;

	/*
	 * FIXME: this is overly restrictive: if the `Ta' is unexpected,
	 * it should simply error out with ARGSLOST.
	 */

	if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos))
		return(0);
	if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It))
		return(0);

	for (;;) {
		la = *pos;
		ac = mdoc_zargs(m, line, pos, buf, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_EOLN == ac)
			break;

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);

		if (MDOC_MAX == ntok) {
			if ( ! dword(m, line, la, p, DELIM_MAX))
				return(0);
			continue;
		}

		if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
			return(0);
		return(append_delims(m, line, pos, buf));
	}

	return(1);
}
예제 #5
0
/*
 * Close out block partial/full explicit.
 */
static void
blk_exp_close(MACRO_PROT_ARGS)
{
	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. */
	struct roff_node *target;	/* For find_pending(). */

	int		 j, lastarg, maxargs, nl, pending;
	enum margserr	 ac;
	int		 atok, ntok;
	char		*p;

	nl = MDOC_NEWLINE & mdoc->flags;

	switch (tok) {
	case MDOC_Ec:
		maxargs = 1;
		break;
	case MDOC_Ek:
		mdoc->flags &= ~MDOC_KEEP;
		/* FALLTHROUGH */
	default:
		maxargs = 0;
		break;
	}

	/*
	 * Search backwards for beginnings of blocks,
	 * both of our own and of pending sub-blocks.
	 */

	atok = rew_alt(tok);
	body = endbody = itblk = later = NULL;
	for (n = mdoc->last; n; n = n->parent) {
		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 == ROFFT_BODY && atok == n->tok) {
			if (n->end == ENDBODY_NOT)
				body = n;
			continue;
		}

		if (n->type != ROFFT_BLOCK || n->tok == MDOC_Nm)
			continue;

		if (n->tok == MDOC_It) {
			itblk = n;
			continue;
		}

		if (atok == n->tok) {
			assert(body);

			/*
			 * Found the start of our own block.
			 * When there is no pending sub block,
			 * just proceed to closing out.
			 */

			if (later == NULL ||
			    (tok == MDOC_El && itblk == NULL))
				break;

			/*
			 * When there is a pending sub block, postpone
			 * closing out the current block until the
			 * rew_pending() closing out the sub-block.
			 * 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
			 * into the end marker.
			 */

			if (maxargs)
				mdoc->next = ROFF_NEXT_CHILD;
			break;
		}

		/* Explicit blocks close out description lines. */

		if (n->tok == MDOC_Nd) {
			rew_last(mdoc, n);
			continue;
		}

		/* Breaking an open sub block. */

		n->flags |= MDOC_BROKEN;
		if (later == NULL)
			later = n;
	}

	if (body == NULL) {
		mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
		    line, ppos, mdoc_macronames[tok]);
		if (later != NULL)
			later->flags &= ~MDOC_BROKEN;
		if (maxargs && endbody == NULL) {
			/*
			 * Stray .Ec without previous .Eo:
			 * Break the output line, keep the arguments.
			 */
			roff_elem_alloc(mdoc, line, ppos, MDOC_br);
			rew_elem(mdoc, MDOC_br);
		}
	} else if (endbody == NULL) {
		rew_last(mdoc, body);
		if (maxargs)
			mdoc_tail_alloc(mdoc, line, ppos, atok);
	}

	if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
		if (buf[*pos] != '\0')
			mandoc_vmsg(MANDOCERR_ARG_SKIP,
			    mdoc->parse, line, ppos,
			    "%s %s", mdoc_macronames[tok],
			    buf + *pos);
		if (endbody == NULL && n != NULL)
			rew_pending(mdoc, n);
		return;
	}

	if (endbody != NULL)
		n = endbody;

	ntok = TOKEN_NONE;
	for (j = 0; ; j++) {
		lastarg = *pos;

		if (j == maxargs && n != NULL)
			rew_last(mdoc, n);

		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
		if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
			break;

		ntok = ac == ARGS_QWORD ? TOKEN_NONE :
		    lookup(mdoc, tok, line, lastarg, p);

		if (ntok == TOKEN_NONE) {
			dword(mdoc, line, lastarg, p, DELIM_MAX,
			    MDOC_JOIN & mdoc_macros[tok].flags);
			continue;
		}

		if (n != NULL)
			rew_last(mdoc, n);
		mdoc->flags &= ~MDOC_NEWLINE;
		mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
		break;
	}

	if (n != NULL) {
		if (ntok != TOKEN_NONE && n->flags & MDOC_BROKEN) {
			target = n;
			do
				target = target->parent;
			while ( ! (target->flags & MDOC_ENDED));
			pending = find_pending(mdoc, ntok, line, ppos,
			    target);
		} else
			pending = 0;
		if ( ! pending)
			rew_pending(mdoc, n);
	}
	if (nl)
		append_delims(mdoc, line, pos, buf);
}
예제 #6
0
static void
in_line(MACRO_PROT_ARGS)
{
	int		 la, scope, cnt, firstarg, mayopen, nc, nl;
	int		 ntok;
	enum margserr	 ac;
	enum mdelim	 d;
	struct mdoc_arg	*arg;
	char		*p;

	nl = MDOC_NEWLINE & mdoc->flags;

	/*
	 * Whether we allow ignored elements (those without content,
	 * usually because of reserved words) to squeak by.
	 */

	switch (tok) {
	case MDOC_An:
	case MDOC_Ar:
	case MDOC_Fl:
	case MDOC_Mt:
	case MDOC_Nm:
	case MDOC_Pa:
		nc = 1;
		break;
	default:
		nc = 0;
		break;
	}

	mdoc_argv(mdoc, line, tok, &arg, pos, buf);

	d = DELIM_NONE;
	firstarg = 1;
	mayopen = 1;
	for (cnt = scope = 0;; ) {
		la = *pos;
		ac = mdoc_args(mdoc, line, pos, buf, tok, &p);

		/*
		 * At the end of a macro line,
		 * opening delimiters do not suppress spacing.
		 */

		if (ac == ARGS_EOLN) {
			if (d == DELIM_OPEN)
				mdoc->last->flags &= ~MDOC_DELIMO;
			break;
		}

		/*
		 * The rest of the macro line is only punctuation,
		 * to be handled by append_delims().
		 * If there were no other arguments,
		 * do not allow the first one to suppress spacing,
		 * even if it turns out to be a closing one.
		 */

		if (ac == ARGS_PUNCT) {
			if (cnt == 0 && (nc == 0 || tok == MDOC_An))
				mdoc->flags |= MDOC_NODELIMC;
			break;
		}

		ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ?
		    TOKEN_NONE : lookup(mdoc, tok, line, la, p);

		/*
		 * In this case, we've located a submacro and must
		 * execute it.  Close out scope, if open.  If no
		 * elements have been generated, either create one (nc)
		 * or raise a warning.
		 */

		if (ntok != TOKEN_NONE) {
			if (scope)
				rew_elem(mdoc, tok);
			if (nc && ! cnt) {
				mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
				rew_last(mdoc, mdoc->last);
			} else if ( ! nc && ! cnt) {
				mdoc_argv_free(arg);
				mandoc_msg(MANDOCERR_MACRO_EMPTY,
				    mdoc->parse, line, ppos,
				    mdoc_macronames[tok]);
			}
			mdoc_macro(mdoc, ntok, line, la, pos, buf);
			if (nl)
				append_delims(mdoc, line, pos, buf);
			return;
		}

		/*
		 * Non-quote-enclosed punctuation.  Set up our scope, if
		 * a word; rewind the scope, if a delimiter; then append
		 * the word.
		 */

		d = ac == ARGS_QWORD ? DELIM_NONE : mdoc_isdelim(p);

		if (DELIM_NONE != d) {
			/*
			 * If we encounter closing punctuation, no word
			 * has been emitted, no scope is open, and we're
			 * allowed to have an empty element, then start
			 * a new scope.
			 */
			if ((d == DELIM_CLOSE ||
			     (d == DELIM_MIDDLE && tok == MDOC_Fl)) &&
			    !cnt && !scope && nc && mayopen) {
				mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
				scope = 1;
				cnt++;
				if (tok == MDOC_Nm)
					mayopen = 0;
			}
			/*
			 * Close out our scope, if one is open, before
			 * any punctuation.
			 */
			if (scope)
				rew_elem(mdoc, tok);
			scope = 0;
			if (tok == MDOC_Fn)
				mayopen = 0;
		} else if (mayopen && !scope) {
			mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
			scope = 1;
			cnt++;
		}

		dword(mdoc, line, la, p, d,
		    MDOC_JOIN & mdoc_macros[tok].flags);

		/*
		 * If the first argument is a closing delimiter,
		 * do not suppress spacing before it.
		 */

		if (firstarg && d == DELIM_CLOSE && !nc)
			mdoc->last->flags &= ~MDOC_DELIMC;
		firstarg = 0;

		/*
		 * `Fl' macros have their scope re-opened with each new
		 * word so that the `-' can be added to each one without
		 * having to parse out spaces.
		 */
		if (scope && tok == MDOC_Fl) {
			rew_elem(mdoc, tok);
			scope = 0;
		}
	}

	if (scope)
		rew_elem(mdoc, tok);

	/*
	 * If no elements have been collected and we're allowed to have
	 * empties (nc), open a scope and close it out.  Otherwise,
	 * raise a warning.
	 */

	if ( ! cnt) {
		if (nc) {
			mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
			rew_last(mdoc, mdoc->last);
		} else {
			mdoc_argv_free(arg);
			mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
			    line, ppos, mdoc_macronames[tok]);
		}
	}
	if (nl)
		append_delims(mdoc, line, pos, buf);
}
예제 #7
0
static void
in_line_argn(MACRO_PROT_ARGS)
{
	struct mdoc_arg	*arg;
	char		*p;
	enum margserr	 ac;
	int		 ntok;
	int		 state; /* arg#; -1: not yet open; -2: closed */
	int		 la, maxargs, nl;

	nl = mdoc->flags & MDOC_NEWLINE;

	/*
	 * A line macro that has a fixed number of arguments (maxargs).
	 * Only open the scope once the first non-leading-punctuation is
	 * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
	 * keep it open until the maximum number of arguments are
	 * exhausted.
	 */

	switch (tok) {
	case MDOC_Ap:
	case MDOC_Ns:
	case MDOC_Ux:
		maxargs = 0;
		break;
	case MDOC_Bx:
	case MDOC_Es:
	case MDOC_Xr:
		maxargs = 2;
		break;
	default:
		maxargs = 1;
		break;
	}

	mdoc_argv(mdoc, line, tok, &arg, pos, buf);

	state = -1;
	p = NULL;
	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 (abs(state) < 2 && tok == MDOC_Pf)
				mandoc_vmsg(MANDOCERR_PF_SKIP,
				    mdoc->parse, line, ppos, "Pf %s",
				    p == NULL ? "at eol" : p);
			break;
		}

		if (state == maxargs) {
			rew_elem(mdoc, tok);
			state = -2;
		}

		ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && state == 0)) ?
		    TOKEN_NONE : lookup(mdoc, tok, line, la, p);

		if (ntok != TOKEN_NONE) {
			if (state >= 0) {
				rew_elem(mdoc, tok);
				state = -2;
			}
			mdoc_macro(mdoc, ntok, line, la, pos, buf);
			break;
		}

		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);
			state = -2;
		}

		dword(mdoc, line, la, p, DELIM_MAX,
		    MDOC_JOIN & mdoc_macros[tok].flags);
	}

	if (state == -1) {
		mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
		    line, ppos, mdoc_macronames[tok]);
		return;
	}

	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);
}
예제 #8
0
/*
 * Close out block partial/full explicit.  
 */
static int
blk_exp_close(MACRO_PROT_ARGS)
{
	int	 	 j, lastarg, maxargs, flushed, nl;
	enum margserr	 ac;
	enum mdoct	 ntok;
	char		*p;

	nl = MDOC_NEWLINE & m->flags;

	switch (tok) {
	case (MDOC_Ec):
		maxargs = 1;
		break;
	default:
		maxargs = 0;
		break;
	}

	if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
		/* FIXME: do this in validate */
		if (buf[*pos]) 
			if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST))
				return(0);

		if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
			return(0);
		return(rew_sub(MDOC_BLOCK, m, tok, line, ppos));
	}

	if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
		return(0);

	if (maxargs > 0) 
		if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok)))
			return(0);

	for (flushed = j = 0; ; j++) {
		lastarg = *pos;

		if (j == maxargs && ! flushed) {
			if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
				return(0);
			flushed = 1;
		}

		ac = mdoc_args(m, line, pos, buf, tok, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_PUNCT == ac)
			break;
		if (ARGS_EOLN == ac)
			break;

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);

		if (MDOC_MAX == ntok) {
			if ( ! mdoc_word_alloc(m, line, lastarg, p))
				return(0);
			continue;
		}

		if ( ! flushed) {
			if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
				return(0);
			flushed = 1;
		}
		if ( ! mdoc_macro(m, ntok, line, lastarg, pos, buf))
			return(0);
		break;
	}

	if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
		return(0);

	if ( ! nl)
		return(1);
	return(append_delims(m, line, pos, buf));
}
예제 #9
0
/*
 * Parse free-form text, that is, a line that does not begin with the
 * control character.
 */
static int
mdoc_ptext(struct mdoc *m, int line, char *buf, int offs)
{
    char		 *c, *ws, *end;
    struct mdoc_node *n;

    /* Ignore bogus comments. */

    if ('\\' == buf[offs] &&
            '.' == buf[offs + 1] &&
            '"' == buf[offs + 2]) {
        mdoc_pmsg(m, line, offs, MANDOCERR_BADCOMMENT);
        return(1);
    }

    /* No text before an initial macro. */

    if (SEC_NONE == m->lastnamed) {
        mdoc_pmsg(m, line, offs, MANDOCERR_NOTEXT);
        return(1);
    }

    assert(m->last);
    n = m->last;

    /*
     * Divert directly to list processing if we're encountering a
     * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry
     * (a MDOC_BODY means it's already open, in which case we should
     * process within its context in the normal way).
     */

    if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
            LIST_column == n->norm->Bl.type) {
        /* `Bl' is open without any children. */
        m->flags |= MDOC_FREECOL;
        return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf));
    }

    if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
            NULL != n->parent &&
            MDOC_Bl == n->parent->tok &&
            LIST_column == n->parent->norm->Bl.type) {
        /* `Bl' has block-level `It' children. */
        m->flags |= MDOC_FREECOL;
        return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf));
    }

    /*
     * Search for the beginning of unescaped trailing whitespace (ws)
     * and for the first character not to be output (end).
     */

    /* FIXME: replace with strcspn(). */
    ws = NULL;
    for (c = end = buf + offs; *c; c++) {
        switch (*c) {
        case '-':
            if (mandoc_hyph(buf + offs, c))
                *c = ASCII_HYPH;
            ws = NULL;
            break;
        case ' ':
            if (NULL == ws)
                ws = c;
            continue;
        case '\t':
            /*
             * Always warn about trailing tabs,
             * even outside literal context,
             * where they should be put on the next line.
             */
            if (NULL == ws)
                ws = c;
            /*
             * Strip trailing tabs in literal context only;
             * outside, they affect the next line.
             */
            if (MDOC_LITERAL & m->flags)
                continue;
            break;
        case '\\':
            /* Skip the escaped character, too, if any. */
            if (c[1])
                c++;
        /* FALLTHROUGH */
        default:
            ws = NULL;
            break;
        }
        end = c + 1;
    }
    *end = '\0';

    if (ws)
        mdoc_pmsg(m, line, (int)(ws-buf), MANDOCERR_EOLNSPACE);

    if ('\0' == buf[offs] && ! (MDOC_LITERAL & m->flags)) {
        mdoc_pmsg(m, line, (int)(c-buf), MANDOCERR_NOBLANKLN);

        /*
         * Insert a `sp' in the case of a blank line.  Technically,
         * blank lines aren't allowed, but enough manuals assume this
         * behaviour that we want to work around it.
         */
        if ( ! mdoc_elem_alloc(m, line, offs, MDOC_sp, NULL))
            return(0);

        m->next = MDOC_NEXT_SIBLING;
        return(1);
    }

    if ( ! mdoc_word_alloc(m, line, offs, buf+offs))
        return(0);

    if (MDOC_LITERAL & m->flags)
        return(1);

    /*
     * End-of-sentence check.  If the last character is an unescaped
     * EOS character, then flag the node as being the end of a
     * sentence.  The front-end will know how to interpret this.
     */

    assert(buf < end);

    if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0))
        m->last->flags |= MDOC_EOS;

    return(1);
}
예제 #10
0
/*
 * Parse a macro line, that is, a line beginning with the control
 * character.
 */
static int
mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs)
{
    enum mdoct	  tok;
    int		  i, j, sv;
    char		  mac[5];
    struct mdoc_node *n;

    /* Empty lines are ignored. */

    offs++;

    if ('\0' == buf[offs])
        return(1);

    i = offs;

    /* Accept tabs/whitespace after the initial control char. */

    if (' ' == buf[i] || '\t' == buf[i]) {
        i++;
        while (buf[i] && (' ' == buf[i] || '\t' == buf[i]))
            i++;
        if ('\0' == buf[i])
            return(1);
    }

    sv = i;

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

    j = 0;
    while (j < 4 && '\0' != buf[i] && ' ' != buf[i] && '\t' != buf[i])
        mac[j++] = buf[i++];
    mac[j] = '\0';

    tok = (j > 1 || j < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
    if (MDOC_MAX == tok) {
        mdoc_vmsg(m, MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1);
        return(1);
    }

    /* Disregard the first trailing tab, if applicable. */

    if ('\t' == buf[i])
        i++;

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

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

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

    if ('\0' == buf[i] && ' ' == buf[i - 1])
        mdoc_pmsg(m, ln, i - 1, MANDOCERR_EOLNSPACE);

    /*
     * If an initial macro or a list invocation, divert directly
     * into macro processing.
     */

    if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) {
        if ( ! mdoc_macro(m, tok, ln, sv, &i, buf))
            goto err;
        return(1);
    }

    n = m->last;
    assert(m->last);

    /*
     * If the first macro of a `Bl -column', open an `It' block
     * context around the parsed macro.
     */

    if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
            LIST_column == n->norm->Bl.type) {
        m->flags |= MDOC_FREECOL;
        if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
            goto err;
        return(1);
    }

    /*
     * If we're following a block-level `It' within a `Bl -column'
     * context (perhaps opened in the above block or in ptext()),
     * then open an `It' block context around the parsed macro.
     */

    if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
            NULL != n->parent &&
            MDOC_Bl == n->parent->tok &&
            LIST_column == n->parent->norm->Bl.type) {
        m->flags |= MDOC_FREECOL;
        if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf))
            goto err;
        return(1);
    }

    /* Normal processing of a macro. */

    if ( ! mdoc_macro(m, tok, ln, sv, &i, buf))
        goto err;

    return(1);

err:	/* Error out. */

    m->flags |= MDOC_HALT;
    return(0);
}
예제 #11
0
파일: mdoc_macro.c 프로젝트: UNGLinux/Obase
static int
in_line(MACRO_PROT_ARGS)
{
	int		 la, scope, cnt, nc, nl;
	enum margverr	 av;
	enum mdoct	 ntok;
	enum margserr	 ac;
	enum mdelim	 d;
	struct mdoc_arg	*arg;
	char		*p;

	nl = MDOC_NEWLINE & m->flags;

	/*
	 * Whether we allow ignored elements (those without content,
	 * usually because of reserved words) to squeak by.
	 */

	switch (tok) {
	case (MDOC_An):
		/* FALLTHROUGH */
	case (MDOC_Ar):
		/* FALLTHROUGH */
	case (MDOC_Fl):
		/* FALLTHROUGH */
	case (MDOC_Mt):
		/* FALLTHROUGH */
	case (MDOC_Nm):
		/* FALLTHROUGH */
	case (MDOC_Pa):
		nc = 1;
		break;
	default:
		nc = 0;
		break;
	}

	for (arg = NULL;; ) {
		la = *pos;
		av = mdoc_argv(m, line, tok, &arg, pos, buf);

		if (ARGV_WORD == av) {
			*pos = la;
			break;
		} 
		if (ARGV_EOLN == av)
			break;
		if (ARGV_ARG == av)
			continue;

		mdoc_argv_free(arg);
		return(0);
	}

	for (cnt = scope = 0;; ) {
		la = *pos;
		ac = mdoc_args(m, line, pos, buf, tok, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_EOLN == ac)
			break;
		if (ARGS_PUNCT == ac)
			break;

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);

		/* 
		 * In this case, we've located a submacro and must
		 * execute it.  Close out scope, if open.  If no
		 * elements have been generated, either create one (nc)
		 * or raise a warning.
		 */

		if (MDOC_MAX != ntok) {
			if (scope && ! rew_elem(m, tok))
				return(0);
			if (nc && 0 == cnt) {
				if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
					return(0);
				if ( ! rew_last(m, m->last))
					return(0);
			} else if ( ! nc && 0 == cnt) {
				mdoc_argv_free(arg);
				mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY);
			}

			if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
				return(0);
			if ( ! nl)
				return(1);
			return(append_delims(m, line, pos, buf));
		} 

		/* 
		 * Non-quote-enclosed punctuation.  Set up our scope, if
		 * a word; rewind the scope, if a delimiter; then append
		 * the word. 
		 */

		d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p);

		if (DELIM_NONE != d) {
			/*
			 * If we encounter closing punctuation, no word
			 * has been omitted, no scope is open, and we're
			 * allowed to have an empty element, then start
			 * a new scope.  `Ar', `Fl', and `Li', only do
			 * this once per invocation.  There may be more
			 * of these (all of them?).
			 */
			if (0 == cnt && (nc || MDOC_Li == tok) && 
					DELIM_CLOSE == d && ! scope) {
				if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
					return(0);
				if (MDOC_Ar == tok || MDOC_Li == tok || 
						MDOC_Fl == tok)
					cnt++;
				scope = 1;
			}
			/*
			 * Close out our scope, if one is open, before
			 * any punctuation.
			 */
			if (scope && ! rew_elem(m, tok))
				return(0);
			scope = 0;
		} else if ( ! scope) {
			if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
				return(0);
			scope = 1;
		}

		if (DELIM_NONE == d)
			cnt++;

		if ( ! dword(m, line, la, p, d))
			return(0);

		/*
		 * `Fl' macros have their scope re-opened with each new
		 * word so that the `-' can be added to each one without
		 * having to parse out spaces.
		 */
		if (scope && MDOC_Fl == tok) {
			if ( ! rew_elem(m, tok))
				return(0);
			scope = 0;
		}
	}

	if (scope && ! rew_elem(m, tok))
		return(0);

	/*
	 * If no elements have been collected and we're allowed to have
	 * empties (nc), open a scope and close it out.  Otherwise,
	 * raise a warning.
	 */

	if (nc && 0 == cnt) {
		if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
			return(0);
		if ( ! rew_last(m, m->last))
			return(0);
	} else if ( ! nc && 0 == cnt) {
		mdoc_argv_free(arg);
		mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY);
	}

	if ( ! nl)
		return(1);
	return(append_delims(m, line, pos, buf));
}
예제 #12
0
파일: mdoc_macro.c 프로젝트: UNGLinux/Obase
static int
blk_full(MACRO_PROT_ARGS)
{
	int		  la, nl, nparsed;
	struct mdoc_arg	 *arg;
	struct mdoc_node *head; /* save of head macro */
	struct mdoc_node *body; /* save of body macro */
	struct mdoc_node *n;
	enum mdoc_type	  mtt;
	enum mdoct	  ntok;
	enum margserr	  ac, lac;
	enum margverr	  av;
	char		 *p;

	nl = MDOC_NEWLINE & m->flags;

	/* Close out prior implicit scope. */

	if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
		if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
			return(0);
		if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
			return(0);
	}

	/*
	 * 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.
	 */

	for (arg = NULL;; ) {
		la = *pos;
		av = mdoc_argv(m, line, tok, &arg, pos, buf);

		if (ARGV_WORD == av) {
			*pos = la;
			break;
		} 

		if (ARGV_EOLN == av)
			break;
		if (ARGV_ARG == av)
			continue;

		mdoc_argv_free(arg);
		return(0);
	}

	if ( ! mdoc_block_alloc(m, line, ppos, tok, arg))
		return(0);

	head = body = NULL;

	/*
	 * Exception: Heads of `It' macros in `-diag' lists are not
	 * parsed, even though `It' macros in general are parsed.
	 */
	nparsed = MDOC_It == tok &&
		MDOC_Bl == m->last->parent->tok &&
		LIST_diag == m->last->parent->norm->Bl.type;

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

	if (MDOC_Nd == tok) {
		if ( ! mdoc_head_alloc(m, line, ppos, tok))
			return(0);
		head = m->last;
		if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
			return(0);
		if ( ! mdoc_body_alloc(m, line, ppos, tok))
			return(0);
		body = m->last;
	} 

	ac = ARGS_ERROR;

	for ( ; ; ) {
		la = *pos;
		/* Initialise last-phrase-type with ARGS_PEND. */
		lac = ARGS_ERROR == ac ? ARGS_PEND : ac;
		ac = mdoc_args(m, line, pos, buf, tok, &p);

		if (ARGS_PUNCT == ac)
			break;

		if (ARGS_ERROR == ac)
			return(0);

		if (ARGS_EOLN == ac) {
			if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac)
				break;
			/*
			 * This is necessary: if the last token on a
			 * line is a `Ta' or tab, then we'll get
			 * ARGS_EOLN, so we must be smart enough to
			 * reopen our scope if the last parse was a
			 * phrase or partial phrase.
			 */
			if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
				return(0);
			if ( ! mdoc_body_alloc(m, line, ppos, tok))
				return(0);
			body = m->last;
			break;
		}

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

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

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

		if (NULL == head) {
			if ( ! mdoc_head_alloc(m, line, ppos, tok))
				return(0);
			head = m->last;
		}

		if (ARGS_PHRASE == ac || 
				ARGS_PEND == ac ||
				ARGS_PPHRASE == ac) {
			/*
			 * If we haven't opened a body yet, rewind the
			 * head; if we have, rewind that instead.
			 */

			mtt = body ? MDOC_BODY : MDOC_HEAD;
			if ( ! rew_sub(mtt, m, tok, line, ppos))
				return(0);
			
			/* Then allocate our body context. */

			if ( ! mdoc_body_alloc(m, line, ppos, tok))
				return(0);
			body = m->last;

			/*
			 * Process phrases: set whether we're in a
			 * partial-phrase (this effects line handling)
			 * then call down into the phrase parser.
			 */

			if (ARGS_PPHRASE == ac)
				m->flags |= MDOC_PPHRASE;
			if (ARGS_PEND == ac && ARGS_PPHRASE == lac)
				m->flags |= MDOC_PPHRASE;

			if ( ! phrase(m, line, la, buf))
				return(0);

			m->flags &= ~MDOC_PPHRASE;
			continue;
		}

		ntok = nparsed || ARGS_QWORD == ac ? 
			MDOC_MAX : lookup(tok, p);

		if (MDOC_MAX == ntok) {
			if ( ! dword(m, line, la, p, DELIM_MAX))
				return(0);
			continue;
		}

		if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
			return(0);
		break;
	}

	if (NULL == head) {
		if ( ! mdoc_head_alloc(m, line, ppos, tok))
			return(0);
		head = m->last;
	}
	
	if (nl && ! append_delims(m, line, pos, buf))
		return(0);

	/* If we've already opened our body, exit now. */

	if (NULL != body)
		goto out;

	/*
	 * If there is an open (i.e., unvalidated) sub-block requiring
	 * explicit close-out, postpone switching the current block from
	 * head to body until the rew_sub() call closing out that
	 * sub-block.
	 */
	for (n = m->last; n && n != head; n = n->parent) {
		if (MDOC_BLOCK == n->type && 
				MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
				! (MDOC_VALID & n->flags)) {
			n->pending = head;
			return(1);
		}
	}

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

	if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
		return(0);
	if ( ! mdoc_body_alloc(m, line, ppos, tok))
		return(0);

out:
	if ( ! (MDOC_FREECOL & m->flags))
		return(1);

	if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
		return(0);
	if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
		return(0);

	m->flags &= ~MDOC_FREECOL;
	return(1);
}
예제 #13
0
/* ARGSUSED */
static int
in_line_argn(MACRO_PROT_ARGS)
{
	int		 la, flushed, j, maxargs, nl;
	enum margserr	 ac;
	enum margverr	 av;
	struct mdoc_arg	*arg;
	char		*p;
	enum mdoct	 ntok;

	nl = MDOC_NEWLINE & m->flags;

	/*
	 * A line macro that has a fixed number of arguments (maxargs).
	 * Only open the scope once the first non-leading-punctuation is
	 * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
	 * keep it open until the maximum number of arguments are
	 * exhausted.
	 */

	switch (tok) {
	case (MDOC_Ap):
		/* FALLTHROUGH */
	case (MDOC_No):
		/* FALLTHROUGH */
	case (MDOC_Ns):
		/* FALLTHROUGH */
	case (MDOC_Ux):
		maxargs = 0;
		break;
	case (MDOC_Xr):
		maxargs = 2;
		break;
	default:
		maxargs = 1;
		break;
	}

	for (arg = NULL; ; ) {
		la = *pos;
		av = mdoc_argv(m, line, tok, &arg, pos, buf);

		if (ARGV_WORD == av) {
			*pos = la;
			break;
		} 

		if (ARGV_EOLN == av)
			break;
		if (ARGV_ARG == av)
			continue;

		mdoc_argv_free(arg);
		return(0);
	}

	for (flushed = j = 0; ; ) {
		la = *pos;
		ac = mdoc_args(m, line, pos, buf, tok, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_PUNCT == ac)
			break;
		if (ARGS_EOLN == ac)
			break;

		if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && 
				ARGS_QWORD != ac &&
				0 == j && DELIM_OPEN == mdoc_isdelim(p)) {
			if ( ! mdoc_word_alloc(m, line, la, p))
				return(0);
			continue;
		} else if (0 == j)
		       if ( ! mdoc_elem_alloc(m, line, la, tok, arg))
			       return(0);

		if (j == maxargs && ! flushed) {
			if ( ! rew_elem(m, tok))
				return(0);
			flushed = 1;
		}

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);

		if (MDOC_MAX != ntok) {
			if ( ! flushed && ! rew_elem(m, tok))
				return(0);
			flushed = 1;
			if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
				return(0);
			j++;
			break;
		}

		if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
				ARGS_QWORD != ac &&
				! flushed &&
				DELIM_NONE != mdoc_isdelim(p)) {
			if ( ! rew_elem(m, tok))
				return(0);
			flushed = 1;
		}

		/* 
		 * XXX: this is a hack to work around groff's ugliness
		 * as regards `Xr' and extraneous arguments.  It should
		 * ideally be deprecated behaviour, but because this is
		 * code is no here, it's unlikely to be removed.
		 */

#ifdef __OpenBSD__
		if (MDOC_Xr == tok && j == maxargs) {
			if ( ! mdoc_elem_alloc(m, line, la, MDOC_Ns, NULL))
				return(0);
			if ( ! rew_elem(m, MDOC_Ns))
				return(0);
		}
#endif

		if ( ! mdoc_word_alloc(m, line, la, p))
			return(0);
		j++;
	}

	if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg))
	       return(0);

	/* Close out in a consistent state. */

	if ( ! flushed && ! rew_elem(m, tok))
		return(0);
	if ( ! nl)
		return(1);
	return(append_delims(m, line, pos, buf));
}
예제 #14
0
파일: mdoc_macro.c 프로젝트: UNGLinux/Obase
/*
 * Close out block partial/full explicit.  
 */
static int
blk_exp_close(MACRO_PROT_ARGS)
{
	struct mdoc_node *body;		/* Our own body. */
	struct mdoc_node *later;	/* A sub-block starting later. */
	struct mdoc_node *n;		/* For searching backwards. */

	int	 	 j, lastarg, maxargs, flushed, nl;
	enum margserr	 ac;
	enum mdoct	 atok, ntok;
	char		*p;

	nl = MDOC_NEWLINE & m->flags;

	switch (tok) {
	case (MDOC_Ec):
		maxargs = 1;
		break;
	default:
		maxargs = 0;
		break;
	}

	/*
	 * Search backwards for beginnings of blocks,
	 * both of our own and of pending sub-blocks.
	 */
	atok = rew_alt(tok);
	body = later = NULL;
	for (n = m->last; n; n = n->parent) {
		if (MDOC_VALID & n->flags)
			continue;

		/* Remember the start of our own body. */
		if (MDOC_BODY == n->type && atok == n->tok) {
			if (ENDBODY_NOT == n->end)
				body = n;
			continue;
		}

		if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok)
			continue;
		if (atok == n->tok) {
			assert(body);

			/*
			 * Found the start of our own block.
			 * When there is no pending sub block,
			 * just proceed to closing out.
			 */
			if (NULL == later)
				break;

			/* 
			 * When there is a pending sub block,
			 * postpone closing out the current block
			 * until the rew_sub() closing out the sub-block.
			 */
			make_pending(later, tok, m, line, ppos);

			/*
			 * Mark the place where the formatting - but not
			 * the scope - of the current block ends.
			 */
			if ( ! mdoc_endbody_alloc(m, line, ppos,
			    atok, body, ENDBODY_SPACE))
				return(0);
			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.
		 */
		if (later &&
		    MDOC_EXPLICIT & mdoc_macros[later->tok].flags)
			continue;
		if (MDOC_CALLABLE & mdoc_macros[n->tok].flags)
			later = n;
	}

	if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
		/* FIXME: do this in validate */
		if (buf[*pos]) 
			mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST);

		if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
			return(0);
		return(rew_sub(MDOC_BLOCK, m, tok, line, ppos));
	}

	if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
		return(0);

	if (NULL == later && maxargs > 0) 
		if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok)))
			return(0);

	for (flushed = j = 0; ; j++) {
		lastarg = *pos;

		if (j == maxargs && ! flushed) {
			if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
				return(0);
			flushed = 1;
		}

		ac = mdoc_args(m, line, pos, buf, tok, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_PUNCT == ac)
			break;
		if (ARGS_EOLN == ac)
			break;

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);

		if (MDOC_MAX == ntok) {
			if ( ! dword(m, line, lastarg, p, DELIM_MAX))
				return(0);
			continue;
		}

		if ( ! flushed) {
			if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
				return(0);
			flushed = 1;
		}
		if ( ! mdoc_macro(m, ntok, line, lastarg, pos, buf))
			return(0);
		break;
	}

	if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
		return(0);

	if ( ! nl)
		return(1);
	return(append_delims(m, line, pos, buf));
}
예제 #15
0
파일: mdoc.c 프로젝트: mr-justin/freebsd
/*
 * Parse a macro line, that is, a line beginning with the control
 * character.
 */
static int
mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
{
	struct mdoc_node *n;
	const char	 *cp;
	enum mdoct	  tok;
	int		  i, sv;
	char		  mac[5];

	sv = 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 > 1 && i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;

	if (tok == MDOC_MAX) {
		mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
		    ln, sv, buf + sv - 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 ('\0' == buf[offs] && ' ' == buf[offs - 1])
		mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
		    ln, offs - 1, NULL);

	/*
	 * If an initial macro or a list invocation, divert directly
	 * into macro processing.
	 */

	if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) {
		mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
		return(1);
	}

	n = mdoc->last;
	assert(mdoc->last);

	/*
	 * If the first macro of a `Bl -column', open an `It' block
	 * context around the parsed macro.
	 */

	if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
	    LIST_column == n->norm->Bl.type) {
		mdoc->flags |= MDOC_FREECOL;
		mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
		return(1);
	}

	/*
	 * If we're following a block-level `It' within a `Bl -column'
	 * context (perhaps opened in the above block or in ptext()),
	 * then open an `It' block context around the parsed macro.
	 */

	if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
	    NULL != n->parent &&
	    MDOC_Bl == n->parent->tok &&
	    LIST_column == n->parent->norm->Bl.type) {
		mdoc->flags |= MDOC_FREECOL;
		mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
		return(1);
	}

	/* Normal processing of a macro. */

	mdoc_macro(mdoc, tok, ln, sv, &offs, buf);

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

	if (mdoc->quick && MDOC_Sh == tok &&
	    SEC_NAME != mdoc->last->sec)
		return(2);

	return(1);
}
예제 #16
0
파일: mdoc_macro.c 프로젝트: UNGLinux/Obase
static int
in_line_eoln(MACRO_PROT_ARGS)
{
	int		 la;
	enum margserr	 ac;
	enum margverr	 av;
	struct mdoc_arg	*arg;
	char		*p;
	enum mdoct	 ntok;

	assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));

	if (tok == MDOC_Pp)
		rew_sub(MDOC_BLOCK, m, MDOC_Nm, line, ppos);

	/* Parse macro arguments. */

	for (arg = NULL; ; ) {
		la = *pos;
		av = mdoc_argv(m, line, tok, &arg, pos, buf);

		if (ARGV_WORD == av) {
			*pos = la;
			break;
		}
		if (ARGV_EOLN == av) 
			break;
		if (ARGV_ARG == av)
			continue;

		mdoc_argv_free(arg);
		return(0);
	}

	/* Open element scope. */

	if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
		return(0);

	/* Parse argument terms. */

	for (;;) {
		la = *pos;
		ac = mdoc_args(m, line, pos, buf, tok, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_EOLN == ac)
			break;

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);

		if (MDOC_MAX == ntok) {
			if ( ! dword(m, line, la, p, DELIM_MAX))
				return(0);
			continue;
		}

		if ( ! rew_elem(m, tok))
			return(0);
		return(mdoc_macro(m, ntok, line, la, pos, buf));
	}

	/* Close out (no delimiters). */

	return(rew_elem(m, tok));
}
예제 #17
0
파일: mdoc_macro.c 프로젝트: UNGLinux/Obase
/* ARGSUSED */
static int
in_line_argn(MACRO_PROT_ARGS)
{
	int		 la, flushed, j, maxargs, nl;
	enum margserr	 ac;
	enum margverr	 av;
	struct mdoc_arg	*arg;
	char		*p;
	enum mdoct	 ntok;

	nl = MDOC_NEWLINE & m->flags;

	/*
	 * A line macro that has a fixed number of arguments (maxargs).
	 * Only open the scope once the first non-leading-punctuation is
	 * found (unless MDOC_IGNDELIM is noted, like in `Pf'), then
	 * keep it open until the maximum number of arguments are
	 * exhausted.
	 */

	switch (tok) {
	case (MDOC_Ap):
		/* FALLTHROUGH */
	case (MDOC_No):
		/* FALLTHROUGH */
	case (MDOC_Ns):
		/* FALLTHROUGH */
	case (MDOC_Ux):
		maxargs = 0;
		break;
	case (MDOC_Bx):
		/* FALLTHROUGH */
	case (MDOC_Xr):
		maxargs = 2;
		break;
	default:
		maxargs = 1;
		break;
	}

	for (arg = NULL; ; ) {
		la = *pos;
		av = mdoc_argv(m, line, tok, &arg, pos, buf);

		if (ARGV_WORD == av) {
			*pos = la;
			break;
		} 

		if (ARGV_EOLN == av)
			break;
		if (ARGV_ARG == av)
			continue;

		mdoc_argv_free(arg);
		return(0);
	}

	for (flushed = j = 0; ; ) {
		la = *pos;
		ac = mdoc_args(m, line, pos, buf, tok, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_PUNCT == ac)
			break;
		if (ARGS_EOLN == ac)
			break;

		if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && 
				ARGS_QWORD != ac && 0 == j && 
				DELIM_OPEN == mdoc_isdelim(p)) {
			if ( ! dword(m, line, la, p, DELIM_OPEN))
				return(0);
			continue;
		} else if (0 == j)
		       if ( ! mdoc_elem_alloc(m, line, la, tok, arg))
			       return(0);

		if (j == maxargs && ! flushed) {
			if ( ! rew_elem(m, tok))
				return(0);
			flushed = 1;
		}

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);

		if (MDOC_MAX != ntok) {
			if ( ! flushed && ! rew_elem(m, tok))
				return(0);
			flushed = 1;
			if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
				return(0);
			j++;
			break;
		}

		if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
				ARGS_QWORD != ac &&
				! flushed &&
				DELIM_NONE != mdoc_isdelim(p)) {
			if ( ! rew_elem(m, tok))
				return(0);
			flushed = 1;
		}

		if ( ! dword(m, line, la, p, DELIM_MAX))
			return(0);
		j++;
	}

	if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg))
	       return(0);

	/* Close out in a consistent state. */

	if ( ! flushed && ! rew_elem(m, tok))
		return(0);
	if ( ! nl)
		return(1);
	return(append_delims(m, line, pos, buf));
}
예제 #18
0
파일: mdoc_macro.c 프로젝트: UNGLinux/Obase
static int
blk_part_exp(MACRO_PROT_ARGS)
{
	int		  la, nl;
	enum margserr	  ac;
	struct mdoc_node *head; /* keep track of head */
	struct mdoc_node *body; /* keep track of body */
	char		 *p;
	enum mdoct	  ntok;

	nl = MDOC_NEWLINE & m->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.
	 */

	if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
		return(0); 

	for (head = body = NULL; ; ) {
		la = *pos;
		ac = mdoc_args(m, line, pos, buf, tok, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_PUNCT == ac)
			break;
		if (ARGS_EOLN == ac)
			break;

		/* Flush out leading punctuation. */

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

		if (NULL == head) {
			assert(NULL == body);
			if ( ! mdoc_head_alloc(m, line, ppos, tok))
				return(0);
			head = m->last;
		}

		/*
		 * `Eo' gobbles any data into the head, but most other
		 * macros just immediately close out and begin the body.
		 */

		if (NULL == body) {
			assert(head);
			/* No check whether it's a macro! */
			if (MDOC_Eo == tok)
				if ( ! dword(m, line, la, p, DELIM_MAX))
					return(0);

			if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
				return(0);
			if ( ! mdoc_body_alloc(m, line, ppos, tok))
				return(0);
			body = m->last;

			if (MDOC_Eo == tok)
				continue;
		}

		assert(NULL != head && NULL != body);

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);

		if (MDOC_MAX == ntok) {
			if ( ! dword(m, line, la, p, DELIM_MAX))
				return(0);
			continue;
		}

		if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
			return(0);
		break;
	}

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

	if (NULL == head)
		if ( ! mdoc_head_alloc(m, line, ppos, tok))
			return(0);

	if (NULL == body) {
		if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
			return(0);
		if ( ! mdoc_body_alloc(m, line, ppos, tok))
			return(0);
	}

	/* Standard appending of delimiters. */

	if ( ! nl)
		return(1);
	return(append_delims(m, line, pos, buf));
}
예제 #19
0
파일: mdoc_macro.c 프로젝트: UNGLinux/Obase
static int
blk_part_imp(MACRO_PROT_ARGS)
{
	int		  la, nl;
	enum mdoct	  ntok;
	enum margserr	  ac;
	char		 *p;
	struct mdoc_node *blk; /* saved block context */
	struct mdoc_node *body; /* saved body context */
	struct mdoc_node *n;

	nl = MDOC_NEWLINE & m->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.
	 */

	if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL))
		return(0);

	blk = m->last;

	if ( ! mdoc_head_alloc(m, line, ppos, tok))
		return(0);
	if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
		return(0);

	/*
	 * 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(m, line, pos, buf, tok, &p);

		if (ARGS_ERROR == ac)
			return(0);
		if (ARGS_EOLN == ac)
			break;
		if (ARGS_PUNCT == ac)
			break;

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

		if (NULL == body) {
		       if ( ! mdoc_body_alloc(m, line, ppos, tok))
			       return(0);
			body = m->last;
		}

		ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);

		if (MDOC_MAX == ntok) {
			if ( ! dword(m, line, la, p, DELIM_MAX))
				return(0);
			continue;
		}

		if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
			return(0);
		break;
	}

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

	if (NULL == body) {
		if ( ! mdoc_body_alloc(m, line, ppos, tok))
			return(0);
		body = m->last;
	}

	for (n = body->child; n && n->next; n = n->next)
		/* Do nothing. */ ;
	
	/* 
	 * End of sentence spacing: if the last node is a text node and
	 * has a trailing period, then mark it as being end-of-sentence.
	 */

	if (n && MDOC_TEXT == n->type && n->string)
		if (mandoc_eos(n->string, strlen(n->string), 1))
			n->flags |= MDOC_EOS;

	/* Up-propagate the end-of-space flag. */

	if (n && (MDOC_EOS & n->flags)) {
		body->flags |= MDOC_EOS;
		body->parent->flags |= MDOC_EOS;
	}

	/*
	 * If there is an open sub-block requiring explicit close-out,
	 * postpone closing out the current block
	 * until the rew_sub() call closing out the sub-block.
	 */
	for (n = m->last; n && n != body && n != blk->parent; n = n->parent) {
		if (MDOC_BLOCK == n->type &&
		    MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
		    ! (MDOC_VALID & n->flags)) {
			make_pending(n, tok, m, line, ppos);
			if ( ! mdoc_endbody_alloc(m, line, ppos,
			    tok, body, ENDBODY_NOSPACE))
				return(0);
			return(1);
		}
	}

	/* 
	 * If we can't rewind to our body, then our scope has already
	 * been closed by another macro (like `Oc' closing `Op').  This
	 * is ugly behaviour nodding its head to OpenBSD's overwhelming
	 * crufty use of `Op' breakage.
	 */
	if (n != body)
		mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, 
				"%s broken", mdoc_macronames[tok]);

	if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos))
		return(0);

	/* Standard appending of delimiters. */

	if (nl && ! append_delims(m, line, pos, buf))
		return(0);

	/* Rewind scope, if applicable. */

	if (n && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
		return(0);

	return(1);
}