static int pre_RS(DECL_ARGS) { int ival; size_t sz; switch (n->type) { case MAN_BLOCK: term_newln(p); return(1); case MAN_HEAD: return(0); default: break; } sz = term_len(p, p->defindent); if (NULL != (n = n->parent->head->child)) if ((ival = a2width(p, n->string)) >= 0) sz = (size_t)ival; mt->offset += sz; p->offset = mt->offset; p->rmargin = p->maxrmargin > p->offset ? p->maxrmargin : p->offset; if (++mt->lmarginsz < MAXMARGINS) mt->lmargincur = mt->lmarginsz; mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1]; return(1); }
static int man_RS_pre(MAN_ARGS) { struct roffsu su; if (n->type == ROFFT_HEAD) return 0; else if (n->type == ROFFT_BODY) return 1; SCALE_HS_INIT(&su, INDENT); if (n->head->child) a2width(n->head->child, &su); print_otag(h, TAG_DIV, "sul", &su); return 1; }
/* ARGSUSED */ static int pre_in(DECL_ARGS) { int len, less; size_t v; const char *cp; term_newln(p); if (NULL == n->child) { p->offset = mt->offset; return(0); } cp = n->child->string; less = 0; if ('-' == *cp) less = -1; else if ('+' == *cp) less = 1; else cp--; if ((len = a2width(p, ++cp)) < 0) return(0); v = (size_t)len; if (less < 0) p->offset -= p->offset > v ? v : p->offset; else if (less > 0) p->offset += v; else p->offset = v; /* Don't let this creep beyond the right margin. */ if (p->offset > p->rmargin) p->offset = p->rmargin; return(0); }
static int pre_HP(DECL_ARGS) { size_t len, one; int ival; const struct man_node *nn; switch (n->type) { case MAN_BLOCK: print_bvspace(p, n, mt->pardist); return(1); case MAN_BODY: break; default: return(0); } if ( ! (MANT_LITERAL & mt->fl)) { p->flags |= TERMP_NOBREAK | TERMP_BRIND; p->trailspace = 2; } len = mt->lmargin[mt->lmargincur]; ival = -1; /* Calculate offset. */ if (NULL != (nn = n->parent->head->child)) if ((ival = a2width(p, nn->string)) >= 0) len = (size_t)ival; one = term_len(p, 1); if (len < one) len = one; p->offset = mt->offset; p->rmargin = mt->offset + len; if (ival >= 0) mt->lmargin[mt->lmargincur] = (size_t)ival; return(1); }
static int man_RS_pre(MAN_ARGS) { struct htmlpair tag; struct roffsu su; if (MAN_HEAD == n->type) return(0); else if (MAN_BODY == n->type) return(1); SCALE_HS_INIT(&su, INDENT); if (n->head->child) a2width(n->head->child, &su); bufinit(h); bufcat_su(h, "margin-left", &su); PAIR_STYLE_INIT(&tag, h); print_otag(h, TAG_DIV, 1, &tag); return(1); }
/* ARGSUSED */ static int pre_HP(DECL_ARGS) { size_t len; int ival; const struct man_node *nn; switch (n->type) { case (MAN_BLOCK): print_bvspace(p, n); return(1); case (MAN_BODY): p->flags |= TERMP_NOBREAK; p->flags |= TERMP_TWOSPACE; break; default: return(0); } len = mt->lmargin; ival = -1; /* Calculate offset. */ if (NULL != (nn = n->parent->head->child)) if ((ival = a2width(p, nn->string)) >= 0) len = (size_t)ival; if (0 == len) len = term_len(p, 1); p->offset = mt->offset; p->rmargin = mt->offset + len; if (ival >= 0) mt->lmargin = (size_t)ival; return(1); }
static int man_HP_pre(MAN_ARGS) { struct roffsu sum, sui; const struct roff_node *np; if (n->type == ROFFT_HEAD) return 0; else if (n->type != ROFFT_BLOCK) return 1; np = n->head->child; if (np == NULL || !a2width(np, &sum)) SCALE_HS_INIT(&sum, INDENT); sui.unit = sum.unit; sui.scale = -sum.scale; print_bvspace(h, n); print_otag(h, TAG_DIV, "csului", "Pp", &sum, &sui); return 1; }
/* ARGSUSED */ static int mdoc_bl_pre(MDOC_ARGS) { int i; struct htmlpair tag[3]; struct roffsu su; char buf[BUFSIZ]; if (MDOC_BODY == n->type) { if (LIST_column == n->norm->Bl.type) print_otag(h, TAG_TBODY, 0, NULL); return(1); } if (MDOC_HEAD == n->type) { if (LIST_column != n->norm->Bl.type) return(0); /* * For each column, print out the <COL> tag with our * suggested width. The last column gets min-width, as * in terminal mode it auto-sizes to the width of the * screen and we want to preserve that behaviour. */ for (i = 0; i < (int)n->norm->Bl.ncols; i++) { a2width(n->norm->Bl.cols[i], &su); bufinit(h); if (i < (int)n->norm->Bl.ncols - 1) bufcat_su(h, "width", &su); else bufcat_su(h, "min-width", &su); PAIR_STYLE_INIT(&tag[0], h); print_otag(h, TAG_COL, 1, tag); } return(0); } SCALE_VS_INIT(&su, 0); bufcat_su(h, "margin-top", &su); bufcat_su(h, "margin-bottom", &su); PAIR_STYLE_INIT(&tag[0], h); assert(lists[n->norm->Bl.type]); strlcpy(buf, "list ", BUFSIZ); strlcat(buf, lists[n->norm->Bl.type], BUFSIZ); PAIR_INIT(&tag[1], ATTR_CLASS, buf); /* Set the block's left-hand margin. */ if (n->norm->Bl.offs) { a2offs(n->norm->Bl.offs, &su); bufcat_su(h, "margin-left", &su); } switch (n->norm->Bl.type) { case(LIST_bullet): /* FALLTHROUGH */ case(LIST_dash): /* FALLTHROUGH */ case(LIST_hyphen): /* FALLTHROUGH */ case(LIST_item): print_otag(h, TAG_UL, 2, tag); break; case(LIST_enum): print_otag(h, TAG_OL, 2, tag); break; case(LIST_diag): /* FALLTHROUGH */ case(LIST_hang): /* FALLTHROUGH */ case(LIST_inset): /* FALLTHROUGH */ case(LIST_ohang): /* FALLTHROUGH */ case(LIST_tag): print_otag(h, TAG_DL, 2, tag); break; case(LIST_column): print_otag(h, TAG_TABLE, 2, tag); break; default: abort(); /* NOTREACHED */ } return(1); }
/* ARGSUSED */ static int mdoc_it_pre(MDOC_ARGS) { struct roffsu su; enum mdoc_list type; struct htmlpair tag[2]; const struct mdoc_node *bl; bl = n->parent; while (bl && MDOC_Bl != bl->tok) bl = bl->parent; assert(bl); type = bl->norm->Bl.type; assert(lists[type]); PAIR_CLASS_INIT(&tag[0], lists[type]); if (MDOC_HEAD == n->type) { switch (type) { case(LIST_bullet): /* FALLTHROUGH */ case(LIST_dash): /* FALLTHROUGH */ case(LIST_item): /* FALLTHROUGH */ case(LIST_hyphen): /* FALLTHROUGH */ case(LIST_enum): return(0); case(LIST_diag): /* FALLTHROUGH */ case(LIST_hang): /* FALLTHROUGH */ case(LIST_inset): /* FALLTHROUGH */ case(LIST_ohang): /* FALLTHROUGH */ case(LIST_tag): SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); bufcat_su(h, "margin-top", &su); PAIR_STYLE_INIT(&tag[1], h); print_otag(h, TAG_DT, 2, tag); if (LIST_diag != type) break; PAIR_CLASS_INIT(&tag[0], "diag"); print_otag(h, TAG_B, 1, tag); break; case(LIST_column): break; default: break; } } else if (MDOC_BODY == n->type) { switch (type) { case(LIST_bullet): /* FALLTHROUGH */ case(LIST_hyphen): /* FALLTHROUGH */ case(LIST_dash): /* FALLTHROUGH */ case(LIST_enum): /* FALLTHROUGH */ case(LIST_item): SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); bufcat_su(h, "margin-top", &su); PAIR_STYLE_INIT(&tag[1], h); print_otag(h, TAG_LI, 2, tag); break; case(LIST_diag): /* FALLTHROUGH */ case(LIST_hang): /* FALLTHROUGH */ case(LIST_inset): /* FALLTHROUGH */ case(LIST_ohang): /* FALLTHROUGH */ case(LIST_tag): if (NULL == bl->norm->Bl.width) { print_otag(h, TAG_DD, 1, tag); break; } a2width(bl->norm->Bl.width, &su); bufcat_su(h, "margin-left", &su); PAIR_STYLE_INIT(&tag[1], h); print_otag(h, TAG_DD, 2, tag); break; case(LIST_column): SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); bufcat_su(h, "margin-top", &su); PAIR_STYLE_INIT(&tag[1], h); print_otag(h, TAG_TD, 2, tag); break; default: break; } } else { switch (type) { case (LIST_column): print_otag(h, TAG_TR, 1, tag); break; default: break; } } return(1); }
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; }
static int termp_bd_pre(DECL_ARGS) { size_t tabwidth, lm, len, rm, rmax; struct roff_node *nn; int offset; if (n->type == ROFFT_BLOCK) { print_bvspace(p, n, n); return 1; } else if (n->type == ROFFT_HEAD) return 0; /* Handle the -offset argument. */ if (n->norm->Bd.offs == NULL || ! strcmp(n->norm->Bd.offs, "left")) /* nothing */; else if ( ! strcmp(n->norm->Bd.offs, "indent")) p->offset += term_len(p, p->defindent + 1); else if ( ! strcmp(n->norm->Bd.offs, "indent-two")) p->offset += term_len(p, (p->defindent + 1) * 2); else { offset = a2width(p, n->norm->Bd.offs); if (offset < 0 && (size_t)(-offset) > p->offset) p->offset = 0; else if (offset < SHRT_MAX) p->offset += offset; } /* * If -ragged or -filled are specified, the block does nothing * but change the indentation. If -unfilled or -literal are * specified, text is printed exactly as entered in the display: * for macro lines, a newline is appended to the line. Blank * lines are allowed. */ if (DISP_literal != n->norm->Bd.type && DISP_unfilled != n->norm->Bd.type && DISP_centered != n->norm->Bd.type) return 1; tabwidth = p->tabwidth; if (DISP_literal == n->norm->Bd.type) p->tabwidth = term_len(p, 8); lm = p->offset; rm = p->rmargin; rmax = p->maxrmargin; p->rmargin = p->maxrmargin = TERM_MAXMARGIN; for (nn = n->child; nn; nn = nn->next) { if (DISP_centered == n->norm->Bd.type) { if (nn->type == ROFFT_TEXT) { len = term_strlen(p, nn->string); p->offset = len >= rm ? 0 : lm + len >= rm ? rm - len : (lm + rm - len) / 2; } else p->offset = lm; } print_mdoc_node(p, pair, meta, nn); /* * If the printed node flushes its own line, then we * needn't do it here as well. This is hacky, but the * notion of selective eoln whitespace is pretty dumb * anyway, so don't sweat it. */ switch (nn->tok) { case MDOC_Sm: case MDOC_br: case MDOC_sp: case MDOC_Bl: case MDOC_D1: case MDOC_Dl: case MDOC_Lp: case MDOC_Pp: continue; default: break; } if (p->flags & TERMP_NONEWLINE || (nn->next && ! (nn->next->flags & MDOC_LINE))) continue; term_flushln(p); p->flags |= TERMP_NOSPACE; } p->tabwidth = tabwidth; p->rmargin = rm; p->maxrmargin = rmax; return 0; }
/* ARGSUSED */ static int pre_TP(DECL_ARGS) { const struct man_node *nn; size_t len; int savelit, ival; switch (n->type) { case (MAN_HEAD): p->flags |= TERMP_NOBREAK; break; case (MAN_BODY): p->flags |= TERMP_NOSPACE; break; case (MAN_BLOCK): print_bvspace(p, n); /* FALLTHROUGH */ default: return(1); } len = (size_t)mt->lmargin[mt->lmargincur]; ival = -1; /* Calculate offset. */ if (NULL != (nn = n->parent->head->child)) if (nn->string && nn->parent->line == nn->line) if ((ival = a2width(p, nn->string)) >= 0) len = (size_t)ival; switch (n->type) { case (MAN_HEAD): /* Handle zero-length properly. */ if (0 == len) len = term_len(p, 1); p->offset = mt->offset; p->rmargin = mt->offset + len; savelit = MANT_LITERAL & mt->fl; mt->fl &= ~MANT_LITERAL; /* Don't print same-line elements. */ for (nn = n->child; nn; nn = nn->next) if (nn->line > n->line) print_man_node(p, mt, nn, m); if (savelit) mt->fl |= MANT_LITERAL; if (ival >= 0) mt->lmargin[mt->lmargincur] = (size_t)ival; return(0); case (MAN_BODY): p->offset = mt->offset + len; p->rmargin = p->maxrmargin; break; default: break; } return(1); }
/* ARGSUSED */ static int pre_IP(DECL_ARGS) { const struct man_node *nn; size_t len; int savelit, ival; switch (n->type) { case (MAN_BODY): p->flags |= TERMP_NOSPACE; break; case (MAN_HEAD): p->flags |= TERMP_NOBREAK; break; case (MAN_BLOCK): print_bvspace(p, n); /* FALLTHROUGH */ default: return(1); } len = mt->lmargin[mt->lmargincur]; ival = -1; /* Calculate the offset from the optional second argument. */ if (NULL != (nn = n->parent->head->child)) if (NULL != (nn = nn->next)) if ((ival = a2width(p, nn->string)) >= 0) len = (size_t)ival; switch (n->type) { case (MAN_HEAD): /* Handle zero-width lengths. */ if (0 == len) len = term_len(p, 1); p->offset = mt->offset; p->rmargin = mt->offset + len; if (ival < 0) break; /* Set the saved left-margin. */ mt->lmargin[mt->lmargincur] = (size_t)ival; savelit = MANT_LITERAL & mt->fl; mt->fl &= ~MANT_LITERAL; if (n->child) print_man_node(p, mt, n->child, m); if (savelit) mt->fl |= MANT_LITERAL; return(0); case (MAN_BODY): p->offset = mt->offset + len; p->rmargin = p->maxrmargin; break; default: break; } return(1); }
static int mdoc_bd_pre(MDOC_ARGS) { struct htmlpair tag[2]; int comp, sv; struct mdoc_node *nn; struct roffsu su; if (MDOC_HEAD == n->type) return(0); if (MDOC_BLOCK == n->type) { comp = n->norm->Bd.comp; for (nn = n; nn && ! comp; nn = nn->parent) { if (MDOC_BLOCK != nn->type) continue; if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok) comp = 1; if (nn->prev) break; } if ( ! comp) print_paragraph(h); return(1); } /* Handle the -offset argument. */ if (n->norm->Bd.offs == NULL || ! strcmp(n->norm->Bd.offs, "left")) SCALE_HS_INIT(&su, 0); else if ( ! strcmp(n->norm->Bd.offs, "indent")) SCALE_HS_INIT(&su, INDENT); else if ( ! strcmp(n->norm->Bd.offs, "indent-two")) SCALE_HS_INIT(&su, INDENT * 2); else a2width(n->norm->Bd.offs, &su); bufinit(h); bufcat_su(h, "margin-left", &su); PAIR_STYLE_INIT(&tag[0], h); if (DISP_unfilled != n->norm->Bd.type && DISP_literal != n->norm->Bd.type) { PAIR_CLASS_INIT(&tag[1], "display"); print_otag(h, TAG_DIV, 2, tag); return(1); } PAIR_CLASS_INIT(&tag[1], "lit display"); print_otag(h, TAG_PRE, 2, tag); /* This can be recursive: save & set our literal state. */ sv = h->flags & HTML_LITERAL; h->flags |= HTML_LITERAL; for (nn = n->child; nn; nn = nn->next) { print_mdoc_node(meta, nn, h); /* * If the printed node flushes its own line, then we * needn't do it here as well. This is hacky, but the * notion of selective eoln whitespace is pretty dumb * anyway, so don't sweat it. */ switch (nn->tok) { case MDOC_Sm: /* FALLTHROUGH */ case MDOC_br: /* FALLTHROUGH */ case MDOC_sp: /* FALLTHROUGH */ case MDOC_Bl: /* FALLTHROUGH */ case MDOC_D1: /* FALLTHROUGH */ case MDOC_Dl: /* FALLTHROUGH */ case MDOC_Lp: /* FALLTHROUGH */ case MDOC_Pp: continue; default: break; } if (h->flags & HTML_NONEWLINE || (nn->next && ! (nn->next->flags & MDOC_LINE))) continue; else if (nn->next) print_text(h, "\n"); h->flags |= HTML_NOSPACE; } if (0 == sv) h->flags &= ~HTML_LITERAL; return(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); }