changeset 815:fdd43713fb52

Add %wrap% and %wrap W% formatting directives.
author Ben Schmidt
date Tue, 17 Jan 2012 13:05:40 +1100
parents 757225257ef3
children ed446ead03bd
files ChangeLog README.listtexts src/prepstdreply.c
diffstat 3 files changed, 199 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Jan 17 11:20:38 2012 +1100
+++ b/ChangeLog	Tue Jan 17 13:05:40 2012 +1100
@@ -1,3 +1,4 @@
+ o Add %wrap% and %wrap W% formatting directives
  o Add %digestthreads%, %gatekeepers%, %listsubs%, %digestsubs%, %nomailsubs%,
    %moderators% and %bouncenumbers%
  o Deprecate various list text substitutions such as $newsub$, $oldsub$,
--- a/README.listtexts	Tue Jan 17 11:20:38 2012 +1100
+++ b/README.listtexts	Tue Jan 17 13:05:40 2012 +1100
@@ -248,10 +248,11 @@
 
 - %wrap%
 - %wrap W%
-  lines until the next blank line are all concatenated (lines after the first
-  have whitespace trimmed; a single space separates lines) and are then
-  rewrapped (by breaking them at spaces) to a width of W (or 76 if W is
-  omitted)
+  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
 
 - %text T%
   text from the file named T in the listdir/text directory; the name may only
--- a/src/prepstdreply.c	Tue Jan 17 11:20:38 2012 +1100
+++ b/src/prepstdreply.c	Tue Jan 17 13:05:40 2012 +1100
@@ -85,6 +85,8 @@
 	substitution *substs;
 	char *mailname;
 	formatted *fmts;
+	size_t wrapindent;
+	size_t wrapwidth;
 };
 
 
@@ -425,6 +427,8 @@
 	txt->substs = NULL;
 	txt->mailname = NULL;
 	txt->fmts = NULL;
+	txt->wrapindent = 0;
+	txt->wrapwidth = 0;
 
 	tmp = concatstr(3, listdir, "/text/", filename);
 	txt->src->fd = open(tmp, O_RDONLY);
@@ -659,13 +663,33 @@
 		*line_p = line;
 		return;
 	} else if(strcmp(token, "comment") == 0 || strcmp(token, "$") == 0 ) {
-		/* Skip the rest of the line; the earlier part which we
-		 * will return has already been truncated; the caller
-		 * will save the next line for later use if necessary. */
 		pos = endpos + 1;
 		while (*pos != '\0' && *pos != '\r' && *pos != '\n') pos++;
-		*pos_p = pos;
+		line = concatstr(2, line, pos);
+		*pos_p = line + (*pos_p - *line_p);
+		myfree(*line_p);
+		*line_p = line;
 		return;
+	} else if(strncmp(token, "wrap", 4) == 0) {
+		token += 4;
+		limit = 0;
+		if (*token == '\0') {
+			limit = 76;
+		} else if (*token == ' ') {
+			token = numeric_token(token + 1);
+			if (token != NULL) limit = atol(token);
+		}
+		if (limit != 0) {
+			txt->wrapindent = strlen(line);
+			if (txt->src->prefix != NULL)
+					txt->wrapindent -= strlen(txt->src->prefix);
+			txt->wrapwidth = limit;
+			line = concatstr(2, line, endpos + 1);
+			*pos_p = line + (*pos_p - *line_p);
+			myfree(*line_p);
+			*line_p = line;
+			return;
+		}
 	} else if(strncmp(token, "control ", 8) == 0) {
 		token = filename_token(token + 8);
 		if (token != NULL) {
@@ -736,14 +760,18 @@
 		const char *listdir)
 {
 	char *line = NULL;
+	const char *item;
 	char *pos;
-	char *tmp;
-	const char *item;
+	char *tmp, *spc;
+	char *prev = NULL;
+	size_t len, i;
 
+	for (;;) {
 	while (txt->src != NULL) {
 		if (txt->src->upcoming != NULL) {
 			if (txt->src->prefix != NULL) {
-				line = concatstr(2, txt->src->prefix, txt->src->upcoming);
+					line = concatstr(2, txt->src->prefix,
+							txt->src->upcoming);
 				myfree(txt->src->upcoming);
 			} else {
 				line = txt->src->upcoming;
@@ -753,7 +781,8 @@
 		}
 		if (txt->src->limit != 0) {
 			if (txt->src->fd != -1) {
-				txt->src->upcoming = mygetline(txt->src->fd);
+					txt->src->upcoming =
+							mygetline(txt->src->fd);
 			} else if (txt->src->fmt != NULL) {
 				item = (*txt->src->fmt->get)(
 						txt->src->fmt->state);
@@ -775,8 +804,50 @@
 	myfree(line);
 	line = tmp;
 
+		if (prev != NULL) {
+			/* Wrapping */
+			len = strlen(prev);
+			pos = prev + len - 1;
+			while (pos > prev && (*pos == ' ' || *pos == '\t'))
+					pos--;
+			pos++;
+			*pos = '\0';
+			len = pos - prev;
+			if (*line == '\r' || *line == '\n' || *line == '\0') {
+				/* Blank line; stop wrapping, finish
+				   the last line and save the blank
+				   line for later. */
+				txt->wrapwidth = 0;
+				txt->src->upcoming = line;
+				line = prev;
+				pos = line + len;
+			} else {
 	pos = line;
+				while (*pos == ' ' || *pos == '\t') pos++;
+				if (*pos == '\0') {
+					myfree(line);
+					continue;
+				}
+				if (*prev == '\0') {
+					tmp = mystrdup(pos);
+				} else {
+					tmp = concatstr(3, prev, " ", pos);
+				}
+				myfree(line);
+				line = tmp;
+				myfree(prev);
+				len++;
+				pos = line + len;
+			}
+			prev = NULL;
+		} else {
+			len = 0;
+			pos = line;
+		}
+
+		spc = NULL;
 	while (*pos != '\0') {
+			if (txt->wrapwidth != 0 && len > txt->wrapwidth) break;
 		if (*pos == '\r') {
 			*pos = '\0';
 			pos++;
@@ -790,24 +861,75 @@
 			if (*pos == '\0') break;
 			txt->src->upcoming = mystrdup(pos);
 			break;
+			} else if (*pos == ' ') {
+				spc = pos;
 		} else if (txt->src->transparent) {
 			/* Do nothing if the file is to be included
 			 * transparently */
 		} else if (*pos == '$') {
-			substitute_one(&line, &pos,
-					listaddr, listdelim, listdir, txt);
+				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;
 		} else if (*pos == '%') {
 			handle_directive(txt, &line, &pos, listdir);
+				len = pos - line;
+				spc = NULL;
 			/* The function sets up for the next character
 			 * to process, so continue straight away. */
 			continue;
 		}
+			len++;
 		pos++;
 	}
 
+		if (txt->wrapwidth != 0) {
+			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 == NULL) {
+				spc = line + txt->wrapwidth - 1;
+			} else {
+				*spc = '\0';
+				spc++;
+			}
+			len = strlen(spc);
+			if (txt->src->upcoming == NULL) {
+				tmp = mymalloc((len + txt->wrapindent + 1) *
+						sizeof(char));
+			} else {
+				tmp = mymalloc((len + txt->wrapindent + 1 +
+						strlen(txt->src->upcoming)) *
+						sizeof(char));
+			}
+			pos = tmp;
+			for (i = txt->wrapindent; i > 0; i--) *pos++ = ' ';
+			strcpy(pos, spc);
+			if (txt->src->upcoming != NULL) {
+				strcpy(pos + len, txt->src->upcoming);
+				myfree(txt->src->upcoming);
+			}
+			txt->src->upcoming = tmp;
+			*spc = '\0';
+			tmp = mystrdup(line);
+			myfree(line);
+			line = tmp;
+		}
+
 	if (txt->src->suffix != NULL) {
 		tmp = concatstr(2, line, txt->src->suffix);
 		myfree(line);
@@ -816,6 +938,7 @@
 		return line;
 	}
 }
+}
 
 
 void close_text(text *txt) {