=================================================================== RCS file: /cvs/mandoc/mdoc_term.c,v retrieving revision 1.283 retrieving revision 1.305 diff -u -p -r1.283 -r1.305 --- mandoc/mdoc_term.c 2014/10/13 22:00:47 1.283 +++ mandoc/mdoc_term.c 2015/01/31 00:12:41 1.305 @@ -1,7 +1,7 @@ -/* $Id: mdoc_term.c,v 1.283 2014/10/13 22:00:47 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.305 2015/01/31 00:12:41 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze + * Copyright (c) 2010, 2012-2015 Ingo Schwarze * Copyright (c) 2013 Franco Fichtner * * Permission to use, copy, modify, and distribute this software for any @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -49,9 +50,7 @@ struct termact { void (*post)(DECL_ARGS); }; -static size_t a2width(const struct termp *, const char *); -static size_t a2height(const struct termp *, const char *); -static size_t a2offs(const struct termp *, const char *); +static int a2width(const struct termp *, const char *); static void print_bvspace(struct termp *, const struct mdoc_node *, @@ -92,7 +91,6 @@ static int termp_bt_pre(DECL_ARGS); static int termp_bx_pre(DECL_ARGS); static int termp_cd_pre(DECL_ARGS); static int termp_d1_pre(DECL_ARGS); -static int termp_es_pre(DECL_ARGS); static int termp_ex_pre(DECL_ARGS); static int termp_fa_pre(DECL_ARGS); static int termp_fd_pre(DECL_ARGS); @@ -112,6 +110,7 @@ static int termp_quote_pre(DECL_ARGS); static int termp_rs_pre(DECL_ARGS); static int termp_rv_pre(DECL_ARGS); static int termp_sh_pre(DECL_ARGS); +static int termp_skip_pre(DECL_ARGS); static int termp_sm_pre(DECL_ARGS); static int termp_sp_pre(DECL_ARGS); static int termp_ss_pre(DECL_ARGS); @@ -184,7 +183,7 @@ static const struct termact termacts[MDOC_MAX] = { { termp_quote_pre, termp_quote_post }, /* Bq */ { termp_xx_pre, NULL }, /* Bsx */ { termp_bx_pre, NULL }, /* Bx */ - { NULL, NULL }, /* Db */ + { termp_skip_pre, NULL }, /* Db */ { NULL, NULL }, /* Dc */ { termp_quote_pre, termp_quote_post }, /* Do */ { termp_quote_pre, termp_quote_post }, /* Dq */ @@ -194,7 +193,7 @@ static const struct termact termacts[MDOC_MAX] = { { termp_quote_pre, termp_quote_post }, /* Eo */ { termp_xx_pre, NULL }, /* Fx */ { termp_bold_pre, NULL }, /* Ms */ - { NULL, NULL }, /* No */ + { termp_li_pre, NULL }, /* No */ { termp_ns_pre, NULL }, /* Ns */ { termp_xx_pre, NULL }, /* Nx */ { termp_xx_pre, NULL }, /* Ox */ @@ -236,7 +235,7 @@ static const struct termact termacts[MDOC_MAX] = { { termp_quote_pre, termp_quote_post }, /* Bro */ { NULL, NULL }, /* Brc */ { NULL, termp____post }, /* %C */ - { termp_es_pre, NULL }, /* Es */ + { termp_skip_pre, NULL }, /* Es */ { termp_quote_pre, termp_quote_post }, /* En */ { termp_xx_pre, NULL }, /* Dx */ { NULL, termp____post }, /* %Q */ @@ -261,9 +260,6 @@ terminal_mdoc(void *arg, const struct mdoc *mdoc) p->rmargin = p->maxrmargin = p->defrmargin; p->tabwidth = term_len(p, 5); - if (NULL == p->symtab) - p->symtab = mchars_alloc(); - n = mdoc_node(mdoc)->child; meta = mdoc_meta(mdoc); @@ -295,9 +291,10 @@ static void print_mdoc_nodelist(DECL_ARGS) { - print_mdoc_node(p, pair, meta, n); - if (n->next) - print_mdoc_nodelist(p, pair, meta, n->next); + while (n != NULL) { + print_mdoc_node(p, pair, meta, n); + n = n->next; + } } static void @@ -310,7 +307,7 @@ print_mdoc_node(DECL_ARGS) chld = 1; offset = p->offset; rmargin = p->rmargin; - n->prev_font = term_fontq(p); + n->prev_font = p->fonti; memset(&npair, 0, sizeof(struct termpair)); npair.ppair = pair; @@ -344,13 +341,18 @@ print_mdoc_node(DECL_ARGS) p->flags |= TERMP_NOSPACE; break; case MDOC_EQN: + if ( ! (n->flags & MDOC_LINE)) + p->flags |= TERMP_NOSPACE; term_eqn(p, n->eqn); + if (n->next != NULL && ! (n->next->flags & MDOC_LINE)) + p->flags |= TERMP_NOSPACE; break; case MDOC_TBL: term_tbl(p, n->span); break; default: - if (termacts[n->tok].pre && ENDBODY_NOT == n->end) + if (termacts[n->tok].pre && + (n->end == ENDBODY_NOT || n->nchild)) chld = (*termacts[n->tok].pre) (p, &npair, meta, n); break; @@ -405,6 +407,7 @@ static void print_mdoc_foot(struct termp *p, const void *arg) { const struct mdoc_meta *meta; + size_t sz; meta = (const struct mdoc_meta *)arg; @@ -421,8 +424,9 @@ print_mdoc_foot(struct termp *p, const void *arg) term_vspace(p); p->offset = 0; - p->rmargin = (p->maxrmargin - - term_strlen(p, meta->date) + term_len(p, 1)) / 2; + sz = term_strlen(p, meta->date); + p->rmargin = p->maxrmargin > sz ? + (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0; p->trailspace = 1; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; @@ -430,7 +434,8 @@ print_mdoc_foot(struct termp *p, const void *arg) term_flushln(p); p->offset = p->rmargin; - p->rmargin = p->maxrmargin - term_strlen(p, meta->os); + sz = term_strlen(p, meta->os); + p->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0; p->flags |= TERMP_NOSPACE; term_word(p, meta->date); @@ -492,7 +497,7 @@ print_mdoc_head(struct termp *p, const void *arg) p->offset = 0; p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? (p->maxrmargin - vollen + term_len(p, 1)) / 2 : - p->maxrmargin - vollen; + vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; term_word(p, title); term_flushln(p); @@ -522,54 +527,18 @@ print_mdoc_head(struct termp *p, const void *arg) free(volume); } -static size_t -a2height(const struct termp *p, const char *v) -{ - struct roffsu su; - - - assert(v); - if ( ! a2roffsu(v, &su, SCALE_VS)) - SCALE_VS_INIT(&su, atoi(v)); - - return(term_vspan(p, &su)); -} - -static size_t +static int a2width(const struct termp *p, const char *v) { struct roffsu su; - assert(v); - if ( ! a2roffsu(v, &su, SCALE_MAX)) { + if (a2roffsu(v, &su, SCALE_MAX) < 2) { SCALE_HS_INIT(&su, term_strlen(p, v)); su.scale /= term_strlen(p, "0"); } - return(term_hspan(p, &su)); } -static size_t -a2offs(const struct termp *p, const char *v) -{ - struct roffsu su; - - if ('\0' == *v) - return(0); - else if (0 == strcmp(v, "left")) - return(0); - else if (0 == strcmp(v, "indent")) - return(term_len(p, p->defindent + 1)); - else if (0 == strcmp(v, "indent-two")) - return(term_len(p, (p->defindent + 1) * 2)); - else if ( ! a2roffsu(v, &su, SCALE_MAX)) { - SCALE_HS_INIT(&su, term_strlen(p, v)); - su.scale /= term_strlen(p, "0"); - } - - return(term_hspan(p, &su)); -} - /* * Determine how much space to print out before block elements of `It' * (and thus `Bl') and `Bd'. And then go ahead and print that space, @@ -593,16 +562,18 @@ print_bvspace(struct termp *p, /* Do not vspace directly after Ss/Sh. */ - for (nn = n; nn; nn = nn->parent) { - if (MDOC_BLOCK != nn->type) - continue; - if (MDOC_Ss == nn->tok) + nn = n; + while (nn->prev == NULL) { + do { + nn = nn->parent; + if (nn->type == MDOC_ROOT) + return; + } while (nn->type != MDOC_BLOCK); + if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss) return; - if (MDOC_Sh == nn->tok) - return; - if (NULL == nn->prev) - continue; - break; + if (nn->tok == MDOC_It && + nn->parent->parent->norm->Bl.type != LIST_item) + break; } /* A `-column' does not assert vspace within the list. */ @@ -635,10 +606,10 @@ termp_ll_pre(DECL_ARGS) static int termp_it_pre(DECL_ARGS) { - const struct mdoc_node *bl, *nn; char buf[24]; - int i; - size_t width, offset, ncols, dcol; + const struct mdoc_node *bl, *nn; + size_t ncols, dcol; + int i, offset, width; enum mdoc_list type; if (MDOC_BLOCK == n->type) { @@ -650,16 +621,47 @@ termp_it_pre(DECL_ARGS) type = bl->norm->Bl.type; /* + * Defaults for specific list types. + */ + + switch (type) { + case LIST_bullet: + /* FALLTHROUGH */ + case LIST_dash: + /* FALLTHROUGH */ + case LIST_hyphen: + /* FALLTHROUGH */ + case LIST_enum: + width = term_len(p, 2); + break; + case LIST_hang: + width = term_len(p, 8); + break; + case LIST_column: + /* FALLTHROUGH */ + 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. */ - width = offset = 0; + 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; + } - if (bl->norm->Bl.offs) - offset = a2offs(p, bl->norm->Bl.offs); - switch (type) { case LIST_column: if (MDOC_HEAD == n->type) @@ -713,43 +715,15 @@ termp_it_pre(DECL_ARGS) * 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); + if (width < 0 && (size_t)(-width) > p->offset) + width = -p->offset; + else if (width > SHRT_MAX) + width = 0; 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. */ @@ -791,16 +765,16 @@ termp_it_pre(DECL_ARGS) case LIST_enum: /* * Weird special case. - * Very narrow enum lists actually hang. + * Some very narrow 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 (width <= (int)term_len(p, 2)) + p->flags |= TERMP_HANG; if (MDOC_HEAD != n->type) break; p->flags |= TERMP_NOBREAK; @@ -889,14 +863,10 @@ termp_it_pre(DECL_ARGS) case LIST_hyphen: /* FALLTHROUGH */ case LIST_tag: - assert(width); if (MDOC_HEAD == n->type) p->rmargin = p->offset + width; - else { + else p->offset += width; - if (p->rmargin < p->offset) - p->rmargin = p->offset; - } break; case LIST_column: assert(width); @@ -1013,6 +983,7 @@ termp_it_post(DECL_ARGS) static int termp_nm_pre(DECL_ARGS) { + const char *cp; if (MDOC_BLOCK == n->type) { p->flags |= TERMP_PREKEEP; @@ -1023,14 +994,15 @@ termp_nm_pre(DECL_ARGS) if (NULL == n->child) return(0); p->flags |= TERMP_NOSPACE; - p->offset += term_len(p, 1) + - (NULL == n->prev->child ? - term_strlen(p, meta->name) : - MDOC_TEXT == n->prev->child->type ? - term_strlen(p, n->prev->child->string) : - term_len(p, 5)); - if (p->rmargin < p->offset) - p->rmargin = p->offset; + cp = NULL; + if (n->prev->child != NULL) + cp = n->prev->child->string; + if (cp == NULL) + cp = meta->name; + if (cp == NULL) + p->offset += term_len(p, 6); + else + p->offset += term_len(p, 1) + term_strlen(p, cp); return(1); } @@ -1243,14 +1215,8 @@ static int termp_nd_pre(DECL_ARGS) { - if (MDOC_BODY != n->type) - return(1); - -#if defined(__OpenBSD__) || defined(__linux__) - term_word(p, "\\(en"); -#else - term_word(p, "\\(em"); -#endif + if (n->type == MDOC_BODY) + term_word(p, "\\(en"); return(1); } @@ -1395,14 +1361,17 @@ static int termp_sh_pre(DECL_ARGS) { - /* No vspace between consecutive `Sh' calls. */ - switch (n->type) { case MDOC_BLOCK: - if (n->prev && MDOC_Sh == n->prev->tok) - if (NULL == n->prev->body->child) - break; - term_vspace(p); + /* + * Vertical space before sections, except + * when the previous section was empty. + */ + if (n->prev == NULL || + MDOC_Sh != n->prev->tok || + (n->prev->body != NULL && + n->prev->body->child != NULL)) + term_vspace(p); break; case MDOC_HEAD: term_fontpush(p, TERMFONT_BOLD); @@ -1573,6 +1542,7 @@ termp_bd_pre(DECL_ARGS) { size_t tabwidth, lm, len, rm, rmax; struct mdoc_node *nn; + int offset; if (MDOC_BLOCK == n->type) { print_bvspace(p, n, n); @@ -1580,9 +1550,23 @@ termp_bd_pre(DECL_ARGS) } else if (MDOC_HEAD == n->type) return(0); - if (n->norm->Bd.offs) - p->offset += a2offs(p, n->norm->Bd.offs); + /* 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 @@ -1642,7 +1626,8 @@ termp_bd_pre(DECL_ARGS) default: break; } - if (nn->next && nn->next->line == nn->line) + if (p->flags & TERMP_NONEWLINE || + (nn->next && ! (nn->next->flags & MDOC_LINE))) continue; term_flushln(p); p->flags |= TERMP_NOSPACE; @@ -1744,7 +1729,8 @@ static void termp_pf_post(DECL_ARGS) { - p->flags |= TERMP_NOSPACE; + if ( ! (n->next == NULL || n->next->flags & MDOC_LINE)) + p->flags |= TERMP_NOSPACE; } static int @@ -1824,11 +1810,17 @@ termp_in_post(DECL_ARGS) static int termp_sp_pre(DECL_ARGS) { + struct roffsu su; size_t i, len; switch (n->tok) { case MDOC_sp: - len = n->child ? a2height(p, n->child->string) : 1; + if (n->child) { + if ( ! a2roffsu(n->child->string, &su, SCALE_VS)) + su.scale = 1.0; + len = term_vspan(p, &su); + } else + len = 1; break; case MDOC_br: len = 0; @@ -1847,7 +1839,7 @@ termp_sp_pre(DECL_ARGS) } static int -termp_es_pre(DECL_ARGS) +termp_skip_pre(DECL_ARGS) { return(0); @@ -1864,7 +1856,8 @@ termp_quote_pre(DECL_ARGS) case MDOC_Ao: /* FALLTHROUGH */ case MDOC_Aq: - term_word(p, "<"); + term_word(p, n->nchild == 1 && + n->child->tok == MDOC_Mt ? "<" : "\\(la"); break; case MDOC_Bro: /* FALLTHROUGH */ @@ -1925,17 +1918,19 @@ static void termp_quote_post(DECL_ARGS) { - if (MDOC_BODY != n->type && MDOC_ELEM != n->type) + if (n->type != MDOC_BODY && n->type != MDOC_ELEM) return; - if (MDOC_En != n->tok) + if ( ! (n->tok == MDOC_En || + (n->tok == MDOC_Eo && n->end == ENDBODY_SPACE))) p->flags |= TERMP_NOSPACE; switch (n->tok) { case MDOC_Ao: /* FALLTHROUGH */ case MDOC_Aq: - term_word(p, ">"); + term_word(p, n->nchild == 1 && + n->child->tok == MDOC_Mt ? ">" : "\\(ra"); break; case MDOC_Bro: /* FALLTHROUGH */