From: schwarze Date: Mon, 12 Jun 2017 18:55:42 +0000 (+0000) Subject: Implement automatic line breaking X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=8afa4451fa15634d3948616c45baf55641fd7d10;p=openbsd Implement automatic line breaking inside individual table cells that contain text blocks. This cures overlong lines in various Xenocara manuals. --- diff --git a/regress/usr.bin/mandoc/char/unicode/input.out_ascii b/regress/usr.bin/mandoc/char/unicode/input.out_ascii index 7711574c61d..410bdc85830 100644 --- a/regress/usr.bin/mandoc/char/unicode/input.out_ascii +++ b/regress/usr.bin/mandoc/char/unicode/input.out_ascii @@ -22,7 +22,7 @@ DDEESSCCRRIIPPTTIIOONN U+007f 0xc1bf ?? highest obfuscated ASCII 0xc278 ?x ASCII continuation U+0080 0xc280 <80><80> lowest two-byte - 0xc2c380 ?`A high continuation + 0xc2c380 ?`A high continuation U+07FF 0xdfbf highest two-byte TThhrreeee--bbyyttee rraannggee diff --git a/usr.bin/mandoc/mandoc_aux.c b/usr.bin/mandoc/mandoc_aux.c index 0536595bd72..6fa396a7909 100644 --- a/usr.bin/mandoc/mandoc_aux.c +++ b/usr.bin/mandoc/mandoc_aux.c @@ -1,7 +1,7 @@ -/* $OpenBSD: mandoc_aux.c,v 1.7 2015/10/12 21:09:08 schwarze Exp $ */ +/* $OpenBSD: mandoc_aux.c,v 1.8 2017/06/12 18:55:42 schwarze Exp $ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons - * Copyright (c) 2014 Ingo Schwarze + * Copyright (c) 2014, 2015, 2017 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 @@ -66,7 +66,6 @@ mandoc_malloc(size_t size) void * mandoc_realloc(void *ptr, size_t size) { - ptr = realloc(ptr, size); if (ptr == NULL) err((int)MANDOCLEVEL_SYSERR, NULL); @@ -76,13 +75,21 @@ mandoc_realloc(void *ptr, size_t size) void * mandoc_reallocarray(void *ptr, size_t num, size_t size) { - ptr = reallocarray(ptr, num, size); if (ptr == NULL) err((int)MANDOCLEVEL_SYSERR, NULL); return ptr; } +void * +mandoc_recallocarray(void *ptr, size_t oldnum, size_t num, size_t size) +{ + ptr = recallocarray(ptr, oldnum, num, size); + if (ptr == NULL) + err((int)MANDOCLEVEL_SYSERR, NULL); + return ptr; +} + char * mandoc_strdup(const char *ptr) { diff --git a/usr.bin/mandoc/mandoc_aux.h b/usr.bin/mandoc/mandoc_aux.h index 05a85f3e6fc..f535d85cf69 100644 --- a/usr.bin/mandoc/mandoc_aux.h +++ b/usr.bin/mandoc/mandoc_aux.h @@ -1,7 +1,7 @@ -/* $OpenBSD: mandoc_aux.h,v 1.8 2017/02/09 17:19:07 schwarze Exp $ */ +/* $OpenBSD: mandoc_aux.h,v 1.9 2017/06/12 18:55:42 schwarze Exp $ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons - * Copyright (c) 2014 Ingo Schwarze + * Copyright (c) 2014, 2017 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 @@ -22,5 +22,6 @@ void *mandoc_calloc(size_t, size_t); void *mandoc_malloc(size_t); void *mandoc_realloc(void *, size_t); void *mandoc_reallocarray(void *, size_t, size_t); +void *mandoc_recallocarray(void *, size_t, size_t, size_t); char *mandoc_strdup(const char *); char *mandoc_strndup(const char *, size_t); diff --git a/usr.bin/mandoc/tbl_term.c b/usr.bin/mandoc/tbl_term.c index 1bb94b77209..fdd0e4732b0 100644 --- a/usr.bin/mandoc/tbl_term.c +++ b/usr.bin/mandoc/tbl_term.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tbl_term.c,v 1.34 2017/06/08 18:11:15 schwarze Exp $ */ +/* $OpenBSD: tbl_term.c,v 1.35 2017/06/12 18:55:42 schwarze Exp $ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons * Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze @@ -66,12 +66,13 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) const struct tbl_cell *cp; const struct tbl_dat *dp; static size_t offset; - size_t tsz; - int ic, horiz, spans, vert; + size_t coloff, tsz; + int ic, horiz, spans, vert, more; + char fc; /* Inhibit printing of spaces: we do padding ourselves. */ - tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE | TERMP_BRNEVER; + tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE; /* * The first time we're invoked for a given table block, @@ -109,82 +110,181 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tbl_hrule(tp, sp, 1); } - /* Vertical frame at the start of each row. */ + /* Set up the columns. */ - horiz = sp->pos == TBL_SPAN_HORIZ || sp->pos == TBL_SPAN_DHORIZ; + tp->flags |= TERMP_MULTICOL; + horiz = 0; + switch (sp->pos) { + case TBL_SPAN_HORIZ: + case TBL_SPAN_DHORIZ: + horiz = 1; + term_setcol(tp, 1); + break; + case TBL_SPAN_DATA: + term_setcol(tp, sp->opts->cols + 2); + coloff = tp->tcol->offset; - if (sp->layout->vert || - (sp->prev != NULL && sp->prev->layout->vert) || - sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)) - term_word(tp, horiz ? "+" : "|"); - else if (sp->opts->lvert) - tbl_char(tp, horiz ? '-' : ASCII_NBRSP, 1); + /* Set up a column for a left vertical frame. */ - /* - * Now print the actual data itself depending on the span type. - * Match data cells to column numbers. - */ + if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) || + sp->opts->lvert) + coloff++; + tp->tcol->rmargin = coloff; + + /* Set up the data columns. */ - if (sp->pos == TBL_SPAN_DATA) { - cp = sp->layout->first; dp = sp->first; spans = 0; for (ic = 0; ic < sp->opts->cols; ic++) { + if (spans == 0) { + tp->tcol++; + tp->tcol->offset = coloff; + } + coloff += tp->tbl.cols[ic].width; + tp->tcol->rmargin = coloff; + coloff++; + if (ic + 1 < sp->opts->cols) + coloff += 2; + if (spans) { + spans--; + continue; + } + if (dp == NULL) + continue; + spans = dp->spans; + dp = dp->next; + } - /* - * Remeber whether we need a vertical bar - * after this cell. - */ + /* Set up a column for a right vertical frame. */ - vert = cp == NULL ? 0 : cp->vert; + tp->tcol++; + tp->tcol->offset = coloff; + if (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) || + sp->opts->rvert) + coloff++; + tp->tcol->rmargin = coloff; - /* - * Print the data and advance to the next cell. - */ + /* Spans may have reduced the number of columns. */ - if (spans == 0) { - tbl_data(tp, sp->opts, dp, tp->tbl.cols + ic); - if (dp != NULL) { - spans = dp->spans; - dp = dp->next; - } - } else - spans--; - if (cp != NULL) - cp = cp->next; + tp->lasttcol = tp->tcol - tp->tcols; - /* - * Separate columns, except in the middle - * of spans and after the last cell. - */ + /* Fill the buffers for all data columns. */ - if (ic + 1 == sp->opts->cols || spans) + tp->tcol = tp->tcols; + dp = sp->first; + spans = 0; + for (ic = 0; ic < sp->opts->cols; ic++) { + if (spans) { + spans--; + continue; + } + tp->tcol++; + tp->col = 0; + tbl_data(tp, sp->opts, dp, tp->tbl.cols + ic); + if (dp == NULL) continue; + spans = dp->spans; + dp = dp->next; + } + break; + } - tbl_char(tp, ASCII_NBRSP, 1); - if (vert > 0) - tbl_char(tp, '|', vert); - if (vert < 2) - tbl_char(tp, ASCII_NBRSP, 2 - vert); + do { + /* Print the vertical frame at the start of each row. */ + + tp->tcol = tp->tcols; + fc = '\0'; + if (sp->layout->vert || + (sp->prev != NULL && sp->prev->layout->vert) || + sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)) + fc = horiz ? '+' : '|'; + else if (horiz && sp->opts->lvert) + fc = '-'; + if (fc != '\0') { + (*tp->advance)(tp, tp->tcols->offset); + (*tp->letter)(tp, fc); + tp->viscol = tp->tcol->offset + 1; } - } else if (horiz) - tbl_hrule(tp, sp, 0); - /* Vertical frame at the end of each row. */ + /* Print the data cells. */ + + more = 0; + if (horiz) { + tbl_hrule(tp, sp, 0); + term_flushln(tp); + } else { + cp = sp->layout->first; + dp = sp->first; + spans = 0; + for (ic = 0; ic < sp->opts->cols; ic++) { + if (spans == 0) { + tp->tcol++; + if (dp != NULL) { + spans = dp->spans; + dp = dp->next; + } + if (tp->tcol->col < tp->tcol->lastcol) + term_flushln(tp); + if (tp->tcol->col < tp->tcol->lastcol) + more = 1; + if (tp->tcol + 1 == + tp->tcols + tp->lasttcol) + continue; + } else + spans--; + + /* Vertical frames between data cells. */ + + if (cp != NULL) { + vert = cp->vert; + cp = cp->next; + } else + vert = 0; + if (vert == 0) + continue; + + if (tp->tcol->rmargin + 1 > tp->viscol) { + (*tp->advance)(tp, tp->tcol->rmargin + + 1 - tp->viscol); + tp->viscol = tp->tcol->rmargin + 1; + } + while (vert--) { + (*tp->letter)(tp, '|'); + tp->viscol++; + } + } + } - if (sp->layout->last->vert || - (sp->prev != NULL && sp->prev->layout->last->vert) || - (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))) - term_word(tp, horiz ? "+" : " |"); - else if (sp->opts->rvert) - tbl_char(tp, horiz ? '-' : ASCII_NBRSP, 1); - term_flushln(tp); + /* Print the vertical frame at the end of each row. */ + + fc = '\0'; + if (sp->layout->last->vert || + (sp->prev != NULL && sp->prev->layout->last->vert) || + (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))) + fc = horiz ? '+' : '|'; + else if (horiz && sp->opts->rvert) + fc = '-'; + if (fc != '\0') { + if (horiz == 0) { + tp->tcol++; + (*tp->advance)(tp, + tp->tcol->offset > tp->viscol ? + tp->tcol->offset - tp->viscol : 1); + } + (*tp->letter)(tp, fc); + } + (*tp->endline)(tp); + tp->viscol = 0; + } while (more); /* * If we're the last row, clean up after ourselves: clear the * existing table configuration and set it to NULL. */ + term_setcol(tp, 1); + tp->flags &= ~TERMP_MULTICOL; + tp->tcol->rmargin = tp->maxrmargin; if (sp->next == NULL) { if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) { tbl_hrule(tp, sp, 1); @@ -199,7 +299,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tp->tbl.cols = NULL; tp->tcol->offset = offset; } - tp->flags &= ~(TERMP_NONOSPACE | TERMP_BRNEVER); + tp->flags &= ~TERMP_NONOSPACE; } /* diff --git a/usr.bin/mandoc/term.c b/usr.bin/mandoc/term.c index 9aa69c7befe..07b7f57a2e5 100644 --- a/usr.bin/mandoc/term.c +++ b/usr.bin/mandoc/term.c @@ -1,4 +1,4 @@ -/* $OpenBSD: term.c,v 1.128 2017/06/08 12:54:40 schwarze Exp $ */ +/* $OpenBSD: term.c,v 1.129 2017/06/12 18:55:42 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010-2017 Ingo Schwarze @@ -37,6 +37,18 @@ static void encode1(struct termp *, int); static void endline(struct termp *); +void +term_setcol(struct termp *p, size_t maxtcol) +{ + if (maxtcol > p->maxtcol) { + p->tcols = mandoc_recallocarray(p->tcols, + p->maxtcol, maxtcol, sizeof(*p->tcols)); + p->maxtcol = maxtcol; + } + p->lasttcol = maxtcol - 1; + p->tcol = p->tcols; +} + void term_free(struct termp *p) { @@ -114,9 +126,9 @@ term_flushln(struct termp *p) p->maxrmargin - p->viscol - vbl : 0; vis = vend = 0; - if (p->lasttcol == 0) + if ((p->flags && TERMP_MULTICOL) == 0) p->tcol->col = 0; - while (p->tcol->col < p->lastcol) { + while (p->tcol->col < p->tcol->lastcol) { /* * Handle literal tab characters: collapse all @@ -124,7 +136,7 @@ term_flushln(struct termp *p) */ ntab = 0; - while (p->tcol->col < p->lastcol && + while (p->tcol->col < p->tcol->lastcol && p->tcol->buf[p->tcol->col] == '\t') { vend = term_tab_next(vis); vbl += vend - vis; @@ -141,7 +153,7 @@ term_flushln(struct termp *p) */ jhy = 0; - for (j = p->tcol->col; j < p->lastcol; j++) { + for (j = p->tcol->col; j < p->tcol->lastcol; j++) { if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t') break; @@ -176,7 +188,7 @@ term_flushln(struct termp *p) if (vend > bp && jhy == 0 && vis > 0 && (p->flags & TERMP_BRNEVER) == 0) { - if (p->lasttcol) + if (p->flags & TERMP_MULTICOL) return; endline(p); @@ -204,14 +216,14 @@ term_flushln(struct termp *p) * Write out the rest of the word. */ - for ( ; p->tcol->col < p->lastcol; p->tcol->col++) { + for ( ; p->tcol->col < p->tcol->lastcol; p->tcol->col++) { if (vend > bp && jhy > 0 && p->tcol->col > jhy) break; if (p->tcol->buf[p->tcol->col] == '\t') break; if (p->tcol->buf[p->tcol->col] == ' ') { j = p->tcol->col; - while (p->tcol->col < p->lastcol && + while (p->tcol->col < p->tcol->lastcol && p->tcol->buf[p->tcol->col] == ' ') p->tcol->col++; dv = (p->tcol->col - j) * (*p->width)(p, ' '); @@ -258,10 +270,13 @@ term_flushln(struct termp *p) else vis = 0; - p->col = p->lastcol = 0; + p->col = p->tcol->col = p->tcol->lastcol = 0; p->minbl = p->trailspace; p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD); + if (p->flags & TERMP_MULTICOL) + return; + /* Trailing whitespace is significant in some columns. */ if (vis && vbl && (TERMP_BRTRSP & p->flags)) @@ -303,7 +318,7 @@ term_newln(struct termp *p) { p->flags |= TERMP_NOSPACE; - if (p->lastcol || p->viscol) + if (p->tcol->lastcol || p->viscol) term_flushln(p); } @@ -563,12 +578,12 @@ term_word(struct termp *p, const char *word) } } /* Trim trailing backspace/blank pair. */ - if (p->lastcol > 2 && - (p->tcol->buf[p->lastcol - 1] == ' ' || - p->tcol->buf[p->lastcol - 1] == '\t')) - p->lastcol -= 2; - if (p->col > p->lastcol) - p->col = p->lastcol; + if (p->tcol->lastcol > 2 && + (p->tcol->buf[p->tcol->lastcol - 1] == ' ' || + p->tcol->buf[p->tcol->lastcol - 1] == '\t')) + p->tcol->lastcol -= 2; + if (p->col > p->tcol->lastcol) + p->col = p->tcol->lastcol; continue; default: continue; @@ -611,10 +626,10 @@ bufferc(struct termp *p, char c) } if (p->col + 1 >= p->tcol->maxcols) adjbuf(p->tcol, p->col + 1); - if (p->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP)) + if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP)) p->tcol->buf[p->col] = c; - if (p->lastcol < ++p->col) - p->lastcol = p->col; + if (p->tcol->lastcol < ++p->col) + p->tcol->lastcol = p->col; } /* @@ -657,10 +672,10 @@ encode1(struct termp *p, int c) p->tcol->buf[p->col++] = c; p->tcol->buf[p->col++] = '\b'; } - if (p->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP)) + if (p->tcol->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP)) p->tcol->buf[p->col] = c; - if (p->lastcol < ++p->col) - p->lastcol = p->col; + if (p->tcol->lastcol < ++p->col) + p->tcol->lastcol = p->col; if (p->flags & TERMP_BACKAFTER) { p->flags |= TERMP_BACKBEFORE; p->flags &= ~TERMP_BACKAFTER; @@ -686,7 +701,7 @@ encode(struct termp *p, const char *word, size_t sz) isgraph((unsigned char)word[i])) encode1(p, word[i]); else { - if (p->lastcol <= p->col || + if (p->tcol->lastcol <= p->col || (word[i] != ' ' && word[i] != ASCII_NBRSP)) p->tcol->buf[p->col] = word[i]; p->col++; @@ -703,8 +718,8 @@ encode(struct termp *p, const char *word, size_t sz) } } } - if (p->lastcol < p->col) - p->lastcol = p->col; + if (p->tcol->lastcol < p->col) + p->tcol->lastcol = p->col; } void diff --git a/usr.bin/mandoc/term.h b/usr.bin/mandoc/term.h index 2d6a12ece7a..ffbeb24127e 100644 --- a/usr.bin/mandoc/term.h +++ b/usr.bin/mandoc/term.h @@ -1,4 +1,4 @@ -/* $OpenBSD: term.h,v 1.70 2017/06/07 20:01:07 schwarze Exp $ */ +/* $OpenBSD: term.h,v 1.71 2017/06/12 18:55:42 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2011-2015, 2017 Ingo Schwarze @@ -52,6 +52,7 @@ struct termp_tbl { struct termp_col { int *buf; /* Output buffer. */ size_t maxcols; /* Allocated bytes in buf. */ + size_t lastcol; /* Last byte in buf. */ size_t col; /* Byte in buf to be written. */ size_t rmargin; /* Current right margin. */ size_t offset; /* Current left margin. */ @@ -69,7 +70,6 @@ struct termp { size_t lastrmargin; /* Right margin before the last ll. */ size_t maxrmargin; /* Max right margin. */ size_t col; /* Byte position in buf. */ - size_t lastcol; /* Bytes in buf. */ size_t viscol; /* Chars on current line. */ size_t trailspace; /* See term_flushln(). */ size_t minbl; /* Minimum blanks before next field. */ @@ -98,6 +98,7 @@ struct termp { #define TERMP_NOBUF (1 << 17) /* Bypass output buffer. */ #define TERMP_NEWMC (1 << 18) /* No .mc printed yet. */ #define TERMP_ENDMC (1 << 19) /* Next break ends .mc mode. */ +#define TERMP_MULTICOL (1 << 20) /* Multiple column mode. */ enum termtype type; /* Terminal, PS, or PDF. */ enum termenc enc; /* Type of encoding. */ enum termfont fontl; /* Last font set. */ @@ -128,6 +129,7 @@ void roff_term_pre(struct termp *, const struct roff_node *); void term_eqn(struct termp *, const struct eqn *); void term_tbl(struct termp *, const struct tbl_span *); void term_free(struct termp *); +void term_setcol(struct termp *, size_t); void term_newln(struct termp *); void term_vspace(struct termp *); void term_word(struct termp *, const char *);