+ for (icol = 0; icol <= maxcol; icol++)
+ colwidth[icol] = SIZE_MAX;
+ for (g = first_group; g != NULL; g = g->next)
+ for (icol = g->startcol; icol <= g->endcol; icol++)
+ colwidth[icol] = tbl->cols[icol].width;
+
+ /*
+ * Find the smallest and second smallest column width
+ * among the columns which may need expamsion.
+ */
+
+ min1 = min2 = SIZE_MAX;
+ for (icol = 0; icol <= maxcol; icol++) {
+ width = colwidth[icol];
+ if (min1 > width) {
+ min2 = min1;
+ min1 = width;
+ } else if (min1 < width && min2 > width)
+ min2 = width;
+ }
+
+ /*
+ * Find the minimum wanted width
+ * for any one of the narrowest columns,
+ * and mark the columns wanting that width.
+ */
+
+ wanted = min2;
+ for (g = first_group; g != NULL; g = g->next) {
+ necol = 0;
+ for (icol = g->startcol; icol <= g->endcol; icol++)
+ if (colwidth[icol] == min1)
+ necol++;
+ if (necol == 0)
+ continue;
+ width = min1 + (g->wanted - 1) / necol + 1;
+ if (width > min2)
+ width = min2;
+ if (wanted > width)
+ wanted = width;
+ }
+
+ /* Record the effect of the widening. */
+
+ gp = &first_group;
+ while ((g = *gp) != NULL) {
+ done = 0;
+ for (icol = g->startcol; icol <= g->endcol; icol++) {
+ if (colwidth[icol] != min1)
+ continue;
+ if (g->wanted <= wanted - min1) {
+ tbl->cols[icol].width += g->wanted;
+ done = 1;
+ break;
+ }
+ tbl->cols[icol].width = wanted;
+ g->wanted -= wanted - min1;
+ }
+ if (done) {
+ *gp = g->next;
+ free(g);
+ } else
+ gp = &g->next;
+ }
+ }
+ free(colwidth);
+
+ /*
+ * Align numbers with text.
+ * Count columns to equalize and columns to maximize.
+ * Find maximum width of the columns to equalize.
+ * Find total width of the columns *not* to maximize.
+ */
+
+ necol = nxcol = 0;
+ ewidth = xwidth = 0;
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if (col->width > col->nwidth)
+ col->decimal += (col->width - col->nwidth) / 2;
+ if (col->flags & TBL_CELL_EQUAL) {
+ necol++;
+ if (ewidth < col->width)
+ ewidth = col->width;
+ }
+ if (col->flags & TBL_CELL_WMAX)
+ nxcol++;
+ else
+ xwidth += col->width;
+ }
+
+ /*
+ * Equalize columns, if requested for any of them.
+ * Update total width of the columns not to maximize.
+ */
+
+ if (necol) {
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if ( ! (col->flags & TBL_CELL_EQUAL))
+ continue;
+ if (col->width == ewidth)
+ continue;
+ if (nxcol && rmargin)
+ xwidth += ewidth - col->width;
+ col->width = ewidth;
+ }
+ }
+
+ /*
+ * If there are any columns to maximize, find the total
+ * available width, deducting 3n margins between columns.
+ * Distribute the available width evenly.
+ */
+
+ if (nxcol && rmargin) {
+ xwidth += 3*maxcol +
+ (opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ?
+ 2 : !!opts->lvert + !!opts->rvert);
+ if (rmargin <= offset + xwidth)
+ return;
+ xwidth = rmargin - offset - xwidth;
+
+ /*
+ * Emulate a bug in GNU tbl width calculation that
+ * manifests itself for large numbers of x-columns.
+ * Emulating it for 5 x-columns gives identical
+ * behaviour for up to 6 x-columns.
+ */
+
+ if (nxcol == 5) {
+ quirkcol = xwidth % nxcol + 2;
+ if (quirkcol != 3 && quirkcol != 4)
+ quirkcol = -1;
+ } else
+ quirkcol = -1;
+
+ necol = 0;
+ ewidth = 0;
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if ( ! (col->flags & TBL_CELL_WMAX))
+ continue;
+ col->width = (double)xwidth * ++necol / nxcol
+ - ewidth + 0.4995;
+ if (necol == quirkcol)
+ col->width--;
+ ewidth += col->width;
+ }
+ }
+}
+
+static size_t
+tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
+ const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw)
+{
+ size_t sz;
+
+ /* Branch down into data sub-types. */
+
+ switch (dp->layout->pos) {
+ case TBL_CELL_HORIZ:
+ case TBL_CELL_DHORIZ:
+ sz = (*tbl->len)(1, tbl->arg);
+ if (col != NULL && col->width < sz)
+ col->width = sz;
+ return sz;
+ case TBL_CELL_LONG:
+ case TBL_CELL_CENTRE:
+ case TBL_CELL_LEFT:
+ case TBL_CELL_RIGHT:
+ return tblcalc_literal(tbl, col, dp, mw);
+ case TBL_CELL_NUMBER:
+ return tblcalc_number(tbl, col, opts, dp);
+ case TBL_CELL_DOWN:
+ return 0;