diff options
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | compat_recallocarray.c | 108 | ||||
-rwxr-xr-x | configure | 9 | ||||
-rw-r--r-- | configure.local.example | 1 | ||||
-rw-r--r-- | mandoc_aux.c | 13 | ||||
-rw-r--r-- | mandoc_aux.h | 3 | ||||
-rw-r--r-- | regress/char/unicode/input.out_ascii | 2 | ||||
-rw-r--r-- | tbl_term.c | 212 | ||||
-rw-r--r-- | term.c | 63 | ||||
-rw-r--r-- | term.h | 4 | ||||
-rw-r--r-- | test-recallocarray.c | 11 |
12 files changed, 343 insertions, 88 deletions
@@ -13,7 +13,7 @@ Copyright (c) 2016 Ed Maste <emaste@freebsd.org> Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org> Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org> Copyright (c) 1998, 2004, 2010 Todd C. Miller <Todd.Miller@courtesan.com> -Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> +Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net> Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> Copyright (c) 1994 Christos Zoulas <christos@netbsd.org> Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org> @@ -38,6 +38,7 @@ TESTSRCS = test-be32toh.c \ test-progname.c \ test-recvmsg.c \ test-reallocarray.c \ + test-recallocarray.c \ test-rewb-bsd.c \ test-rewb-sysv.c \ test-sandbox_init.c \ @@ -64,6 +65,7 @@ SRCS = att.c \ compat_ohash.c \ compat_progname.c \ compat_reallocarray.c \ + compat_recallocarray.c \ compat_strcasestr.c \ compat_stringlist.c \ compat_strlcat.c \ @@ -240,6 +242,7 @@ COMPAT_OBJS = compat_err.o \ compat_ohash.o \ compat_progname.o \ compat_reallocarray.o \ + compat_recallocarray.o \ compat_strcasestr.o \ compat_strlcat.o \ compat_strlcpy.o \ diff --git a/compat_recallocarray.c b/compat_recallocarray.c new file mode 100644 index 00000000..c5fcea9f --- /dev/null +++ b/compat_recallocarray.c @@ -0,0 +1,108 @@ +#include "config.h" + +#if HAVE_RECALLOCARRAY + +int dummy; + +#else + +/* $Id$ */ +/* $OpenBSD: malloc.c,v 1.225 2017/05/13 07:11:29 otto Exp $ */ +/* + * Copyright (c) 2017 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) + +/* + * Even though specified in POSIX, the PAGESIZE and PAGE_SIZE + * macros have very poor portability. Since we only use this + * to avoid free() overhead for small shrinking, simply pick + * an arbitrary number. + */ +#define MALLOC_PAGESIZE (1UL << 12) + + +void * +recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) +{ + size_t oldsize, newsize; + void *newptr; + + if (ptr == NULL) + return calloc(newnmemb, size); + + if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + newnmemb > 0 && SIZE_MAX / newnmemb < size) { + errno = ENOMEM; + return NULL; + } + newsize = newnmemb * size; + + if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { + errno = EINVAL; + return NULL; + } + oldsize = oldnmemb * size; + + /* + * Don't bother too much if we're shrinking just a bit, + * we do not shrink for series of small steps, oh well. + */ + if (newsize <= oldsize) { + size_t d = oldsize - newsize; + + if (d < oldsize / 2 && d < MALLOC_PAGESIZE) { + memset((char *)ptr + newsize, 0, d); + return ptr; + } + } + + newptr = malloc(newsize); + if (newptr == NULL) + return NULL; + + if (newsize > oldsize) { + memcpy(newptr, ptr, oldsize); + memset((char *)newptr + oldsize, 0, newsize - oldsize); + } else + memcpy(newptr, ptr, newsize); + + /* + * At this point, the OpenBSD implementation calls + * explicit_bzero() on the old memory before it is + * freed. Since explicit_bzero() is hard to implement + * portably and we don't handle confidential data in + * mandoc in the first place, simply free the memory + * without clearing it. + */ + + free(ptr); + + return newptr; +} + +#endif /* !HAVE_RECALLOCARRAY */ @@ -73,6 +73,7 @@ HAVE_PATH_MAX= HAVE_PLEDGE= HAVE_PROGNAME= HAVE_REALLOCARRAY= +HAVE_RECALLOCARRAY= HAVE_RECVMSG= HAVE_REWB_BSD= HAVE_REWB_SYSV= @@ -229,6 +230,7 @@ runtest pledge PLEDGE || true runtest sandbox_init SANDBOX_INIT || true runtest progname PROGNAME || true runtest reallocarray REALLOCARRAY || true +runtest recallocarray RECALLOCARRAY || true runtest rewb-bsd REWB_BSD || true runtest rewb-sysv REWB_SYSV || true runtest strcasestr STRCASESTR || true @@ -348,7 +350,8 @@ cat << __HEREDOC__ __HEREDOC__ -[ ${HAVE_GETLINE} -eq 0 -o ${HAVE_REALLOCARRAY} -eq 0 -o \ +[ ${HAVE_GETLINE} -eq 0 -o \ + ${HAVE_REALLOCARRAY} -eq 0 -o ${HAVE_RECALLOCARRAY} -eq 0 -o \ ${HAVE_STRLCAT} -eq 0 -o ${HAVE_STRLCPY} -eq 0 ] \ && echo "#include <sys/types.h>" [ ${HAVE_VASPRINTF} -eq 0 ] && echo "#include <stdarg.h>" @@ -383,6 +386,7 @@ cat << __HEREDOC__ #define HAVE_PLEDGE ${HAVE_PLEDGE} #define HAVE_PROGNAME ${HAVE_PROGNAME} #define HAVE_REALLOCARRAY ${HAVE_REALLOCARRAY} +#define HAVE_RECALLOCARRAY ${HAVE_RECALLOCARRAY} #define HAVE_REWB_BSD ${HAVE_REWB_BSD} #define HAVE_REWB_SYSV ${HAVE_REWB_SYSV} #define HAVE_SANDBOX_INIT ${HAVE_SANDBOX_INIT} @@ -434,6 +438,9 @@ fi [ ${HAVE_REALLOCARRAY} -eq 0 ] && \ echo "extern void *reallocarray(void *, size_t, size_t);" +[ ${HAVE_RECALLOCARRAY} -eq 0 ] && \ + echo "extern void *recallocarray(void *, size_t, size_t, size_t);" + [ ${HAVE_STRCASESTR} -eq 0 ] && \ echo "extern char *strcasestr(const char *, const char *);" diff --git a/configure.local.example b/configure.local.example index e1d5b829..324fe38b 100644 --- a/configure.local.example +++ b/configure.local.example @@ -292,6 +292,7 @@ HAVE_PATH_MAX=0 HAVE_PLEDGE=0 HAVE_PROGNAME=0 HAVE_REALLOCARRAY=0 +HAVE_RECALLOCARRAY=0 HAVE_REWB_BSD=0 HAVE_REWB_SYSV=0 HAVE_STRCASESTR=0 diff --git a/mandoc_aux.c b/mandoc_aux.c index b469a0d8..78466d95 100644 --- a/mandoc_aux.c +++ b/mandoc_aux.c @@ -1,7 +1,7 @@ /* $Id$ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -71,7 +71,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); @@ -81,13 +80,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/mandoc_aux.h b/mandoc_aux.h index 3742c412..765f3c99 100644 --- a/mandoc_aux.h +++ b/mandoc_aux.h @@ -1,7 +1,7 @@ /* $Id$ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org> * * 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/regress/char/unicode/input.out_ascii b/regress/char/unicode/input.out_ascii index 7711574c..410bdc85 100644 --- a/regress/char/unicode/input.out_ascii +++ b/regress/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 @@ -68,12 +68,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, @@ -111,82 +112,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); @@ -201,7 +301,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; } /* @@ -40,6 +40,18 @@ 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) { for (p->tcol = p->tcols; p->tcol < p->tcols + p->maxtcol; p->tcol++) @@ -116,9 +128,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 @@ -126,7 +138,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; @@ -143,7 +155,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; @@ -178,7 +190,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); @@ -206,14 +218,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, ' '); @@ -260,10 +272,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)) @@ -305,7 +320,7 @@ term_newln(struct termp *p) { p->flags |= TERMP_NOSPACE; - if (p->lastcol || p->viscol) + if (p->tcol->lastcol || p->viscol) term_flushln(p); } @@ -565,12 +580,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; @@ -613,10 +628,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; } /* @@ -659,10 +674,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; @@ -688,7 +703,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++; @@ -705,8 +720,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 @@ -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 *); diff --git a/test-recallocarray.c b/test-recallocarray.c new file mode 100644 index 00000000..e0c60d71 --- /dev/null +++ b/test-recallocarray.c @@ -0,0 +1,11 @@ +#include <stdlib.h> + +int +main(void) +{ + void *p; + + if ((p = calloc(2, 2)) == NULL) + return 1; + return !recallocarray(p, 2, 3, 2); +} |