mdoc_term.c revision 260e9a87725c090ba5835b1f9f0b62fa2f96036f
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov/* $Id: mdoc_term.c,v 1.313 2015/03/06 15:48:52 schwarze Exp $ */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * copyright notice and this permission notice appear in all copies.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankovstatic int a2width(const struct termp *, const char *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const struct mdoc_node *,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const struct mdoc_node *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void print_mdoc_head(struct termp *, const void *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic void print_mdoc_foot(struct termp *, const void *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore const struct mdoc_node *);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorestatic const struct termact termacts[MDOC_MAX] = {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Op */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_under_pre, termp____post }, /* %B */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_under_pre, termp____post }, /* %I */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_under_pre, termp____post }, /* %J */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Ao */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Aq */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Bo */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Bq */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Do */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Dq */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { NULL, NULL }, /* Ec */ /* FIXME: no space */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Po */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Pq */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Ql */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Qo */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Qq */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* So */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Sq */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore { termp_quote_pre, termp_quote_post }, /* Oo */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { termp_quote_pre, termp_quote_post }, /* Brq */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov { termp_quote_pre, termp_quote_post }, /* Bro */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreterminal_mdoc(void *arg, const struct mdoc *mdoc)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (n != NULL) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov while (n != NULL) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Keeps only work until the end of a line. If a keep was
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * invoked in a prior line, revert it to PREKEEP.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (p->flags & TERMP_KEEP && n->flags & MDOC_LINE) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * After the keep flags have been set up, we may now
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * produce output. Note that some pre-handlers do so.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->type) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (' ' == *n->string && MDOC_LINE & n->flags)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (n->next != NULL && ! (n->next->flags & MDOC_LINE))
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore print_mdoc_nodelist(p, &npair, meta, n->child);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (ENDBODY_NOT == n->end ? n : n->body)->prev_font);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->type) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags)
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore (void)(*termacts[n->tok].post)(p, &npair, meta, n);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Explicit end tokens not only call the post
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * handler, but also tell the respective block
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * that it must not call the post handler again.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * End of line terminating an implicit block
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * while an explicit block is still open.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Continue the explicit block without spacing.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreprint_mdoc_foot(struct termp *p, const void *arg)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Output the footer in new-groff style, that is, three columns
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * with the middle being the manual date and flanking columns
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * being the operating system:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * SYSTEM DATE SYSTEM
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoreprint_mdoc_head(struct termp *p, const void *arg)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * The header is strange. It has three components, which are
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * really two with the first duplicated. It goes like this:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * IDENTIFIER TITLE IDENTIFIER
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * The IDENTIFIER is NAME(SECTION), which is the command-name
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * (if given, or "unknown" if not) followed by the manual page
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * section. These are given in `Dt'. The TITLE is a free-form
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * string depending on the manual volume. If not specified, it
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * switches on the manual section.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amorea2width(const struct termp *p, const char *v)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Determine how much space to print out before block elements of `It'
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * (and thus `Bl') and `Bd'. And then go ahead and print that space,
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const struct mdoc_node *n)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (MDOC_Bd == bl->tok && bl->norm->Bd.comp)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (MDOC_Bl == bl->tok && bl->norm->Bl.comp)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* Do not vspace directly after Ss/Sh. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* A `-column' does not assert vspace within the list. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* A `-diag' without body does not vspace. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov term_setwidth(p, n->nchild ? n->child->string : NULL);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Defaults for specific list types.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* FALLTHROUGH */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* FALLTHROUGH */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* FALLTHROUGH */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * First calculate width and offset. This is pretty easy unless
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * we're a -column list, in which case all prior columns must
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * be accounted for.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (offset < 0 && (size_t)(-offset) > p->offset)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Imitate groff's column handling:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * - For each earlier column, add its width.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * - For less than 5 columns, add four more blanks per
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * - For exactly 5 columns, add three more blank per
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * - For more than 5 columns, add only one column.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Calculate the offset by applying all prior MDOC_BODY,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * so we stop at the MDOC_HEAD (NULL == nn->prev).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * When exceeding the declared number of columns, leave
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the remaining widths at 0. This will later be
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * adjusted to the default width of 10, or, for the last
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * column, stretched to the right margin.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (i >= (int)ncols)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Use the declared column widths, extended as explained
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * in the preceding paragraph.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore width = a2width(p, bl->norm->Bl.cols[i]) + dcol;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Note: buffer the width by 2, which is groff's magic
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * number for buffering single arguments. See the above
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * handling for column for how this changes.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Whitespace control. Inset bodies need an initial space,
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * while diagonal bodies need two.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (MDOC_BODY == n->type && n->parent->head->nchild)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Pad and break control. This is the tricky part. These flags
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * are documented in term_flushln() in term.c. Note that we're
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * going to unset all of these flags in termp_it_post() when we
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore * Weird special case.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Some very narrow lists actually hang.
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * This is ugly. If `-hang' is specified and the body
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * is a `Bl' or `Bd', then we want basically to nullify
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * the "overstep" effect in term_flushln() and treat
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * this as a `-ohang' list instead.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == n->next || NULL == n->next->child)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Margin control. Set-head-width lists have their right
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * margins shortened. The body for these lists has the offset
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * necessarily lengthened. Everybody gets the offset.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Same stipulation as above, regarding `-hang'. We
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * don't want to recalculate rmargin and offsets when
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * using `Bd' or `Bl' within `-hang' overstep lists.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * XXX - this behaviour is not documented: the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * right-most column is filled to the right margin.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == n->next && p->rmargin < p->maxrmargin)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * The dash, hyphen, bullet and enum lists all have a special
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * HEAD character (temporarily bold, in some cases).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we're not going to process our children, indicate so here.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore type = n->parent->parent->parent->norm->Bl.type;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Now that our output is flushed, we can reset our tags. Since
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * only `It' sets these flags, we're free to assume that nobody
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * has munged them in the meanwhile.
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov const char *cp;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->offset += term_len(p, 1) + term_strlen(p, cp);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->rmargin += term_strlen(p, n->child->string);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore } else if (MDOC_BODY == n->type && n->child)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! (n->nchild == 0 &&
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == n->next || MDOC__A != n->next->tok)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (n->sec == SEC_AUTHORS && ! (p->flags & TERMP_NOSPLIT))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov " the value\\~0 is returned;");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov term_word(p, "otherwise the value\\~\\-1 is returned"
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov " and the global variable");
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov term_word(p, "on success, and\\~>0 if an error occurs.");
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * This decides how to assert whitespace before any of the SYNOPSIS set
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * macro combos).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amoresynopsis_pre(struct termp *p, const struct mdoc_node *n)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Obviously, if we're not in a SYNOPSIS or no prior macros
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * exist, do nothing.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we're the second in a pair of like elements, emit our
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * newline and return. UNLESS we're `Fo', `Fn', `Fn', in which
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * case we soldier on.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we're one of the SYNOPSIS set and non-like pair-wise after
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * another (or Fn/Fo, which we've let slip through) then assert
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * vertical space, else only newline and move on.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->type) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * Vertical space before sections, except
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov * when the previous section was empty.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->type) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore term_word(p, "currently under development.");
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* NB: MDOC_LINE does not effect this! */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore if (nn->next || (n->next && n->next->tok == MDOC_Fa)) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* Handle the -offset argument. */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov /* nothing */;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov p->offset += term_len(p, (p->defindent + 1) * 2);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (offset < 0 && (size_t)(-offset) > p->offset)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If -ragged or -filled are specified, the block does nothing
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * but change the indentation. If -unfilled or -literal are
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * specified, text is printed exactly as entered in the display:
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * for macro lines, a newline is appended to the line. Blank
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * lines are allowed.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If the printed node flushes its own line, then we
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * needn't do it here as well. This is hacky, but the
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * notion of selective eoln whitespace is pretty dumb
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * anyway, so don't sweat it.
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->tok) {
698f87a48e2e945bfe5493ce168e0d0ae1cedd5cGarrett D'Amore /* NOTREACHED */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! (n->next == NULL || n->next->flags & MDOC_LINE))
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->type) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore p->offset = term_len(p, (p->defindent+1)/2);
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (n->type == MDOC_HEAD || n->type == MDOC_BODY)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->tok) {
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if ( ! a2roffsu(n->child->string, &su, SCALE_VS))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (len < 0)
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov for (i = 0; i < len; i++)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (MDOC_BODY != n->type && MDOC_ELEM != n->type)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->tok) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* NOTREACHED */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov if (n->type != MDOC_BODY && n->type != MDOC_ELEM)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->tok) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* FALLTHROUGH */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* NOTREACHED */
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if (n->end != ENDBODY_NOT ? n->child != NULL :
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov n->parent->head->child != NULL && (n->child != NULL ||
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov (n->parent->tail != NULL && n->parent->tail->child != NULL)))
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov body = n->child != NULL || n->parent->head->child != NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
260e9a87725c090ba5835b1f9f0b62fa2f96036fYuri Pankov else if ( ! tail)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* XXX: we drop non-initial arguments as per groff. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * Handle lists of authors. In general, print each followed by
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * a comma. Don't print the comma if there are only two
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == n->next->next || MDOC__A != n->next->next->tok)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == n->prev || MDOC__A != n->prev->tok)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* TODO: %U. */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (NULL == n->parent || MDOC_Rs != n->parent->tok)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore switch (n->type) {
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (n->parent->args || 0 == n->prev->nchild)
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore /* NOTREACHED */
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we're in an `Rs' and there's a journal present, then quote
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * us instead of underlining us (for disambiguation).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (n->parent && MDOC_Rs == n->parent->tok &&
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * If we're in an `Rs' and there's a journal present, then quote
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore * us instead of underlining us (for disambiguation).
95c635efb7c3b86efc493e0447eaec7aecca3f0fGarrett D'Amore if (n->parent && MDOC_Rs == n->parent->tok &&