changeset 837:f51138584096

Improvements to wrapping. - Introduce \<space> to indicate line-break positions to enable sensible wrapping of Chinese and similar text. - Allow lines to be longer than the wrapping width if there are no spaces, as generated email addresses (e.g. for moderation) won't work if split. - Fix a bug where using a whole line while wrapping would turn wrapping off as the saved (empty) remaining portion would be considered a blank line. - Use int rather than size_t for line lengths; it's just easier, since we use negatives for certain conditions, and it should be plenty big enough.
author Ben Schmidt
date Mon, 23 Jan 2012 19:55:04 +1100
parents 5ab7b62e8223
children 64552670ace9
files ChangeLog README.listtexts src/prepstdreply.c
diffstat 3 files changed, 82 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Jan 23 18:30:06 2012 +1100
+++ b/ChangeLog	Mon Jan 23 19:55:04 2012 +1100
@@ -1,3 +1,7 @@
+ o Introduce \<space> to indicate line-break positions to enable sensible
+   wrapping of Chinese and similar text.
+ o Allow lines to be longer than the wrapping width if there are no spaces,
+   as generated email addresses (e.g. for moderation) won't work if split.
  o Add rejection of posts and obstruction of subscriptions.
  o Avoid bogus error messages when logging that the list address has been
    found in To: or CC: headers.
--- a/README.listtexts	Mon Jan 23 18:30:06 2012 +1100
+++ b/README.listtexts	Mon Jan 23 19:55:04 2012 +1100
@@ -248,11 +248,13 @@
 
 - %wrap%
 - %wrap W%
-  lines until the next blank line are concatenated (lines have whitespace
-  trimmed, then a single space is used to separate them) and are then rewrapped
-  (by breaking them at spaces) to a width of W (or 76 if W is omitted); the
-  width is reckoned including characters preceding the directive so it is an
-  absolute maximum width
+  lines until the next blank line are concatenated and are then rewrapped to a
+  width of W (or 76 if W is omitted); lines have whitespace trimmed before
+  being joined with a single space; lines are broken at spaces or at points
+  marked for breaking with \<space>; the width is reckoned including any text
+  preceding the directive and any indentation preserved from a file which
+  included the current one, so it is an absolute maximum width; it is measured
+  in bytes
 
 - %text T%
   text from the file named T in the listdir/text directory; the name may only
@@ -502,6 +504,8 @@
   Subject: header as Mlmmj does automatic quoting for that header as described
   above)
 
+- \<space>
+  nothing, but allow the line to be broken here when wrapping
+
 - \\
   a single \
-
--- a/src/prepstdreply.c	Mon Jan 23 18:30:06 2012 +1100
+++ b/src/prepstdreply.c	Mon Jan 23 19:55:04 2012 +1100
@@ -106,8 +106,8 @@
 	substitution *substs;
 	char *mailname;
 	formatted *fmts;
-	size_t wrapindent;
-	size_t wrapwidth;
+	int wrapindent;
+	int wrapwidth;
 	conditional *cond;
 	conditional *skip;
 };
@@ -961,11 +961,11 @@
 {
 	char *line;
 	const char *item;
-	char *pos;
-	char *tmp, *spc;
+	char *pos, *subpos;
+	char *tmp;
 	char *prev = NULL;
-	int incision;
-	size_t len, i;
+	int incision, spc, spcnext;
+	int len, i;
 	int directive;
 	int peeking = 0; /* for a failed conditional without an else */
 	int swallow;
@@ -1060,11 +1060,27 @@
 		} else {
 			incision = -1;
 		}
-		spc = NULL;
+		spc = -1;
+		spcnext = 0;
 		directive = 0;
 		while (*pos != '\0') {
-			if (txt->wrapwidth != 0 && len > txt->wrapwidth &&
-					!peeking) break;
+			if (txt->wrapwidth != 0 && len >= txt->wrapwidth &&
+					!peeking) {
+				if (spcnext < txt->wrapwidth || spc == -1) {
+					subpos = line + spcnext;
+					while (subpos < pos) {
+						if (*subpos == ' ') {
+							spc = subpos - line;
+						}
+						spcnext++;
+						if (spcnext >= txt->wrapwidth &&
+								spc != -1)
+								break;
+						subpos++;
+					}
+				}
+				if (spc != -1) break;
+			}
 			if (*pos == '\r') {
 				*pos = '\0';
 				pos++;
@@ -1079,7 +1095,21 @@
 				txt->src->upcoming = mystrdup(pos);
 				break;
 			} else if (*pos == ' ') {
-				spc = pos;
+				if (txt->skip == NULL) {
+					spc = pos - line;
+					spcnext = spc + 1;
+				}
+			} else if (*pos == '\\' && *(pos + 1) == ' ') {
+				if (txt->skip == NULL) {
+					spc = pos - line - 1;
+					spcnext = spc + 1;
+				}
+				*pos = '\0';
+				tmp = concatstr(2, line, pos + 2);
+				pos = tmp + (pos - line);
+				myfree(line);
+				line = tmp;
+				continue;
 			} else if (*pos == '\t') {
 				/* Avoid breaking due to peeking */
 			} else if (txt->src->transparent) {
@@ -1091,7 +1121,6 @@
 				substitute_one(&line, &pos, listaddr,
 						listdelim, listdir, txt);
 				len = pos - line;
-				spc = NULL;
 				/* The function sets up for the next character
 				 * to process, so continue straight away. */
 				continue;
@@ -1099,7 +1128,6 @@
 				directive = 1;
 				swallow = handle_directive(txt, &line, &pos,
 						peeking, listdir);
-				spc = NULL;
 				if (swallow == 1) peeking = 0;
 				if (swallow == -1) break;
 				if (txt->skip != NULL) {
@@ -1130,7 +1158,10 @@
 			} else if (peeking && txt->skip == NULL) {
 				break;
 			}
-			if (txt->skip == NULL) len++;
+			if (txt->skip == NULL) {
+				if (spcnext == len) spcnext++;
+				len++;
+			}
 			pos++;
 		}
 
@@ -1155,27 +1186,17 @@
 		}
 
 		if (txt->wrapwidth != 0 && !peeking) {
-			if (len <= txt->wrapwidth) {
+			if (len < txt->wrapwidth) {
 				prev = line;
 				continue;
 			}
-			if (spc == NULL) {
-				pos = line + len - 1;
-				while (pos >= line) {
-					if (*pos == ' ') {
-						spc = pos;
-						break;
-					}
-					pos--;
+			if (spc != -1) {
+				if (line[spc] == ' ') line[spc] = '\0';
+				spc++;
+				if (line[spc] == '\0') spc = -1;
 				}
-			}
-			if (spc == NULL) {
-				spc = line + txt->wrapwidth - 1;
-			} else {
-				*spc = '\0';
-				spc++;
-			}
-			len = strlen(spc);
+			if (spc != -1) {
+				len = strlen(line + spc);
 			if (txt->src->upcoming == NULL) {
 				tmp = mymalloc((len + txt->wrapindent + 1) *
 						sizeof(char));
@@ -1185,14 +1206,16 @@
 						sizeof(char));
 			}
 			pos = tmp;
-			for (i = txt->wrapindent; i > 0; i--) *pos++ = ' ';
-			strcpy(pos, spc);
+				for (i = txt->wrapindent; i > 0; i--)
+					*pos++ = ' ';
+				strcpy(pos, line + spc);
 			if (txt->src->upcoming != NULL) {
 				strcpy(pos + len, txt->src->upcoming);
 				myfree(txt->src->upcoming);
 			}
 			txt->src->upcoming = tmp;
-			*spc = '\0';
+			}
+			line[spc] = '\0';
 			tmp = mystrdup(line);
 			myfree(line);
 			line = tmp;