X-Git-Url: https://git.cameronkatri.com/mandoc.git/blobdiff_plain/95ec7b52881820b8d6d9d9497b358d00a856ca28..c44d370823355882e5013556927675ea11fa8199:/out.c?ds=sidebyside

diff --git a/out.c b/out.c
index aff35583..b2b64378 100644
--- a/out.c
+++ b/out.c
@@ -1,7 +1,7 @@
-/*	$Id: out.c,v 1.62 2015/10/12 00:08:16 schwarze Exp $ */
+/*	$Id: out.c,v 1.70 2017/06/27 18:25:02 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 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
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <assert.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
@@ -29,9 +30,10 @@
 #include "out.h"
 
 static	void	tblcalc_data(struct rofftbl *, struct roffcol *,
-			const struct tbl_opts *, const struct tbl_dat *);
+			const struct tbl_opts *, const struct tbl_dat *,
+			size_t);
 static	void	tblcalc_literal(struct rofftbl *, struct roffcol *,
-			const struct tbl_dat *);
+			const struct tbl_dat *, size_t);
 static	void	tblcalc_number(struct rofftbl *, struct roffcol *,
 			const struct tbl_opts *, const struct tbl_dat *);
 
@@ -40,10 +42,10 @@ static	void	tblcalc_number(struct rofftbl *, struct roffcol *,
  * Parse the *src string and store a scaling unit into *dst.
  * If the string doesn't specify the unit, use the default.
  * If no default is specified, fail.
- * Return 2 on complete success, 1 when a conversion was done,
- * but there was trailing garbage, and 0 on total failure.
+ * Return a pointer to the byte after the last byte used,
+ * or NULL on total failure.
  */
-int
+const char *
 a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
 {
 	char		*endptr;
@@ -51,7 +53,7 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
 	dst->unit = def == SCALE_MAX ? SCALE_BU : def;
 	dst->scale = strtod(src, &endptr);
 	if (endptr == src)
-		return 0;
+		return NULL;
 
 	switch (*endptr++) {
 	case 'c':
@@ -84,17 +86,14 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
 	case 'v':
 		dst->unit = SCALE_VS;
 		break;
-	case '\0':
-		endptr--;
-		/* FALLTHROUGH */
 	default:
+		endptr--;
 		if (SCALE_MAX == def)
-			return 0;
+			return NULL;
 		dst->unit = def;
 		break;
 	}
-
-	return *endptr == '\0' ? 2 : 1;
+	return endptr;
 }
 
 /*
@@ -105,8 +104,9 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
  */
 void
 tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
-	size_t totalwidth)
+    size_t offset, size_t rmargin)
 {
+	struct roffsu		 su;
 	const struct tbl_opts	*opts;
 	const struct tbl_dat	*dp;
 	struct roffcol		*col;
@@ -141,13 +141,29 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
 			if (1 < spans)
 				continue;
 			icol = dp->layout->col;
-			if (maxcol < icol)
-				maxcol = icol;
+			while (maxcol < icol)
+				tbl->cols[++maxcol].spacing = SIZE_MAX;
 			col = tbl->cols + icol;
 			col->flags |= dp->layout->flags;
 			if (dp->layout->flags & TBL_CELL_WIGN)
 				continue;
-			tblcalc_data(tbl, col, opts, dp);
+			if (dp->layout->wstr != NULL &&
+			    dp->layout->width == 0 &&
+			    a2roffsu(dp->layout->wstr, &su, SCALE_EN)
+			    != NULL)
+				dp->layout->width =
+				    (*tbl->sulen)(&su, tbl->arg);
+			if (col->width < dp->layout->width)
+				col->width = dp->layout->width;
+			if (dp->layout->spacing != SIZE_MAX &&
+			    (col->spacing == SIZE_MAX ||
+			     col->spacing < dp->layout->spacing))
+				col->spacing = dp->layout->spacing;
+			tblcalc_data(tbl, col, opts, dp,
+			    dp->block == 0 ? 0 :
+			    dp->layout->width ? dp->layout->width :
+			    rmargin ? (rmargin + sp->opts->cols / 2)
+			    / (sp->opts->cols + 1) : 0);
 		}
 	}
 
@@ -161,6 +177,8 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
 	ewidth = xwidth = 0;
 	for (icol = 0; icol <= maxcol; icol++) {
 		col = tbl->cols + icol;
+		if (col->spacing == SIZE_MAX || icol == maxcol)
+			col->spacing = 3;
 		if (col->flags & TBL_CELL_EQUAL) {
 			necol++;
 			if (ewidth < col->width)
@@ -184,7 +202,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
 				continue;
 			if (col->width == ewidth)
 				continue;
-			if (nxcol && totalwidth)
+			if (nxcol && rmargin)
 				xwidth += ewidth - col->width;
 			col->width = ewidth;
 		}
@@ -196,10 +214,13 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
 	 * Distribute the available width evenly.
 	 */
 
-	if (nxcol && totalwidth) {
-		xwidth = totalwidth - xwidth - 3*maxcol -
+	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
@@ -232,7 +253,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
 
 static void
 tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
-		const struct tbl_opts *opts, const struct tbl_dat *dp)
+    const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw)
 {
 	size_t		 sz;
 
@@ -249,7 +270,7 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
 	case TBL_CELL_CENTRE:
 	case TBL_CELL_LEFT:
 	case TBL_CELL_RIGHT:
-		tblcalc_literal(tbl, col, dp);
+		tblcalc_literal(tbl, col, dp, mw);
 		break;
 	case TBL_CELL_NUMBER:
 		tblcalc_number(tbl, col, opts, dp);
@@ -263,16 +284,35 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
 
 static void
 tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
-		const struct tbl_dat *dp)
+    const struct tbl_dat *dp, size_t mw)
 {
-	size_t		 sz;
-	const char	*str;
-
-	str = dp->string ? dp->string : "";
-	sz = (*tbl->slen)(str, tbl->arg);
-
-	if (col->width < sz)
-		col->width = sz;
+	const char	*str;	/* Beginning of the first line. */
+	const char	*beg;	/* Beginning of the current line. */
+	char		*end;	/* End of the current line. */
+	size_t		 lsz;	/* Length of the current line. */
+	size_t		 wsz;	/* Length of the current word. */
+
+	if (dp->string == NULL || *dp->string == '\0')
+		return;
+	str = mw ? mandoc_strdup(dp->string) : dp->string;
+	lsz = 0;
+	for (beg = str; beg != NULL && *beg != '\0'; beg = end) {
+		end = mw ? strchr(beg, ' ') : NULL;
+		if (end != NULL) {
+			*end++ = '\0';
+			while (*end == ' ')
+				end++;
+		}
+		wsz = (*tbl->slen)(beg, tbl->arg);
+		if (mw && lsz && lsz + 1 + wsz <= mw)
+			lsz += 1 + wsz;
+		else
+			lsz = wsz;
+		if (col->width < lsz)
+			col->width = lsz;
+	}
+	if (mw)
+		free((void *)str);
 }
 
 static void