=================================================================== RCS file: /cvs/mandoc/man_term.c,v retrieving revision 1.93 retrieving revision 1.116 diff -u -p -r1.93 -r1.116 --- mandoc/man_term.c 2011/01/03 15:30:25 1.93 +++ mandoc/man_term.c 2011/09/18 21:08:34 1.116 @@ -1,6 +1,7 @@ -/* $Id: man_term.c,v 1.93 2011/01/03 15:30:25 kristaps Exp $ */ +/* $Id: man_term.c,v 1.116 2011/09/18 21:08:34 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2010, 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -30,32 +31,21 @@ #include "out.h" #include "man.h" #include "term.h" -#include "chars.h" #include "main.h" -#define INDENT 7 -#define HALFINDENT 3 +#define INDENT 7 /* fixed-width char full-indent */ +#define HALFINDENT 3 /* fixed-width char half-indent */ +#define MAXMARGINS 64 /* maximum number of indented scopes */ /* FIXME: have PD set the default vspace width. */ struct mtermp { int fl; #define MANT_LITERAL (1 << 0) - /* - * Default amount to indent the left margin after leading text - * has been printed (e.g., `HP' left-indent, `TP' and `IP' body - * indent). This needs to be saved because `HP' and so on, if - * not having a specified value, must default. - * - * Note that this is the indentation AFTER the left offset, so - * the total offset is usually offset + lmargin. - */ - size_t lmargin; - /* - * The default offset, i.e., the amount between any text and the - * page boundary. - */ - size_t offset; + size_t lmargin[MAXMARGINS]; /* margins (incl. visible page) */ + int lmargincur; /* index of current margin */ + int lmarginsz; /* actual number of nested margins */ + size_t offset; /* default offset to visible page */ }; #define DECL_ARGS struct termp *p, \ @@ -125,7 +115,7 @@ static const struct termact termacts[MAN_MAX] = { { pre_I, NULL, 0 }, /* I */ { pre_alternate, NULL, 0 }, /* IR */ { pre_alternate, NULL, 0 }, /* RI */ - { NULL, NULL, MAN_NOTEXT }, /* na */ + { pre_ign, NULL, MAN_NOTEXT }, /* na */ { pre_sp, NULL, MAN_NOTEXT }, /* sp */ { pre_literal, NULL, 0 }, /* nf */ { pre_literal, NULL, 0 }, /* fi */ @@ -156,14 +146,7 @@ terminal_man(void *arg, const struct man *man) p->tabwidth = term_len(p, 5); if (NULL == p->symtab) - switch (p->enc) { - case (TERMENC_ASCII): - p->symtab = chars_init(CHARS_ASCII); - break; - default: - abort(); - /* NOTREACHED */ - } + p->symtab = mchars_alloc(); n = man_node(man); m = man_meta(man); @@ -171,8 +154,9 @@ terminal_man(void *arg, const struct man *man) term_begin(p, print_man_head, print_man_foot, m); p->flags |= TERMP_NOSPACE; - mt.fl = 0; - mt.lmargin = term_len(p, INDENT); + memset(&mt, 0, sizeof(struct mtermp)); + + mt.lmargin[mt.lmargincur] = term_len(p, INDENT); mt.offset = term_len(p, INDENT); if (n->child) @@ -188,7 +172,7 @@ a2height(const struct termp *p, const char *cp) struct roffsu su; if ( ! a2roffsu(cp, &su, SCALE_VS)) - SCALE_VS_INIT(&su, term_strlen(p, cp)); + SCALE_VS_INIT(&su, atoi(cp)); return(term_vspan(p, &su)); } @@ -205,24 +189,31 @@ a2width(const struct termp *p, const char *cp) return((int)term_hspan(p, &su)); } - +/* + * Printing leading vertical space before a block. + * This is used for the paragraph macros. + * The rules are pretty simple, since there's very little nesting going + * on here. Basically, if we're the first within another block (SS/SH), + * then don't emit vertical space. If we are (RS), then do. If not the + * first, print it. + */ static void print_bvspace(struct termp *p, const struct man_node *n) { + term_newln(p); - if (NULL == n->prev) - return; + if (n->body && n->body->child) + if (MAN_TBL == n->body->child->type) + return; - if (MAN_SS == n->prev->tok) - return; - if (MAN_SH == n->prev->tok) - return; + if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok) + if (NULL == n->prev) + return; term_vspace(p); } - /* ARGSUSED */ static int pre_ign(DECL_ARGS) @@ -254,7 +245,7 @@ pre_literal(DECL_ARGS) else mt->fl &= ~MANT_LITERAL; - return(1); + return(0); } /* ARGSUSED */ @@ -396,6 +387,11 @@ pre_in(DECL_ARGS) else p->offset = v; + /* Don't let this creep beyond the right margin. */ + + if (p->offset > p->rmargin) + p->offset = p->rmargin; + return(0); } @@ -406,6 +402,13 @@ pre_sp(DECL_ARGS) { size_t i, len; + if ((NULL == n->prev && n->parent)) { + if (MAN_SS == n->parent->tok) + return(0); + if (MAN_SH == n->parent->tok) + return(0); + } + switch (n->tok) { case (MAN_br): len = 0; @@ -444,7 +447,7 @@ pre_HP(DECL_ARGS) return(0); } - len = mt->lmargin; + len = mt->lmargin[mt->lmargincur]; ival = -1; /* Calculate offset. */ @@ -460,7 +463,7 @@ pre_HP(DECL_ARGS) p->rmargin = mt->offset + len; if (ival >= 0) - mt->lmargin = (size_t)ival; + mt->lmargin[mt->lmargincur] = (size_t)ival; return(1); } @@ -495,7 +498,7 @@ pre_PP(DECL_ARGS) switch (n->type) { case (MAN_BLOCK): - mt->lmargin = term_len(p, INDENT); + mt->lmargin[mt->lmargincur] = term_len(p, INDENT); print_bvspace(p, n); break; default: @@ -513,7 +516,7 @@ pre_IP(DECL_ARGS) { const struct man_node *nn; size_t len; - int ival; + int savelit, ival; switch (n->type) { case (MAN_BODY): @@ -530,18 +533,14 @@ pre_IP(DECL_ARGS) return(1); } - len = mt->lmargin; + len = mt->lmargin[mt->lmargincur]; ival = -1; - /* Calculate offset. */ - + /* Calculate the offset from the optional second argument. */ if (NULL != (nn = n->parent->head->child)) - if (NULL != (nn = nn->next)) { - for ( ; nn->next; nn = nn->next) - /* Do nothing. */ ; + if (NULL != (nn = nn->next)) if ((ival = a2width(p, nn->string)) >= 0) len = (size_t)ival; - } switch (n->type) { case (MAN_HEAD): @@ -555,11 +554,17 @@ pre_IP(DECL_ARGS) break; /* Set the saved left-margin. */ - mt->lmargin = (size_t)ival; + mt->lmargin[mt->lmargincur] = (size_t)ival; - /* Don't print the length value. */ - for (nn = n->child; nn->next; nn = nn->next) - print_man_node(p, mt, nn, m); + 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; @@ -585,7 +590,7 @@ post_IP(DECL_ARGS) p->rmargin = p->maxrmargin; break; case (MAN_BODY): - term_flushln(p); + term_newln(p); p->flags &= ~TERMP_NOLPAD; break; default: @@ -600,12 +605,11 @@ pre_TP(DECL_ARGS) { const struct man_node *nn; size_t len; - int ival; + int savelit, ival; switch (n->type) { case (MAN_HEAD): p->flags |= TERMP_NOBREAK; - p->flags |= TERMP_TWOSPACE; break; case (MAN_BODY): p->flags |= TERMP_NOLPAD; @@ -618,18 +622,15 @@ pre_TP(DECL_ARGS) return(1); } - len = (size_t)mt->lmargin; + len = (size_t)mt->lmargin[mt->lmargincur]; ival = -1; /* Calculate offset. */ - if (NULL != (nn = n->parent->head->child)) { - while (nn && MAN_TEXT != nn->type) - nn = nn->next; - if (nn && nn->next) + if (NULL != (nn = n->parent->head->child)) + if (nn->parent->line == nn->line) if ((ival = a2width(p, nn->string)) >= 0) len = (size_t)ival; - } switch (n->type) { case (MAN_HEAD): @@ -640,13 +641,18 @@ pre_TP(DECL_ARGS) 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) + 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 = (size_t)ival; + mt->lmargin[mt->lmargincur] = (size_t)ival; return(0); case (MAN_BODY): @@ -674,7 +680,7 @@ post_TP(DECL_ARGS) p->rmargin = p->maxrmargin; break; case (MAN_BODY): - term_flushln(p); + term_newln(p); p->flags &= ~TERMP_NOLPAD; break; default: @@ -690,7 +696,8 @@ pre_SS(DECL_ARGS) switch (n->type) { case (MAN_BLOCK): - mt->lmargin = term_len(p, INDENT); + mt->fl &= ~MANT_LITERAL; + mt->lmargin[mt->lmargincur] = term_len(p, INDENT); mt->offset = term_len(p, INDENT); /* If following a prior empty `SS', no vspace. */ if (n->prev && MAN_SS == n->prev->tok) @@ -740,7 +747,8 @@ pre_SH(DECL_ARGS) switch (n->type) { case (MAN_BLOCK): - mt->lmargin = term_len(p, INDENT); + mt->fl &= ~MANT_LITERAL; + mt->lmargin[mt->lmargincur] = term_len(p, INDENT); mt->offset = term_len(p, INDENT); /* If following a prior empty `SH', no vspace. */ if (n->prev && MAN_SH == n->prev->tok) @@ -783,13 +791,12 @@ post_SH(DECL_ARGS) } } - /* ARGSUSED */ static int pre_RS(DECL_ARGS) { - const struct man_node *nn; - int ival; + int ival; + size_t sz; switch (n->type) { case (MAN_BLOCK): @@ -801,98 +808,126 @@ pre_RS(DECL_ARGS) break; } - if (NULL == (nn = n->parent->head->child)) { - mt->offset = mt->lmargin + term_len(p, INDENT); - p->offset = mt->offset; - return(1); - } + sz = term_len(p, INDENT); - if ((ival = a2width(p, nn->string)) < 0) - return(1); + if (NULL != (n = n->parent->head->child)) + if ((ival = a2width(p, n->string)) >= 0) + sz = (size_t)ival; - mt->offset = term_len(p, INDENT) + (size_t)ival; + mt->offset += sz; p->offset = mt->offset; + if (++mt->lmarginsz < MAXMARGINS) + mt->lmargincur = mt->lmarginsz; + + mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1]; return(1); } - /* ARGSUSED */ static void post_RS(DECL_ARGS) { + int ival; + size_t sz; switch (n->type) { case (MAN_BLOCK): - mt->offset = mt->lmargin = term_len(p, INDENT); - break; + return; case (MAN_HEAD): - break; + return; default: term_newln(p); - p->offset = term_len(p, INDENT); break; } -} + sz = term_len(p, INDENT); + if (NULL != (n = n->parent->head->child)) + if ((ival = a2width(p, n->string)) >= 0) + sz = (size_t)ival; + + mt->offset = mt->offset < sz ? 0 : mt->offset - sz; + p->offset = mt->offset; + + if (--mt->lmarginsz < MAXMARGINS) + mt->lmargincur = mt->lmarginsz; +} + static void print_man_node(DECL_ARGS) { size_t rm, rmax; int c; - c = 1; - switch (n->type) { case(MAN_TEXT): - if (0 == *n->string) { + /* + * If we have a blank line, output a vertical space. + * If we have a space as the first character, break + * before printing the line's data. + */ + if ('\0' == *n->string) { term_vspace(p); - break; - } + return; + } else if (' ' == *n->string && MAN_LINE & n->flags) + term_newln(p); term_word(p, n->string); - /* FIXME: this means that macro lines are munged! */ - - if (MANT_LITERAL & mt->fl) { + /* + * If we're in a literal context, make sure that words + * togehter on the same line stay together. This is a + * POST-printing call, so we check the NEXT word. Since + * -man doesn't have nested macros, we don't need to be + * more specific than this. + */ + if (MANT_LITERAL & mt->fl && + (NULL == n->next || + n->next->line > n->line)) { rm = p->rmargin; rmax = p->maxrmargin; p->rmargin = p->maxrmargin = TERM_MAXMARGIN; p->flags |= TERMP_NOSPACE; term_flushln(p); + p->flags &= ~TERMP_NOLPAD; p->rmargin = rm; p->maxrmargin = rmax; } - break; + + if (MAN_EOS & n->flags) + p->flags |= TERMP_SENTENCE; + return; + case (MAN_EQN): + term_eqn(p, n->eqn); + return; case (MAN_TBL): + /* + * Tables are preceded by a newline. Then process a + * table line, which will cause line termination, + */ if (TBL_SPAN_FIRST & n->span->flags) term_newln(p); term_tbl(p, n->span); - break; + return; default: - if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) - term_fontrepl(p, TERMFONT_NONE); - if (termacts[n->tok].pre) - c = (*termacts[n->tok].pre)(p, mt, n, m); break; } + if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) + term_fontrepl(p, TERMFONT_NONE); + + c = 1; + if (termacts[n->tok].pre) + c = (*termacts[n->tok].pre)(p, mt, n, m); + if (c && n->child) print_man_nodelist(p, mt, n->child, m); - switch (n->type) { - case (MAN_TEXT): - /* FALLTHROUGH */ - case (MAN_TBL): - break; - default: - if (termacts[n->tok].post) - (*termacts[n->tok].post)(p, mt, n, m); - if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) - term_fontrepl(p, TERMFONT_NONE); - break; - } + if (termacts[n->tok].post) + (*termacts[n->tok].post)(p, mt, n, m); + if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) + term_fontrepl(p, TERMFONT_NONE); if (MAN_EOS & n->flags) p->flags |= TERMP_SENTENCE; @@ -913,24 +948,18 @@ print_man_nodelist(DECL_ARGS) static void print_man_foot(struct termp *p, const void *arg) { - char buf[DATESIZ]; const struct man_meta *meta; meta = (const struct man_meta *)arg; term_fontrepl(p, TERMFONT_NONE); - if (meta->rawdate) - strlcpy(buf, meta->rawdate, DATESIZ); - else - time2a(meta->date, buf, DATESIZ); - term_vspace(p); term_vspace(p); term_vspace(p); p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; - p->rmargin = p->maxrmargin - term_strlen(p, buf); + p->rmargin = p->maxrmargin - term_strlen(p, meta->date); p->offset = 0; /* term_strlen() can return zero. */ @@ -948,7 +977,7 @@ print_man_foot(struct termp *p, const void *arg) p->rmargin = p->maxrmargin; p->flags &= ~TERMP_NOBREAK; - term_word(p, buf); + term_word(p, meta->date); term_flushln(p); }