=================================================================== RCS file: /cvs/mandoc/mdoc_term.c,v retrieving revision 1.106 retrieving revision 1.113 diff -u -p -r1.106 -r1.113 --- mandoc/mdoc_term.c 2010/01/01 14:32:52 1.106 +++ mandoc/mdoc_term.c 2010/04/03 14:25:12 1.113 @@ -1,4 +1,4 @@ -/* $Id: mdoc_term.c,v 1.106 2010/01/01 14:32:52 kristaps Exp $ */ +/* $Id: mdoc_term.c,v 1.113 2010/04/03 14:25:12 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -14,6 +14,10 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include @@ -33,7 +37,6 @@ struct termpair { struct termpair *ppair; - int flag; int count; }; @@ -64,11 +67,6 @@ static void print_mdoc_head(DECL_ARGS); static void print_mdoc_nodelist(DECL_ARGS); static void print_foot(DECL_ARGS); -#ifdef __linux__ -extern size_t strlcpy(char *, const char *, size_t); -extern size_t strlcat(char *, const char *, size_t); -#endif - static void termp____post(DECL_ARGS); static void termp_an_post(DECL_ARGS); static void termp_aq_post(DECL_ARGS); @@ -134,6 +132,7 @@ static int termp_sq_pre(DECL_ARGS); static int termp_ss_pre(DECL_ARGS); static int termp_under_pre(DECL_ARGS); static int termp_ud_pre(DECL_ARGS); +static int termp_vt_pre(DECL_ARGS); static int termp_xr_pre(DECL_ARGS); static int termp_xx_pre(DECL_ARGS); @@ -177,7 +176,7 @@ static const struct termact termacts[MDOC_MAX] = { { termp_rv_pre, NULL }, /* Rv */ { NULL, NULL }, /* St */ { termp_under_pre, NULL }, /* Va */ - { termp_under_pre, termp_vt_post }, /* Vt */ + { termp_vt_pre, termp_vt_post }, /* Vt */ { termp_xr_pre, NULL }, /* Xr */ { NULL, termp____post }, /* %A */ { termp_under_pre, termp____post }, /* %B */ @@ -204,7 +203,7 @@ static const struct termact termacts[MDOC_MAX] = { { NULL, NULL }, /* Dc */ { termp_dq_pre, termp_dq_post }, /* Do */ { termp_dq_pre, termp_dq_post }, /* Dq */ - { NULL, NULL }, /* Ec */ + { NULL, NULL }, /* Ec */ /* FIXME: no space */ { NULL, NULL }, /* Ef */ { termp_under_pre, NULL }, /* Em */ { NULL, NULL }, /* Eo */ @@ -271,6 +270,9 @@ terminal_mdoc(void *arg, const struct mdoc *mdoc) p = (struct termp *)arg; + p->overstep = 0; + p->maxrmargin = 78; + if (NULL == p->symtab) switch (p->enc) { case (TERMENC_ASCII): @@ -471,12 +473,7 @@ a2width(const struct mdoc_argv *arg, int pos) if ( ! a2roffsu(arg->value[pos], &su, SCALE_MAX)) SCALE_HS_INIT(&su, strlen(arg->value[pos])); - /* - * This is a bit if a magic number on groff's part. Be careful - * in changing it, as the MDOC_Column handler will subtract one - * from this for >5 columns (don't go below zero!). - */ - return(term_hspan(&su) + 2); + return(term_hspan(&su)); } @@ -541,6 +538,10 @@ a2offs(const struct mdoc_argv *arg) } +/* + * Return 1 if an argument has a particular argument value or 0 if it + * does not. See arg_getattr(). + */ static int arg_hasattr(int arg, const struct mdoc_node *n) { @@ -549,6 +550,10 @@ arg_hasattr(int arg, const struct mdoc_node *n) } +/* + * Get the index of an argument in a node's argument list or -1 if it + * does not exist. See arg_getattrs(). + */ static int arg_getattr(int v, const struct mdoc_node *n) { @@ -558,6 +563,12 @@ arg_getattr(int v, const struct mdoc_node *n) } +/* + * Walk through the argument list for a node and fill an array "vals" + * with the positions of the argument structures listed in "keys". + * Return the number of elements that were written into "vals", which + * can be zero. + */ static int arg_getattrs(const int *keys, int *vals, size_t sz, const struct mdoc_node *n) @@ -577,6 +588,11 @@ arg_getattrs(const int *keys, int *vals, } +/* + * 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, + * too. + */ static void print_bvspace(struct termp *p, const struct mdoc_node *bl, @@ -655,8 +671,7 @@ termp_it_pre(DECL_ARGS) const struct mdoc_node *bl, *nn; char buf[7]; int i, type, keys[3], vals[3]; - size_t width, offset, ncols; - int dcol; + size_t width, offset, ncols, dcol; if (MDOC_BLOCK == n->type) { print_bvspace(p, n->parent->parent, n); @@ -665,67 +680,79 @@ termp_it_pre(DECL_ARGS) bl = n->parent->parent->parent; - /* Save parent attributes. */ + /* Get list width, offset, and list type from argument list. */ - pair->flag = p->flags; - - /* Get list width and offset. */ - keys[0] = MDOC_Width; keys[1] = MDOC_Offset; keys[2] = MDOC_Column; vals[0] = vals[1] = vals[2] = -1; - width = offset = 0; + arg_getattrs(keys, vals, 3, bl); - (void)arg_getattrs(keys, vals, 3, bl); - type = arg_listtype(bl); assert(-1 != 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 (vals[1] >= 0) offset = a2offs(&bl->args->argv[vals[1]]); - /* Calculate real width and offset. */ - switch (type) { case (MDOC_Column): if (MDOC_BODY == n->type) break; - /* - * Imitate groff's column handling. - * For each earlier column, add its width. - * For less than 5 columns, add two more blanks per column. - * For exactly 5 columns, add only one more blank per column. - * For more than 5 columns, SUBTRACT one column. We can - * do this because a2width() pads exactly 2 spaces. + * 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->args->argv[vals[2]].sz; - dcol = ncols < 5 ? 2 : ncols == 5 ? 1 : -1; - for (i=0, nn=n->prev; nn && i < (int)ncols; nn=nn->prev, i++) - offset += a2width(&bl->args->argv[vals[2]], i) + - (size_t)dcol; + /* LINTED */ + dcol = ncols < 5 ? 4 : ncols == 5 ? 3 : 1; + for (i = 0, nn = n->prev; + nn && i < (int)ncols; + nn = nn->prev, i++) + offset += dcol + a2width + (&bl->args->argv[vals[2]], i); + + /* - * Use the declared column widths, - * extended as explained in the preceding paragraph. + * 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) - width = a2width(&bl->args->argv[vals[2]], i) + - (size_t)dcol; + if (i >= (int)ncols) + break; /* - * 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. + * Use the declared column widths, extended as explained + * in the preceding paragraph. */ + width = a2width(&bl->args->argv[vals[2]], i) + dcol; break; default: - if (vals[0] >= 0) - width = a2width(&bl->args->argv[vals[0]], 0); + if (vals[0] < 0) + 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(&bl->args->argv[vals[0]], 0) + 2; break; } @@ -794,11 +821,10 @@ termp_it_pre(DECL_ARGS) } /* - * Pad and break control. This is the tricker part. Lists with - * set right-margins for the head get TERMP_NOBREAK because, if - * they overrun the margin, they wrap to the new margin. - * Correspondingly, the body for these types don't left-pad, as - * the head will pad out to to the right. + * 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) { @@ -939,7 +965,7 @@ termp_it_pre(DECL_ARGS) break; case (MDOC_Enum): (pair->ppair->ppair->count)++; - (void)snprintf(buf, sizeof(buf), "%d.", + snprintf(buf, sizeof(buf), "%d.", pair->ppair->ppair->count); term_word(p, buf); break; @@ -982,7 +1008,7 @@ termp_it_post(DECL_ARGS) { int type; - if (MDOC_BODY != n->type && MDOC_HEAD != n->type) + if (MDOC_BLOCK == n->type) return; type = arg_listtype(n->parent->parent->parent); @@ -1006,7 +1032,17 @@ termp_it_post(DECL_ARGS) break; } - p->flags = pair->flag; + /* + * Now that our output is flushed, we can reset our tags. Since + * only `It' sets these flags, we're free to assume that nobody + * has munged them in the meanwhile. + */ + + p->flags &= ~TERMP_DANGLE; + p->flags &= ~TERMP_NOBREAK; + p->flags &= ~TERMP_TWOSPACE; + p->flags &= ~TERMP_NOLPAD; + p->flags &= ~TERMP_HANG; } @@ -1241,7 +1277,10 @@ termp_xr_pre(DECL_ARGS) { const struct mdoc_node *nn; - assert(n->child && MDOC_TEXT == n->child->type); + if (NULL == n->child) + return(0); + + assert(MDOC_TEXT == n->child->type); nn = n->child; term_word(p, nn->string); @@ -1258,12 +1297,27 @@ termp_xr_pre(DECL_ARGS) } +static int +termp_vt_pre(DECL_ARGS) +{ + + if (MDOC_ELEM == n->type) + return(termp_under_pre(p, pair, m, n)); + else if (MDOC_HEAD == n->type) + return(0); + else if (MDOC_BLOCK == n->type) + return(1); + + return(termp_under_pre(p, pair, m, n)); +} + + /* ARGSUSED */ static void termp_vt_post(DECL_ARGS) { - if (n->sec != SEC_SYNOPSIS) + if (MDOC_BLOCK != n->type) return; if (n->next && MDOC_Vt == n->next->tok) term_newln(p); @@ -1987,10 +2041,9 @@ termp_sm_pre(DECL_ARGS) { assert(n->child && MDOC_TEXT == n->child->type); - if (0 == strcmp("on", n->child->string)) { + if (0 == strcmp("on", n->child->string)) p->flags &= ~TERMP_NONOSPACE; - p->flags &= ~TERMP_NOSPACE; - } else + else p->flags |= TERMP_NONOSPACE; return(0);