示例#1
0
static int
termp_rv_pre(DECL_ARGS)
{
	int		 nchild;

	term_newln(p);

	nchild = n->nchild;
	if (nchild > 0) {
		term_word(p, "The");

		for (n = n->child; n; n = n->next) {
			term_fontpush(p, TERMFONT_BOLD);
			term_word(p, n->string);
			term_fontpop(p);

			p->flags |= TERMP_NOSPACE;
			term_word(p, "()");

			if (n->next == NULL)
				continue;

			if (nchild > 2) {
				p->flags |= TERMP_NOSPACE;
				term_word(p, ",");
			}
			if (n->next->next == NULL)
				term_word(p, "and");
		}

		if (nchild > 1)
			term_word(p, "functions return");
		else
			term_word(p, "function returns");

		term_word(p, "the value\\~0 if successful;");
	} else
		term_word(p, "Upon successful completion,"
		    " the value\\~0 is returned;");

	term_word(p, "otherwise the value\\~\\-1 is returned"
	    " and the global variable");

	term_fontpush(p, TERMFONT_UNDER);
	term_word(p, "errno");
	term_fontpop(p);

	term_word(p, "is set to indicate the error.");
	p->flags |= TERMP_SENTENCE;

	return(0);
}
示例#2
0
static void
eqn_box(struct termp *p, const struct eqn_box *bp)
{

	if (EQNFONT_NONE != bp->font)
		term_fontpush(p, fontmap[(int)bp->font]);
	if (bp->left)
		term_word(p, bp->left);
	if (EQN_SUBEXPR == bp->type)
		term_word(p, "(");

	if (bp->text)
		term_word(p, bp->text);

	if (bp->first)
		eqn_box(p, bp->first);

	if (EQN_SUBEXPR == bp->type)
		term_word(p, ")");
	if (bp->right)
		term_word(p, bp->right);
	if (EQNFONT_NONE != bp->font) 
		term_fontpop(p);

	if (bp->next)
		eqn_box(p, bp->next);
}
示例#3
0
static int
termp_ex_pre(DECL_ARGS)
{
	struct roff_node *nch;

	term_newln(p);
	term_word(p, "The");

	for (nch = n->child; nch != NULL; nch = nch->next) {
		term_fontpush(p, TERMFONT_BOLD);
		term_word(p, nch->string);
		term_fontpop(p);

		if (nch->next == NULL)
			continue;

		if (nch->prev != NULL || nch->next->next != NULL) {
			p->flags |= TERMP_NOSPACE;
			term_word(p, ",");
		}

		if (nch->next->next == NULL)
			term_word(p, "and");
	}

	if (n->child != NULL && n->child->next != NULL)
		term_word(p, "utilities exit\\~0");
	else
		term_word(p, "utility exits\\~0");

	term_word(p, "on success, and\\~>0 if an error occurs.");

	p->flags |= TERMP_SENTENCE;
	return 0;
}
示例#4
0
static int
termp_ex_pre(DECL_ARGS)
{
	int		 nchild;

	term_newln(p);
	term_word(p, "The");

	nchild = n->nchild;
	for (n = n->child; n; n = n->next) {
		term_fontpush(p, TERMFONT_BOLD);
		term_word(p, n->string);
		term_fontpop(p);

		if (nchild > 2 && n->next) {
			p->flags |= TERMP_NOSPACE;
			term_word(p, ",");
		}

		if (n->next && NULL == n->next->next)
			term_word(p, "and");
	}

	if (nchild > 1)
		term_word(p, "utilities exit\\~0");
	else
		term_word(p, "utility exits\\~0");

	term_word(p, "on success, and\\~>0 if an error occurs.");

	p->flags |= TERMP_SENTENCE;
	return 0;
}
示例#5
0
/* ARGSUSED */
static int
termp_fa_pre(DECL_ARGS)
{
	const struct mdoc_node	*nn;

	if (n->parent->tok != MDOC_Fo) {
		term_fontpush(p, TERMFONT_UNDER);
		return(1);
	}

	for (nn = n->child; nn; nn = nn->next) {
		term_fontpush(p, TERMFONT_UNDER);
		term_word(p, nn->string);
		term_fontpop(p);

		if (nn->next) {
			p->flags |= TERMP_NOSPACE;
			term_word(p, ",");
		}
	}

	if (n->child && n->next && n->next->tok == MDOC_Fa) {
		p->flags |= TERMP_NOSPACE;
		term_word(p, ",");
	}

	return(0);
}
示例#6
0
/* ARGSUSED */
static int
termp_ex_pre(DECL_ARGS)
{
	const struct mdoc_node	*nn;

	term_word(p, "The");

	for (nn = n->child; nn; nn = nn->next) {
		term_fontpush(p, TERMFONT_BOLD);
		term_word(p, nn->string);
		term_fontpop(p);
		p->flags |= TERMP_NOSPACE;
		if (nn->next && NULL == nn->next->next)
			term_word(p, ", and");
		else if (nn->next)
			term_word(p, ",");
		else
			p->flags &= ~TERMP_NOSPACE;
	}

	if (n->child && n->child->next)
		term_word(p, "utilities exit");
	else
		term_word(p, "utility exits");

       	term_word(p, "0 on success, and >0 if an error occurs.");
	p->flags |= TERMP_SENTENCE;

	return(0);
}
示例#7
0
/* ARGSUSED */
static int
termp_rv_pre(DECL_ARGS)
{
	int		 nchild;

	term_newln(p);
	term_word(p, "The");

	nchild = n->nchild;
	for (n = n->child; n; n = n->next) {
		term_fontpush(p, TERMFONT_BOLD);
		term_word(p, n->string);
		term_fontpop(p);

		p->flags |= TERMP_NOSPACE;
		term_word(p, "()");

		if (nchild > 2 && n->next) {
			p->flags |= TERMP_NOSPACE;
			term_word(p, ",");
		}

		if (n->next && NULL == n->next->next)
			term_word(p, "and");
	}

	if (nchild > 1)
		term_word(p, "functions return");
	else
		term_word(p, "function returns");

       	term_word(p, "the value 0 if successful; otherwise the value "
			"-1 is returned and the global variable");

	term_fontpush(p, TERMFONT_UNDER);
	term_word(p, "errno");
	term_fontpop(p);

       	term_word(p, "is set to indicate the error.");
	p->flags |= TERMP_SENTENCE;

	return(0);
}
示例#8
0
/* ARGSUSED */
static int
termp_fn_pre(DECL_ARGS)
{
	int		 pretty;

	pretty = MDOC_SYNPRETTY & n->flags;

	synopsis_pre(p, n);

	if (NULL == (n = n->child))
		return(0);

	assert(MDOC_TEXT == n->type);
	term_fontpush(p, TERMFONT_BOLD);
	term_word(p, n->string);
	term_fontpop(p);

	p->flags |= TERMP_NOSPACE;
	term_word(p, "(");
	p->flags |= TERMP_NOSPACE;

	for (n = n->next; n; n = n->next) {
		assert(MDOC_TEXT == n->type);
		term_fontpush(p, TERMFONT_UNDER);
		term_word(p, n->string);
		term_fontpop(p);

		if (n->next) {
			p->flags |= TERMP_NOSPACE;
			term_word(p, ",");
		}
	}

	p->flags |= TERMP_NOSPACE;
	term_word(p, ")");

	if (pretty) {
		p->flags |= TERMP_NOSPACE;
		term_word(p, ";");
	}

	return(0);
}
示例#9
0
static void
termp_in_post(DECL_ARGS)
{

	if (MDOC_SYNPRETTY & n->flags)
		term_fontpush(p, TERMFONT_BOLD);

	p->flags |= TERMP_NOSPACE;
	term_word(p, ">");

	if (MDOC_SYNPRETTY & n->flags)
		term_fontpop(p);
}
示例#10
0
static int
termp_it_pre(DECL_ARGS)
{
	char			buf[24];
	const struct roff_node *bl, *nn;
	size_t			ncols, dcol;
	int			i, offset, width;
	enum mdoc_list		type;

	if (n->type == ROFFT_BLOCK) {
		print_bvspace(p, n->parent->parent, n);
		return 1;
	}

	bl = n->parent->parent->parent;
	type = bl->norm->Bl.type;

	/*
	 * Defaults for specific list types.
	 */

	switch (type) {
	case LIST_bullet:
	case LIST_dash:
	case LIST_hyphen:
	case LIST_enum:
		width = term_len(p, 2);
		break;
	case LIST_hang:
		width = term_len(p, 8);
		break;
	case LIST_column:
	case LIST_tag:
		width = term_len(p, 10);
		break;
	default:
		width = 0;
		break;
	}
	offset = 0;

	/*
	 * First calculate width and offset.  This is pretty easy unless
	 * we're a -column list, in which case all prior columns must
	 * be accounted for.
	 */

	if (bl->norm->Bl.offs != NULL) {
		offset = a2width(p, bl->norm->Bl.offs);
		if (offset < 0 && (size_t)(-offset) > p->offset)
			offset = -p->offset;
		else if (offset > SHRT_MAX)
			offset = 0;
	}

	switch (type) {
	case LIST_column:
		if (n->type == ROFFT_HEAD)
			break;

		/*
		 * Imitate groff's column handling:
		 * - For each earlier column, add its width.
		 * - For less than 5 columns, add four more blanks per
		 *   column.
		 * - For exactly 5 columns, add three more blank per
		 *   column.
		 * - For more than 5 columns, add only one column.
		 */
		ncols = bl->norm->Bl.ncols;
		dcol = ncols < 5 ? term_len(p, 4) :
		    ncols == 5 ? term_len(p, 3) : term_len(p, 1);

		/*
		 * Calculate the offset by applying all prior ROFFT_BODY,
		 * so we stop at the ROFFT_HEAD (nn->prev == NULL).
		 */

		for (i = 0, nn = n->prev;
		    nn->prev && i < (int)ncols;
		    nn = nn->prev, i++)
			offset += dcol + a2width(p,
			    bl->norm->Bl.cols[i]);

		/*
		 * When exceeding the declared number of columns, leave
		 * the remaining widths at 0.  This will later be
		 * adjusted to the default width of 10, or, for the last
		 * column, stretched to the right margin.
		 */
		if (i >= (int)ncols)
			break;

		/*
		 * Use the declared column widths, extended as explained
		 * in the preceding paragraph.
		 */
		width = a2width(p, bl->norm->Bl.cols[i]) + dcol;
		break;
	default:
		if (NULL == bl->norm->Bl.width)
			break;

		/*
		 * Note: buffer the width by 2, which is groff's magic
		 * number for buffering single arguments.  See the above
		 * handling for column for how this changes.
		 */
		width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
		if (width < 0 && (size_t)(-width) > p->offset)
			width = -p->offset;
		else if (width > SHRT_MAX)
			width = 0;
		break;
	}

	/*
	 * Whitespace control.  Inset bodies need an initial space,
	 * while diagonal bodies need two.
	 */

	p->flags |= TERMP_NOSPACE;

	switch (type) {
	case LIST_diag:
		if (n->type == ROFFT_BODY)
			term_word(p, "\\ \\ ");
		break;
	case LIST_inset:
		if (n->type == ROFFT_BODY && n->parent->head->child != NULL)
			term_word(p, "\\ ");
		break;
	default:
		break;
	}

	p->flags |= TERMP_NOSPACE;

	switch (type) {
	case LIST_diag:
		if (n->type == ROFFT_HEAD)
			term_fontpush(p, TERMFONT_BOLD);
		break;
	default:
		break;
	}

	/*
	 * Pad and break control.  This is the tricky part.  These flags
	 * are documented in term_flushln() in term.c.  Note that we're
	 * going to unset all of these flags in termp_it_post() when we
	 * exit.
	 */

	switch (type) {
	case LIST_enum:
	case LIST_bullet:
	case LIST_dash:
	case LIST_hyphen:
		/*
		 * Weird special case.
		 * Some very narrow lists actually hang.
		 */
		if (width <= (int)term_len(p, 2))
			p->flags |= TERMP_HANG;
		if (n->type != ROFFT_HEAD)
			break;
		p->flags |= TERMP_NOBREAK;
		p->trailspace = 1;
		break;
	case LIST_hang:
		if (n->type != ROFFT_HEAD)
			break;

		/*
		 * This is ugly.  If `-hang' is specified and the body
		 * is a `Bl' or `Bd', then we want basically to nullify
		 * the "overstep" effect in term_flushln() and treat
		 * this as a `-ohang' list instead.
		 */
		if (NULL != n->next &&
		    NULL != n->next->child &&
		    (MDOC_Bl == n->next->child->tok ||
		     MDOC_Bd == n->next->child->tok))
			break;

		p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
		p->trailspace = 1;
		break;
	case LIST_tag:
		if (n->type != ROFFT_HEAD)
			break;

		p->flags |= TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND;
		p->trailspace = 2;

		if (NULL == n->next || NULL == n->next->child)
			p->flags |= TERMP_DANGLE;
		break;
	case LIST_column:
		if (n->type == ROFFT_HEAD)
			break;

		if (NULL == n->next) {
			p->flags &= ~TERMP_NOBREAK;
			p->trailspace = 0;
		} else {
			p->flags |= TERMP_NOBREAK;
			p->trailspace = 1;
		}

		break;
	case LIST_diag:
		if (n->type != ROFFT_HEAD)
			break;
		p->flags |= TERMP_NOBREAK | TERMP_BRIND;
		p->trailspace = 1;
		break;
	default:
		break;
	}

	/*
	 * Margin control.  Set-head-width lists have their right
	 * margins shortened.  The body for these lists has the offset
	 * necessarily lengthened.  Everybody gets the offset.
	 */

	p->offset += offset;

	switch (type) {
	case LIST_hang:
		/*
		 * Same stipulation as above, regarding `-hang'.  We
		 * don't want to recalculate rmargin and offsets when
		 * using `Bd' or `Bl' within `-hang' overstep lists.
		 */
		if (n->type == ROFFT_HEAD &&
		    NULL != n->next &&
		    NULL != n->next->child &&
		    (MDOC_Bl == n->next->child->tok ||
		     MDOC_Bd == n->next->child->tok))
			break;
		/* FALLTHROUGH */
	case LIST_bullet:
	case LIST_dash:
	case LIST_enum:
	case LIST_hyphen:
	case LIST_tag:
		if (n->type == ROFFT_HEAD)
			p->rmargin = p->offset + width;
		else
			p->offset += width;
		break;
	case LIST_column:
		assert(width);
		p->rmargin = p->offset + width;
		/*
		 * XXX - this behaviour is not documented: the
		 * right-most column is filled to the right margin.
		 */
		if (n->type == ROFFT_HEAD)
			break;
		if (NULL == n->next && p->rmargin < p->maxrmargin)
			p->rmargin = p->maxrmargin;
		break;
	default:
		break;
	}

	/*
	 * The dash, hyphen, bullet and enum lists all have a special
	 * HEAD character (temporarily bold, in some cases).
	 */

	if (n->type == ROFFT_HEAD)
		switch (type) {
		case LIST_bullet:
			term_fontpush(p, TERMFONT_BOLD);
			term_word(p, "\\[bu]");
			term_fontpop(p);
			break;
		case LIST_dash:
		case LIST_hyphen:
			term_fontpush(p, TERMFONT_BOLD);
			term_word(p, "-");
			term_fontpop(p);
			break;
		case LIST_enum:
			(pair->ppair->ppair->count)++;
			(void)snprintf(buf, sizeof(buf), "%d.",
			    pair->ppair->ppair->count);
			term_word(p, buf);
			break;
		default:
			break;
		}

	/*
	 * If we're not going to process our children, indicate so here.
	 */

	switch (type) {
	case LIST_bullet:
	case LIST_item:
	case LIST_dash:
	case LIST_hyphen:
	case LIST_enum:
		if (n->type == ROFFT_HEAD)
			return 0;
		break;
	case LIST_column:
		if (n->type == ROFFT_HEAD)
			return 0;
		break;
	default:
		break;
	}

	return 1;
}
示例#11
0
static int
termp_fn_pre(DECL_ARGS)
{
	size_t		 rmargin = 0;
	int		 pretty;

	pretty = MDOC_SYNPRETTY & n->flags;

	synopsis_pre(p, n);

	if (NULL == (n = n->child))
		return 0;

	if (pretty) {
		rmargin = p->rmargin;
		p->rmargin = p->offset + term_len(p, 4);
		p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
	}

	assert(n->type == ROFFT_TEXT);
	term_fontpush(p, TERMFONT_BOLD);
	term_word(p, n->string);
	term_fontpop(p);

	if (n->sec == SEC_DESCRIPTION)
		tag_put(n->string, ++fn_prio, p->line);

	if (pretty) {
		term_flushln(p);
		p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
		p->offset = p->rmargin;
		p->rmargin = rmargin;
	}

	p->flags |= TERMP_NOSPACE;
	term_word(p, "(");
	p->flags |= TERMP_NOSPACE;

	for (n = n->next; n; n = n->next) {
		assert(n->type == ROFFT_TEXT);
		term_fontpush(p, TERMFONT_UNDER);
		if (pretty)
			p->flags |= TERMP_NBRWORD;
		term_word(p, n->string);
		term_fontpop(p);

		if (n->next) {
			p->flags |= TERMP_NOSPACE;
			term_word(p, ",");
		}
	}

	p->flags |= TERMP_NOSPACE;
	term_word(p, ")");

	if (pretty) {
		p->flags |= TERMP_NOSPACE;
		term_word(p, ";");
		term_flushln(p);
	}

	return 0;
}
示例#12
0
static void
eqn_box(struct termp *p, const struct eqn_box *bp)
{
	const struct eqn_box *child;
	const char *cp;
	int delim;

	/* Delimiters around this box? */

	if ((bp->type == EQN_LIST && bp->expectargs > 1) ||
	    (bp->type == EQN_PILE && (bp->prev || bp->next)) ||
	    (bp->parent != NULL && (bp->parent->pos == EQNPOS_SQRT ||
	    /* Diacritic followed by ^ or _. */
	    ((bp->top != NULL || bp->bottom != NULL) &&
	     bp->parent->type == EQN_SUBEXPR &&
	     bp->parent->pos != EQNPOS_OVER && bp->next != NULL) ||
	    /* Nested over, sub, sup, from, to. */
	    (bp->type == EQN_SUBEXPR && bp->pos != EQNPOS_SQRT &&
	     ((bp->parent->type == EQN_LIST && bp->expectargs == 1) ||
	      (bp->parent->type == EQN_SUBEXPR &&
	       bp->pos != EQNPOS_SQRT)))))) {
		if ((bp->parent->type == EQN_SUBEXPR && bp->prev != NULL) ||
		    (bp->type == EQN_LIST &&
		     bp->first != NULL &&
		     bp->first->type != EQN_PILE &&
		     bp->first->type != EQN_MATRIX &&
		     bp->prev != NULL &&
		     (bp->prev->type == EQN_LIST ||
		      (bp->prev->type == EQN_TEXT &&
		       (*bp->prev->text == '\\' ||
		        isalpha((unsigned char)*bp->prev->text))))))
			p->flags |= TERMP_NOSPACE;
		term_word(p, bp->left != NULL ? bp->left : "(");
		p->flags |= TERMP_NOSPACE;
		delim = 1;
	} else
		delim = 0;

	/* Handle Fonts and text. */

	if (bp->font != EQNFONT_NONE)
		term_fontpush(p, fontmap[(int)bp->font]);

	if (bp->text != NULL) {
		if (strchr("!\"'),.:;?]}", *bp->text) != NULL)
			p->flags |= TERMP_NOSPACE;
		term_word(p, bp->text);
		if ((cp = strchr(bp->text, '\0')) > bp->text &&
		    (strchr("\"'([{", cp[-1]) != NULL ||
		     (bp->prev == NULL && (cp[-1] == '-' ||
		      (cp >= bp->text + 5 &&
		       strcmp(cp - 5, "\\[mi]") == 0)))))
			p->flags |= TERMP_NOSPACE;
	}

	/* Special box types. */

	if (bp->pos == EQNPOS_SQRT) {
		term_word(p, "\\(sr");
		if (bp->first != NULL) {
			p->flags |= TERMP_NOSPACE;
			eqn_box(p, bp->first);
		}
	} else if (bp->type == EQN_SUBEXPR) {
		child = bp->first;
		eqn_box(p, child);
		p->flags |= TERMP_NOSPACE;
		term_word(p, bp->pos == EQNPOS_OVER ? "/" :
		    (bp->pos == EQNPOS_SUP ||
		     bp->pos == EQNPOS_TO) ? "^" : "_");
		child = child->next;
		if (child != NULL) {
			p->flags |= TERMP_NOSPACE;
			eqn_box(p, child);
			if (bp->pos == EQNPOS_FROMTO ||
			    bp->pos == EQNPOS_SUBSUP) {
				p->flags |= TERMP_NOSPACE;
				term_word(p, "^");
				p->flags |= TERMP_NOSPACE;
				child = child->next;
				if (child != NULL)
					eqn_box(p, child);
			}
		}
	} else {
		child = bp->first;
		if (bp->type == EQN_MATRIX &&
		    child != NULL &&
		    child->type == EQN_LIST &&
		    child->expectargs > 1)
			child = child->first;
		while (child != NULL) {
			eqn_box(p,
			    bp->type == EQN_PILE &&
			    child->type == EQN_LIST &&
			    child->expectargs > 1 &&
			    child->args == 1 ?
			    child->first : child);
			child = child->next;
		}
	}

	/* Handle Fonts and diacritics. */

	if (bp->font != EQNFONT_NONE)
		term_fontpop(p);
	if (bp->top != NULL) {
		p->flags |= TERMP_NOSPACE;
		term_word(p, bp->top);
	}
	if (bp->bottom != NULL) {
		p->flags |= TERMP_NOSPACE;
		term_word(p, "_");
	}

	/* Right delimiter after this box? */

	if (delim) {
		p->flags |= TERMP_NOSPACE;
		term_word(p, bp->right != NULL ? bp->right : ")");
		if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL)
			p->flags |= TERMP_NOSPACE;
	}
}
示例#13
0
static void
eqn_box(struct termp *p, const struct eqn_box *bp)
{
	const struct eqn_box *child;

	if (bp->type == EQN_LIST ||
	    (bp->type == EQN_PILE && (bp->prev || bp->next)) ||
	    (bp->parent != NULL && bp->parent->pos == EQNPOS_SQRT)) {
		if (bp->parent->type == EQN_SUBEXPR && bp->prev != NULL)
			p->flags |= TERMP_NOSPACE;
		term_word(p, bp->left != NULL ? bp->left : "(");
		p->flags |= TERMP_NOSPACE;
	}
	if (bp->font != EQNFONT_NONE)
		term_fontpush(p, fontmap[(int)bp->font]);

	if (bp->text != NULL)
		term_word(p, bp->text);

	if (bp->pos == EQNPOS_SQRT) {
		term_word(p, "sqrt");
		p->flags |= TERMP_NOSPACE;
		eqn_box(p, bp->first);
	} else if (bp->type == EQN_SUBEXPR) {
		child = bp->first;
		eqn_box(p, child);
		p->flags |= TERMP_NOSPACE;
		term_word(p, bp->pos == EQNPOS_OVER ? "/" :
		    (bp->pos == EQNPOS_SUP ||
		     bp->pos == EQNPOS_TO) ? "^" : "_");
		p->flags |= TERMP_NOSPACE;
		child = child->next;
		eqn_box(p, child);
		if (bp->pos == EQNPOS_FROMTO ||
		    bp->pos == EQNPOS_SUBSUP) {
			p->flags |= TERMP_NOSPACE;
			term_word(p, "^");
			p->flags |= TERMP_NOSPACE;
			child = child->next;
			eqn_box(p, child);
		}
	} else {
		child = bp->first;
		if (bp->type == EQN_MATRIX && child->type == EQN_LIST)
			child = child->first;
		while (child != NULL) {
			eqn_box(p,
			    bp->type == EQN_PILE &&
			    child->type == EQN_LIST &&
			    child->args == 1 ?
			    child->first : child);
			child = child->next;
		}
	}

	if (bp->font != EQNFONT_NONE)
		term_fontpop(p);
	if (bp->type == EQN_LIST ||
	    (bp->type == EQN_PILE && (bp->prev || bp->next)) ||
	    (bp->parent != NULL && bp->parent->pos == EQNPOS_SQRT)) {
		p->flags |= TERMP_NOSPACE;
		term_word(p, bp->right != NULL ? bp->right : ")");
		if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL)
			p->flags |= TERMP_NOSPACE;
	}

	if (bp->top != NULL) {
		p->flags |= TERMP_NOSPACE;
		term_word(p, bp->top);
	}
	if (bp->bottom != NULL) {
		p->flags |= TERMP_NOSPACE;
		term_word(p, "_");
	}
}
示例#14
0
/* ARGSUSED */
static int
termp_it_pre(DECL_ARGS)
{
	const struct mdoc_node *bl, *nn;
	char		        buf[7];
	int		        i;
	size_t		        width, offset, ncols, dcol;
	enum mdoc_list		type;

	if (MDOC_BLOCK == n->type) {
		print_bvspace(p, n->parent->parent, n);
		return(1);
	}

	bl = n->parent->parent->parent;
	type = bl->norm->Bl.type;

	/* 
	 * First calculate width and offset.  This is pretty easy unless
	 * we're a -column list, in which case all prior columns must
	 * be accounted for.
	 */

	width = offset = 0;

	if (bl->norm->Bl.offs)
		offset = a2offs(p, bl->norm->Bl.offs);

	switch (type) {
	case (LIST_column):
		if (MDOC_HEAD == n->type)
			break;

		/*
		 * Imitate groff's column handling:
		 * - For each earlier column, add its width.
		 * - For less than 5 columns, add four more blanks per
		 *   column.
		 * - For exactly 5 columns, add three more blank per
		 *   column.
		 * - For more than 5 columns, add only one column.
		 */
		ncols = bl->norm->Bl.ncols;

		/* LINTED */
		dcol = ncols < 5 ? term_len(p, 4) : 
			ncols == 5 ? term_len(p, 3) : term_len(p, 1);

		/*
		 * Calculate the offset by applying all prior MDOC_BODY,
		 * so we stop at the MDOC_HEAD (NULL == nn->prev).
		 */

		for (i = 0, nn = n->prev; 
				nn->prev && i < (int)ncols; 
				nn = nn->prev, i++)
			offset += dcol + a2width
				(p, bl->norm->Bl.cols[i]);

		/*
		 * When exceeding the declared number of columns, leave
		 * the remaining widths at 0.  This will later be
		 * adjusted to the default width of 10, or, for the last
		 * column, stretched to the right margin.
		 */
		if (i >= (int)ncols)
			break;

		/*
		 * Use the declared column widths, extended as explained
		 * in the preceding paragraph.
		 */
		width = a2width(p, bl->norm->Bl.cols[i]) + dcol;
		break;
	default:
		if (NULL == bl->norm->Bl.width)
			break;

		/* 
		 * Note: buffer the width by 2, which is groff's magic
		 * number for buffering single arguments.  See the above
		 * handling for column for how this changes.
		 */
		assert(bl->norm->Bl.width);
		width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
		break;
	}

	/* 
	 * List-type can override the width in the case of fixed-head
	 * values (bullet, dash/hyphen, enum).  Tags need a non-zero
	 * offset.
	 */

	switch (type) {
	case (LIST_bullet):
		/* FALLTHROUGH */
	case (LIST_dash):
		/* FALLTHROUGH */
	case (LIST_hyphen):
		if (width < term_len(p, 4))
			width = term_len(p, 4);
		break;
	case (LIST_enum):
		if (width < term_len(p, 5))
			width = term_len(p, 5);
		break;
	case (LIST_hang):
		if (0 == width)
			width = term_len(p, 8);
		break;
	case (LIST_column):
		/* FALLTHROUGH */
	case (LIST_tag):
		if (0 == width)
			width = term_len(p, 10);
		break;
	default:
		break;
	}

	/* 
	 * Whitespace control.  Inset bodies need an initial space,
	 * while diagonal bodies need two.
	 */

	p->flags |= TERMP_NOSPACE;

	switch (type) {
	case (LIST_diag):
		if (MDOC_BODY == n->type)
			term_word(p, "\\ \\ ");
		break;
	case (LIST_inset):
		if (MDOC_BODY == n->type) 
			term_word(p, "\\ ");
		break;
	default:
		break;
	}

	p->flags |= TERMP_NOSPACE;

	switch (type) {
	case (LIST_diag):
		if (MDOC_HEAD == n->type)
			term_fontpush(p, TERMFONT_BOLD);
		break;
	default:
		break;
	}

	/*
	 * Pad and break control.  This is the tricky part.  These flags
	 * are documented in term_flushln() in term.c.  Note that we're
	 * going to unset all of these flags in termp_it_post() when we
	 * exit.
	 */

	switch (type) {
	case (LIST_bullet):
		/* FALLTHROUGH */
	case (LIST_dash):
		/* FALLTHROUGH */
	case (LIST_enum):
		/* FALLTHROUGH */
	case (LIST_hyphen):
		if (MDOC_HEAD == n->type)
			p->flags |= TERMP_NOBREAK;
		break;
	case (LIST_hang):
		if (MDOC_HEAD == n->type)
			p->flags |= TERMP_NOBREAK;
		else
			break;

		/*
		 * This is ugly.  If `-hang' is specified and the body
		 * is a `Bl' or `Bd', then we want basically to nullify
		 * the "overstep" effect in term_flushln() and treat
		 * this as a `-ohang' list instead.
		 */
		if (n->next->child && 
				(MDOC_Bl == n->next->child->tok ||
				 MDOC_Bd == n->next->child->tok))
			p->flags &= ~TERMP_NOBREAK;
		else
			p->flags |= TERMP_HANG;
		break;
	case (LIST_tag):
		if (MDOC_HEAD == n->type)
			p->flags |= TERMP_NOBREAK | TERMP_TWOSPACE;

		if (MDOC_HEAD != n->type)
			break;
		if (NULL == n->next || NULL == n->next->child)
			p->flags |= TERMP_DANGLE;
		break;
	case (LIST_column):
		if (MDOC_HEAD == n->type)
			break;

		if (NULL == n->next)
			p->flags &= ~TERMP_NOBREAK;
		else
			p->flags |= TERMP_NOBREAK;

		break;
	case (LIST_diag):
		if (MDOC_HEAD == n->type)
			p->flags |= TERMP_NOBREAK;
		break;
	default:
		break;
	}

	/* 
	 * Margin control.  Set-head-width lists have their right
	 * margins shortened.  The body for these lists has the offset
	 * necessarily lengthened.  Everybody gets the offset.
	 */

	p->offset += offset;

	switch (type) {
	case (LIST_hang):
		/*
		 * Same stipulation as above, regarding `-hang'.  We
		 * don't want to recalculate rmargin and offsets when
		 * using `Bd' or `Bl' within `-hang' overstep lists.
		 */
		if (MDOC_HEAD == n->type && n->next->child &&
				(MDOC_Bl == n->next->child->tok || 
				 MDOC_Bd == n->next->child->tok))
			break;
		/* FALLTHROUGH */
	case (LIST_bullet):
		/* FALLTHROUGH */
	case (LIST_dash):
		/* FALLTHROUGH */
	case (LIST_enum):
		/* FALLTHROUGH */
	case (LIST_hyphen):
		/* FALLTHROUGH */
	case (LIST_tag):
		assert(width);
		if (MDOC_HEAD == n->type)
			p->rmargin = p->offset + width;
		else 
			p->offset += width;
		break;
	case (LIST_column):
		assert(width);
		p->rmargin = p->offset + width;
		/* 
		 * XXX - this behaviour is not documented: the
		 * right-most column is filled to the right margin.
		 */
		if (MDOC_HEAD == n->type)
			break;
		if (NULL == n->next && p->rmargin < p->maxrmargin)
			p->rmargin = p->maxrmargin;
		break;
	default:
		break;
	}

	/* 
	 * The dash, hyphen, bullet and enum lists all have a special
	 * HEAD character (temporarily bold, in some cases).  
	 */

	if (MDOC_HEAD == n->type)
		switch (type) {
		case (LIST_bullet):
			term_fontpush(p, TERMFONT_BOLD);
			term_word(p, "\\[bu]");
			term_fontpop(p);
			break;
		case (LIST_dash):
			/* FALLTHROUGH */
		case (LIST_hyphen):
			term_fontpush(p, TERMFONT_BOLD);
			term_word(p, "\\(hy");
			term_fontpop(p);
			break;
		case (LIST_enum):
			(pair->ppair->ppair->count)++;
			snprintf(buf, sizeof(buf), "%d.", 
					pair->ppair->ppair->count);
			term_word(p, buf);
			break;
		default:
			break;
		}

	/* 
	 * If we're not going to process our children, indicate so here.
	 */

	switch (type) {
	case (LIST_bullet):
		/* FALLTHROUGH */
	case (LIST_item):
		/* FALLTHROUGH */
	case (LIST_dash):
		/* FALLTHROUGH */
	case (LIST_hyphen):
		/* FALLTHROUGH */
	case (LIST_enum):
		if (MDOC_HEAD == n->type)
			return(0);
		break;
	case (LIST_column):
		if (MDOC_HEAD == n->type)
			return(0);
		break;
	default:
		break;
	}

	return(1);
}