Beispiel #1
0
int
mchars_num2uc(const char *p, size_t sz)
{
	int               i;

	if ((i = mandoc_strntoi(p, sz, 16)) < 0)
		return('\0');
	/* FIXME: make sure we're not in a bogus range. */
	return(i > 0x80 && i <= 0x10FFFF ? i : '\0');
}
Beispiel #2
0
char
mchars_num2char(const char *p, size_t sz)
{
	int		  i;

	if ((i = mandoc_strntoi(p, sz, 10)) < 0)
		return('\0');
	return(i > 0 && i < 256 && isprint(i) ? 
			/* LINTED */ i : '\0');
}
Beispiel #3
0
static int
eqn_do_gsize(struct eqn_node *ep)
{
	const char	*start;
	size_t		 sz;

	if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
		EQN_MSG(MANDOCERR_EQNEOF, ep);
		return(0);
	} 
	ep->gsize = mandoc_strntoi(start, sz, 10);
	return(1);
}
Beispiel #4
0
/* ARGSUSED */
static enum rofferr
roff_nr(ROFF_ARGS)
{
	const char	*key;
	char		*val;
	int		 iv;

	val = *bufp + pos;
	key = roff_getname(r, &val, ln, pos);

	if (0 == strcmp(key, "nS")) {
		r->regs[(int)REG_nS].set = 1;
		if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0)
			r->regs[(int)REG_nS].u = (unsigned)iv;
		else
			r->regs[(int)REG_nS].u = 0u;
	}

	return(ROFF_IGN);
}
Beispiel #5
0
int
mchars_num2uc(const char *p, size_t sz)
{
	int	 i;

	if ((i = mandoc_strntoi(p, sz, 16)) < 0)
		return('\0');

	/*
	 * Security warning:
	 * Never extend the range of accepted characters
	 * to overlap with the ASCII range, 0x00-0x7F
	 * without re-auditing the callers of this function.
	 * Some callers might relay on the fact that we never
	 * return ASCII characters for their escaping decisions.
	 *
	 * XXX Code is missing here to exclude bogus ranges.
	 */

	return(i > 0x80 && i <= 0x10FFFF ? i : '\0');
}
Beispiel #6
0
/* ARGSUSED */
static enum rofferr
roff_it(ROFF_ARGS)
{
	char		*cp;
	size_t		 len;
	int		 iv;

	/* Parse the number of lines. */
	cp = *bufp + pos;
	len = strcspn(cp, " \t");
	cp[len] = '\0';
	if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
		mandoc_msg(MANDOCERR_NUMERIC, r->parse,
				ln, ppos, *bufp + 1);
		return(ROFF_IGN);
	}
	cp += len + 1;

	/* Arm the input line trap. */
	roffit_lines = iv;
	roffit_macro = mandoc_strdup(cp);
	return(ROFF_IGN);
}
Beispiel #7
0
/* ARGSUSED */
static enum rofferr
roff_nr(ROFF_ARGS)
{
	const char	*key;
	char		*val;
	size_t		 sz;
	int		 iv;
	char		 sign;

	val = *bufp + pos;
	key = roff_getname(r, &val, ln, pos);

	sign = *val;
	if ('+' == sign || '-' == sign)
		val++;

	sz = strspn(val, "0123456789");
	iv = sz ? mandoc_strntoi(val, sz, 10) : 0;

	roff_setreg(r, key, iv, sign);

	return(ROFF_IGN);
}
Beispiel #8
0
/*
 * Recursively parse an eqn(7) expression.
 */
static enum rofferr
eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
{
	char		 sym[64];
	struct eqn_box	*cur;
	const char	*start;
	char		*p;
	size_t		 i, sz;
	enum eqn_tok	 tok, subtok;
	enum eqn_post	 pos;
	int		 size;

	assert(parent != NULL);

	/*
	 * Empty equation.
	 * Do not add it to the high-level syntax tree.
	 */

	if (ep->data == NULL)
		return(ROFF_IGN);

next_tok:
	tok = eqn_tok_parse(ep, &p);

this_tok:
	switch (tok) {
	case (EQN_TOK_UNDEF):
		eqn_undef(ep);
		break;
	case (EQN_TOK_NDEFINE):
	case (EQN_TOK_DEFINE):
		eqn_def(ep);
		break;
	case (EQN_TOK_TDEFINE):
		if (eqn_nextrawtok(ep, NULL) == NULL ||
		    eqn_next(ep, ep->data[(int)ep->cur], NULL, 0) == NULL)
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, "tdefine");
		break;
	case (EQN_TOK_DELIM):
		eqn_delim(ep);
		break;
	case (EQN_TOK_GFONT):
		if (eqn_nextrawtok(ep, NULL) == NULL)
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
		break;
	case (EQN_TOK_MARK):
	case (EQN_TOK_LINEUP):
		/* Ignore these. */
		break;
	case (EQN_TOK_DYAD):
	case (EQN_TOK_VEC):
	case (EQN_TOK_UNDER):
	case (EQN_TOK_BAR):
	case (EQN_TOK_TILDE):
	case (EQN_TOK_HAT):
	case (EQN_TOK_DOT):
	case (EQN_TOK_DOTDOT):
		if (parent->last == NULL) {
			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			cur = eqn_box_alloc(ep, parent);
			cur->type = EQN_TEXT;
			cur->text = mandoc_strdup("");
		}
		parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent);
		parent->type = EQN_LISTONE;
		parent->expectargs = 1;
		switch (tok) {
		case (EQN_TOK_DOTDOT):
			strlcpy(sym, "\\[ad]", sizeof(sym));
			break;
		case (EQN_TOK_VEC):
			strlcpy(sym, "\\[->]", sizeof(sym));
			break;
		case (EQN_TOK_DYAD):
			strlcpy(sym, "\\[<>]", sizeof(sym));
			break;
		case (EQN_TOK_TILDE):
			strlcpy(sym, "\\[a~]", sizeof(sym));
			break;
		case (EQN_TOK_UNDER):
			strlcpy(sym, "\\[ul]", sizeof(sym));
			break;
		case (EQN_TOK_BAR):
			strlcpy(sym, "\\[rl]", sizeof(sym));
			break;
		case (EQN_TOK_DOT):
			strlcpy(sym, "\\[a.]", sizeof(sym));
			break;
		case (EQN_TOK_HAT):
			strlcpy(sym, "\\[ha]", sizeof(sym));
			break;
		default:
			abort();
		}

		switch (tok) {
		case (EQN_TOK_DOTDOT):
		case (EQN_TOK_VEC):
		case (EQN_TOK_DYAD):
		case (EQN_TOK_TILDE):
		case (EQN_TOK_BAR):
		case (EQN_TOK_DOT):
		case (EQN_TOK_HAT):
			parent->top = mandoc_strdup(sym);
			break;
		case (EQN_TOK_UNDER):
			parent->bottom = mandoc_strdup(sym);
			break;
		default:
			abort();
		}
		parent = parent->parent;
		break;
	case (EQN_TOK_FWD):
	case (EQN_TOK_BACK):
	case (EQN_TOK_DOWN):
	case (EQN_TOK_UP):
		subtok = eqn_tok_parse(ep, NULL);
		if (subtok != EQN_TOK__MAX) {
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			tok = subtok;
			goto this_tok;
		}
		break;
	case (EQN_TOK_FAT):
	case (EQN_TOK_ROMAN):
	case (EQN_TOK_ITALIC):
	case (EQN_TOK_BOLD):
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		/*
		 * These values apply to the next word or sequence of
		 * words; thus, we mark that we'll have a child with
		 * exactly one of those.
		 */
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_LISTONE;
		parent->expectargs = 1;
		switch (tok) {
		case (EQN_TOK_FAT):
			parent->font = EQNFONT_FAT;
			break;
		case (EQN_TOK_ROMAN):
			parent->font = EQNFONT_ROMAN;
			break;
		case (EQN_TOK_ITALIC):
			parent->font = EQNFONT_ITALIC;
			break;
		case (EQN_TOK_BOLD):
			parent->font = EQNFONT_BOLD;
			break;
		default:
			abort();
		}
		break;
	case (EQN_TOK_SIZE):
	case (EQN_TOK_GSIZE):
		/* Accept two values: integral size and a single. */
		if (NULL == (start = eqn_nexttok(ep, &sz))) {
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		size = mandoc_strntoi(start, sz, 10);
		if (-1 == size) {
			mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		if (EQN_TOK_GSIZE == tok) {
			ep->gsize = size;
			break;
		}
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_LISTONE;
		parent->expectargs = 1;
		parent->size = size;
		break;
	case (EQN_TOK_FROM):
	case (EQN_TOK_TO):
	case (EQN_TOK_SUB):
	case (EQN_TOK_SUP):
		/*
		 * We have a left-right-associative expression.
		 * Repivot under a positional node, open a child scope
		 * and keep on reading.
		 */
		if (parent->last == NULL) {
			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			cur = eqn_box_alloc(ep, parent);
			cur->type = EQN_TEXT;
			cur->text = mandoc_strdup("");
		}
		/* Handle the "subsup" and "fromto" positions. */
		if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) {
			parent->expectargs = 3;
			parent->pos = EQNPOS_SUBSUP;
			break;
		}
		if (EQN_TOK_TO == tok && parent->pos == EQNPOS_FROM) {
			parent->expectargs = 3;
			parent->pos = EQNPOS_FROMTO;
			break;
		}
		switch (tok) {
		case (EQN_TOK_FROM):
			pos = EQNPOS_FROM;
			break;
		case (EQN_TOK_TO):
			pos = EQNPOS_TO;
			break;
		case (EQN_TOK_SUP):
			pos = EQNPOS_SUP;
			break;
		case (EQN_TOK_SUB):
			pos = EQNPOS_SUB;
			break;
		default:
			abort();
		}
		parent = eqn_box_makebinary(ep, pos, parent);
		break;
	case (EQN_TOK_SQRT):
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		/*
		 * Accept a left-right-associative set of arguments just
		 * like sub and sup and friends but without rebalancing
		 * under a pivot.
		 */
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_SUBEXPR;
		parent->pos = EQNPOS_SQRT;
		parent->expectargs = 1;
		break;
	case (EQN_TOK_OVER):
		/*
		 * We have a right-left-associative fraction.
		 * Close out anything that's currently open, then
		 * rebalance and continue reading.
		 */
		if (parent->last == NULL) {
			mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			cur = eqn_box_alloc(ep, parent);
			cur->type = EQN_TEXT;
			cur->text = mandoc_strdup("");
		}
		while (EQN_SUBEXPR == parent->type)
			parent = parent->parent;
		parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);
		break;
	case (EQN_TOK_RIGHT):
	case (EQN_TOK_BRACE_CLOSE):
		/*
		 * Close out the existing brace.
		 * FIXME: this is a shitty sentinel: we should really
		 * have a native EQN_BRACE type or whatnot.
		 */
		for (cur = parent; cur != NULL; cur = cur->parent)
			if (cur->type == EQN_LIST &&
			    (tok == EQN_TOK_BRACE_CLOSE ||
			     cur->left != NULL))
				break;
		if (cur == NULL) {
			mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		parent = cur;
		if (EQN_TOK_RIGHT == tok) {
			if (NULL == (start = eqn_nexttok(ep, &sz))) {
				mandoc_msg(MANDOCERR_REQ_EMPTY,
				    ep->parse, ep->eqn.ln,
				    ep->eqn.pos, eqn_toks[tok]);
				break;
			}
			/* Handling depends on right/left. */
			if (STRNEQ(start, sz, "ceiling", 7)) {
				strlcpy(sym, "\\[rc]", sizeof(sym));
				parent->right = mandoc_strdup(sym);
			} else if (STRNEQ(start, sz, "floor", 5)) {
				strlcpy(sym, "\\[rf]", sizeof(sym));
				parent->right = mandoc_strdup(sym);
			} else
				parent->right = mandoc_strndup(start, sz);
		}
		parent = parent->parent;
		if (EQN_TOK_BRACE_CLOSE == tok && parent &&
		    (parent->type == EQN_PILE ||
		     parent->type == EQN_MATRIX))
			parent = parent->parent;
		/* Close out any "singleton" lists. */
		while (parent && parent->type == EQN_LISTONE &&
		    parent->args == parent->expectargs)
			parent = parent->parent;
		break;
	case (EQN_TOK_BRACE_OPEN):
	case (EQN_TOK_LEFT):
		/*
		 * If we already have something in the stack and we're
		 * in an expression, then rewind til we're not any more
		 * (just like with the text node).
		 */
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		if (EQN_TOK_LEFT == tok &&
		    (start = eqn_nexttok(ep, &sz)) == NULL) {
			mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_LIST;
		if (EQN_TOK_LEFT == tok) {
			if (STRNEQ(start, sz, "ceiling", 7)) {
				strlcpy(sym, "\\[lc]", sizeof(sym));
				parent->left = mandoc_strdup(sym);
			} else if (STRNEQ(start, sz, "floor", 5)) {
				strlcpy(sym, "\\[lf]", sizeof(sym));
				parent->left = mandoc_strdup(sym);
			} else
				parent->left = mandoc_strndup(start, sz);
		}
		break;
	case (EQN_TOK_PILE):
	case (EQN_TOK_LPILE):
	case (EQN_TOK_RPILE):
	case (EQN_TOK_CPILE):
	case (EQN_TOK_CCOL):
	case (EQN_TOK_LCOL):
	case (EQN_TOK_RCOL):
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_PILE;
		parent->expectargs = 1;
		break;
	case (EQN_TOK_ABOVE):
		for (cur = parent; cur != NULL; cur = cur->parent)
			if (cur->type == EQN_PILE)
				break;
		if (cur == NULL) {
			mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
			    ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
			break;
		}
		parent = eqn_box_alloc(ep, cur);
		parent->type = EQN_LIST;
		break;
	case (EQN_TOK_MATRIX):
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		parent = eqn_box_alloc(ep, parent);
		parent->type = EQN_MATRIX;
		parent->expectargs = 1;
		break;
	case (EQN_TOK_EOF):
		/*
		 * End of file!
		 * TODO: make sure we're not in an open subexpression.
		 */
		return(ROFF_EQN);
	default:
		assert(tok == EQN_TOK__MAX);
		assert(NULL != p);
		/*
		 * If we already have something in the stack and we're
		 * in an expression, then rewind til we're not any more.
		 */
		while (parent->args == parent->expectargs)
			parent = parent->parent;
		cur = eqn_box_alloc(ep, parent);
		cur->type = EQN_TEXT;
		for (i = 0; i < EQNSYM__MAX; i++)
			if (0 == strcmp(eqnsyms[i].str, p)) {
				(void)snprintf(sym, sizeof(sym),
					"\\[%s]", eqnsyms[i].sym);
				cur->text = mandoc_strdup(sym);
				free(p);
				break;
			}

		if (i == EQNSYM__MAX)
			cur->text = p;
		/*
		 * Post-process list status.
		 */
		while (parent->type == EQN_LISTONE &&
		    parent->args == parent->expectargs)
			parent = parent->parent;
		break;
	}
	goto next_tok;
}
Beispiel #9
0
static enum eqn_rest
eqn_box(struct eqn_node *ep, struct eqn_box *last)
{
	size_t		 sz;
	const char	*start;
	char		*left;
	char		 sym[64];
	enum eqn_rest	 c;
	int		 i, size;
	struct eqn_box	*bp;

	if (NULL == (start = eqn_nexttok(ep, &sz)))
		return(EQN_EOF);

	if (STRNEQ(start, sz, "}", 1))
		return(EQN_DESCOPE);
	else if (STRNEQ(start, sz, "right", 5))
		return(EQN_DESCOPE);
	else if (STRNEQ(start, sz, "above", 5))
		return(EQN_DESCOPE);
	else if (STRNEQ(start, sz, "mark", 4))
		return(EQN_OK);
	else if (STRNEQ(start, sz, "lineup", 6))
		return(EQN_OK);

	for (i = 0; i < (int)EQN__MAX; i++) {
		if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
			continue;
		return((*eqnparts[i].fp)(ep) ? 
				EQN_OK : EQN_ERR);
	} 

	if (STRNEQ(start, sz, "{", 1)) {
		if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
			if (EQN_ERR != c)
				EQN_MSG(MANDOCERR_EQNSCOPE, ep);
			return(EQN_ERR);
		}
		eqn_rewind(ep);
		start = eqn_nexttok(ep, &sz);
		assert(start);
		if (STRNEQ(start, sz, "}", 1))
			return(EQN_OK);
		EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
		return(EQN_ERR);
	} 

	for (i = 0; i < (int)EQNPILE__MAX; i++) {
		if ( ! EQNSTREQ(&eqnpiles[i], start, sz))
			continue;
		if (EQN_OK == (c = eqn_list(ep, last)))
			last->last->pile = (enum eqn_pilet)i;
		return(c);
	}

	if (STRNEQ(start, sz, "matrix", 6))
		return(eqn_matrix(ep, last));

	if (STRNEQ(start, sz, "left", 4)) {
		if (NULL == (start = eqn_nexttok(ep, &sz))) {
			EQN_MSG(MANDOCERR_EQNEOF, ep);
			return(EQN_ERR);
		}
		left = mandoc_strndup(start, sz);
		c = eqn_eqn(ep, last);
		if (last->last)
			last->last->left = left;
		else
			free(left);
		if (EQN_DESCOPE != c)
			return(c);
		assert(last->last);
		eqn_rewind(ep);
		start = eqn_nexttok(ep, &sz);
		assert(start);
		if ( ! STRNEQ(start, sz, "right", 5))
			return(EQN_DESCOPE);
		if (NULL == (start = eqn_nexttok(ep, &sz))) {
			EQN_MSG(MANDOCERR_EQNEOF, ep);
			return(EQN_ERR);
		}
		last->last->right = mandoc_strndup(start, sz);
		return(EQN_OK);
	}

	for (i = 0; i < (int)EQNPOS__MAX; i++) {
		if ( ! EQNSTREQ(&eqnposs[i], start, sz))
			continue;
		if (NULL == last->last) {
			EQN_MSG(MANDOCERR_EQNSYNT, ep);
			return(EQN_ERR);
		} 
		last->last->pos = (enum eqn_post)i;
		if (EQN_EOF == (c = eqn_box(ep, last))) {
			EQN_MSG(MANDOCERR_EQNEOF, ep);
			return(EQN_ERR);
		}
		return(c);
	}

	for (i = 0; i < (int)EQNMARK__MAX; i++) {
		if ( ! EQNSTREQ(&eqnmarks[i], start, sz))
			continue;
		if (NULL == last->last) {
			EQN_MSG(MANDOCERR_EQNSYNT, ep);
			return(EQN_ERR);
		} 
		last->last->mark = (enum eqn_markt)i;
		if (EQN_EOF == (c = eqn_box(ep, last))) {
			EQN_MSG(MANDOCERR_EQNEOF, ep);
			return(EQN_ERR);
		}
		return(c);
	}

	for (i = 0; i < (int)EQNFONT__MAX; i++) {
		if ( ! EQNSTREQ(&eqnfonts[i], start, sz))
			continue;
		if (EQN_EOF == (c = eqn_box(ep, last))) {
			EQN_MSG(MANDOCERR_EQNEOF, ep);
			return(EQN_ERR);
		} else if (EQN_OK == c)
			last->last->font = (enum eqn_fontt)i;
		return(c);
	}

	if (STRNEQ(start, sz, "size", 4)) {
		if (NULL == (start = eqn_nexttok(ep, &sz))) {
			EQN_MSG(MANDOCERR_EQNEOF, ep);
			return(EQN_ERR);
		}
		size = mandoc_strntoi(start, sz, 10);
		if (EQN_EOF == (c = eqn_box(ep, last))) {
			EQN_MSG(MANDOCERR_EQNEOF, ep);
			return(EQN_ERR);
		} else if (EQN_OK != c)
			return(c);
		last->last->size = size;
	}

	bp = eqn_box_alloc(ep, last);
	bp->type = EQN_TEXT;
	for (i = 0; i < (int)EQNSYM__MAX; i++)
		if (EQNSTREQ(&eqnsyms[i].str, start, sz)) {
			sym[63] = '\0';
			snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
			bp->text = mandoc_strdup(sym);
			return(EQN_OK);
		}

	bp->text = mandoc_strndup(start, sz);
	return(EQN_OK);
}