/* 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 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): /* FALLTHROUGH */ case (LIST_enum): if (width < term_len(p, 2)) width = term_len(p, 2); 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_enum): /* * Weird special case. * Very narrow enum lists actually hang. */ if (width == term_len(p, 2)) p->flags |= TERMP_HANG; /* FALLTHROUGH */ case (LIST_bullet): /* FALLTHROUGH */ case (LIST_dash): /* FALLTHROUGH */ case (LIST_hyphen): if (MDOC_HEAD != n->type) break; p->flags |= TERMP_NOBREAK; p->trailspace = 1; break; case (LIST_hang): if (MDOC_HEAD != n->type) 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)) break; p->flags |= TERMP_NOBREAK | TERMP_HANG; p->trailspace = 1; break; case (LIST_tag): if (MDOC_HEAD != n->type) break; p->flags |= TERMP_NOBREAK; p->trailspace = 2; 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; p->trailspace = 0; } else { p->flags |= TERMP_NOBREAK; p->trailspace = 1; } break; case (LIST_diag): if (MDOC_HEAD != n->type) break; p->flags |= TERMP_NOBREAK; 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 (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); }
/* ARGSUSED */ static int mdoc_bd_pre(MDOC_ARGS) { struct htmlpair tag[2]; int comp, sv; const 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_otag(h, TAG_P, 0, NULL); return(1); } SCALE_HS_INIT(&su, 0); if (n->norm->Bd.offs) a2offs(n->norm->Bd.offs, &su); 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(m, 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 (nn->next && nn->next->line == nn->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_bd_pre(DECL_ARGS) { size_t tabwidth, rm, rmax; struct mdoc_node *nn; if (MDOC_BLOCK == n->type) { print_bvspace(p, n, n); return(1); } else if (MDOC_HEAD == n->type) return(0); if (n->norm->Bd.offs) p->offset += a2offs(p, n->norm->Bd.offs); /* * 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) return(1); tabwidth = p->tabwidth; if (DISP_literal == n->norm->Bd.type) p->tabwidth = term_len(p, 8); rm = p->rmargin; rmax = p->maxrmargin; p->rmargin = p->maxrmargin = TERM_MAXMARGIN; for (nn = n->child; nn; nn = nn->next) { 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): /* 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 (nn->next && nn->next->line == nn->line) continue; term_flushln(p); p->flags |= TERMP_NOSPACE; } p->tabwidth = tabwidth; p->rmargin = rm; p->maxrmargin = rmax; return(0); }