summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE2
-rw-r--r--Makefile3
-rw-r--r--compat_recallocarray.c108
-rwxr-xr-xconfigure9
-rw-r--r--configure.local.example1
-rw-r--r--mandoc_aux.c13
-rw-r--r--mandoc_aux.h3
-rw-r--r--regress/char/unicode/input.out_ascii2
-rw-r--r--tbl_term.c212
-rw-r--r--term.c63
-rw-r--r--term.h4
-rw-r--r--test-recallocarray.c11
12 files changed, 343 insertions, 88 deletions
diff --git a/LICENSE b/LICENSE
index c364839a..6010d814 100644
--- a/LICENSE
+++ b/LICENSE
@@ -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>
diff --git a/Makefile b/Makefile
index 1964818d..958a8b45 100644
--- a/Makefile
+++ b/Makefile
@@ -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 */
diff --git a/configure b/configure
index 27b13b04..4d1a26a4 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/tbl_term.c b/tbl_term.c
index 351b262a..6156a25b 100644
--- a/tbl_term.c
+++ b/tbl_term.c
@@ -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;
}
/*
diff --git a/term.c b/term.c
index 2e917c8f..bbadef66 100644
--- a/term.c
+++ b/term.c
@@ -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
diff --git a/term.h b/term.h
index 0a7f19ce..25735631 100644
--- a/term.h
+++ b/term.h
@@ -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);
+}