changeset 818:24bf028aa8a0

Skip blank lines followed by unsatisfied conditionals with no else part.
author Ben Schmidt
date Tue, 17 Jan 2012 14:14:26 +1100
parents 9caf15c6ae31
children 6cc2a4cdc468
files ChangeLog include/prepstdreply.h src/prepstdreply.c src/send_digest.c
diffstat 4 files changed, 96 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Jan 17 14:14:21 2012 +1100
+++ b/ChangeLog	Tue Jan 17 14:14:26 2012 +1100
@@ -1,3 +1,5 @@
+ o Automatically skip blank lines followed by unsatisfied conditionals with no
+   else part in list texts
  o Automatically skip lines with only whitespace and directives in list texts
  o Add support for conditionals in list texts
  o Add %wrap% and %wrap W% formatting directives
--- a/include/prepstdreply.h	Tue Jan 17 14:14:21 2012 +1100
+++ b/include/prepstdreply.h	Tue Jan 17 14:14:26 2012 +1100
@@ -60,7 +60,7 @@
 void register_originalmail(text *txt, const char *mailname);
 void register_formatted(text *txt, const char *token,
 		rewind_function rew, get_function get, void * state);
-char *get_processed_text_line(text *txt,
+char *get_processed_text_line(text *txt, int headers,
 		const char *listaddr, const char *listdelim, const char *listdir);
 char *prepstdreply(text *txt, const char *listdir,
 		const char *from, const char *to, const char *replyto);
--- a/src/prepstdreply.c	Tue Jan 17 14:14:21 2012 +1100
+++ b/src/prepstdreply.c	Tue Jan 17 14:14:26 2012 +1100
@@ -716,6 +716,9 @@
 			pos++;
 		}
 	} else {
+		/* We consider nested conditionals as successful while skipping
+		 * text so they don't register themselves as the reason for
+		 * skipping, nor trigger swallowing blank lines */
 		satisfied = 1;
 		pos = token + 1;
 		while (*pos != '\0') pos++;
@@ -743,8 +746,12 @@
 }
 
 
-static void handle_directive(text *txt, char **line_p, char **pos_p,
-		const char *listdir) {
+static int handle_directive(text *txt, char **line_p, char **pos_p,
+		int conditionalsonly, const char *listdir) {
+	/* This function returns 1 to swallow a preceding blank line, i.e. if
+	 * we just finished processing a failed conditional without an else
+	 * part, -1 if we did nothing due to only processing conditionals, and
+	 * 0 otherwise. */
 	char *line = *line_p;
 	char *pos = *pos_p;
 	char *token = pos + 1;
@@ -753,11 +760,13 @@
 	int limit;
 	formatted *fmt;
 	conditional *cond;
+	int swallow;
 
 	endpos = strchr(token, '%');
 	if (endpos == NULL) {
+		if (conditionalsonly) return -1;
 		(*pos_p)++;
-		return;
+		return 0;
 	}
 
 	*pos = '\0';
@@ -766,35 +775,35 @@
 	if(strncmp(token, "ifaction ", 9) == 0) {
 		token += 9;
 		if (handle_conditional(txt, line_p, pos_p, token,
-				0, ACTION, 1, listdir) == 0) return;
+				0, ACTION, 1, listdir) == 0) return 0;
 	} else if(strncmp(token, "ifreason ", 9) == 0) {
 		token += 9;
 		if (handle_conditional(txt, line_p, pos_p, token,
-				0, REASON, 1, listdir) == 0) return;
+				0, REASON, 1, listdir) == 0) return 0;
 	} else if(strncmp(token, "iftype ", 7) == 0) {
 		token += 7;
 		if (handle_conditional(txt, line_p, pos_p, token,
-				0, TYPE, 1, listdir) == 0) return;
+				0, TYPE, 1, listdir) == 0) return 0;
 	} else if(strncmp(token, "ifcontrol ", 10) == 0) {
 		token += 10;
 		if (handle_conditional(txt, line_p, pos_p, token,
-				0, CONTROL, 1, listdir) == 0) return;
+				0, CONTROL, 1, listdir) == 0) return 0;
 	} else if(strncmp(token, "ifnaction ", 10) == 0) {
 		token += 10;
 		if (handle_conditional(txt, line_p, pos_p, token,
-				1, ACTION, 0, listdir) == 0) return;
+				1, ACTION, 0, listdir) == 0) return 0;
 	} else if(strncmp(token, "ifnreason ", 10) == 0) {
 		token += 10;
 		if (handle_conditional(txt, line_p, pos_p, token,
-				1, REASON, 0, listdir) == 0) return;
+				1, REASON, 0, listdir) == 0) return 0;
 	} else if(strncmp(token, "ifntype ", 8) == 0) {
 		token += 8;
 		if (handle_conditional(txt, line_p, pos_p, token,
-				1, TYPE, 0, listdir) == 0) return;
+				1, TYPE, 0, listdir) == 0) return 0;
 	} else if(strncmp(token, "ifncontrol ", 11) == 0) {
 		token += 11;
 		if (handle_conditional(txt, line_p, pos_p, token,
-				1, CONTROL, 1, listdir) == 0) return;
+				1, CONTROL, 1, listdir) == 0) return 0;
 	} else if(strcmp(token, "else") == 0) {
 		if (txt->cond != NULL) {
 			if (txt->skip == txt->cond) txt->skip = NULL;
@@ -804,20 +813,27 @@
 			*pos_p = line + (*pos_p - *line_p);
 			myfree(*line_p);
 			*line_p = line;
-			return;
+			return 0;
 		}
 	} else if(strcmp(token, "endif") == 0) {
 		if (txt->cond != NULL) {
 			if (txt->skip == txt->cond) txt->skip = NULL;
 			cond = txt->cond;
-			txt->cond = txt->cond->outer;
+			swallow = (!cond->satisfied && !cond->elsepart)?1:0;
+			txt->cond = cond->outer;
 			myfree(cond);
 			line = concatstr(2, line, endpos + 1);
 			*pos_p = line + (*pos_p - *line_p);
 			myfree(*line_p);
 			*line_p = line;
-			return;
+			return swallow;
+		}
 		}
+
+	if (conditionalsonly) {
+		*pos = '%';
+		*endpos = '%';
+		return -1;
 	}
 
 	if (txt->skip != NULL) {
@@ -826,7 +842,7 @@
 		*pos = '%';
 		*endpos = '%';
 		(*pos_p)++;
-		return;
+		return 0;
 	}
 
 	if(strcmp(token, "") == 0) {
@@ -834,7 +850,7 @@
 		*pos_p = line + (*pos_p - *line_p) + 1;
 		myfree(*line_p);
 		*line_p = line;
-		return;
+		return 0;
 	} else if(strcmp(token, "^") == 0) {
 		if (txt->src->prefix != NULL) {
 			line[strlen(txt->src->prefix)] = '\0';
@@ -845,7 +861,7 @@
 		*pos_p = line;
 		myfree(*line_p);
 		*line_p = line;
-		return;
+		return 0;
 	} else if(strcmp(token, "comment") == 0 || strcmp(token, "$") == 0 ) {
 		pos = endpos + 1;
 		while (*pos != '\0' && *pos != '\r' && *pos != '\n') pos++;
@@ -853,7 +869,7 @@
 		*pos_p = line + (*pos_p - *line_p);
 		myfree(*line_p);
 		*line_p = line;
-		return;
+		return 0;
 	} else if(strncmp(token, "wrap", 4) == 0) {
 		token += 4;
 		limit = 0;
@@ -872,7 +888,7 @@
 			*pos_p = line + (*pos_p - *line_p);
 			myfree(*line_p);
 			*line_p = line;
-			return;
+			return 0;
 		}
 	} else if(strncmp(token, "control ", 8) == 0) {
 		token = filename_token(token + 8);
@@ -880,7 +896,7 @@
 			filename = concatstr(3, listdir, "/control/", token);
 			begin_new_source_file(txt, line_p, pos_p, filename);
 			myfree(filename);
-			return;
+			return 0;
 		}
 	} else if(strncmp(token, "text ", 5) == 0) {
 		token = filename_token(token + 5);
@@ -888,7 +904,7 @@
 			filename = concatstr(3, listdir, "/text/", token);
 			begin_new_source_file(txt, line_p, pos_p, filename);
 			myfree(filename);
-			return;
+			return 0;
 		}
 	} else if(strncmp(token, "originalmail", 12) == 0 &&
 			txt->mailname != NULL) {
@@ -909,7 +925,7 @@
 			txt->src->transparent = 1;
 			if (limit == -1) txt->src->limit = -1;
 			else txt->src->limit = limit - 1;
-			return;
+			return 0;
 		}
 	}
 	if (token == NULL) {
@@ -918,7 +934,7 @@
 		*pos = '%';
 		*endpos = '%';
 		(*pos_p)++;
-		return;
+		return 0;
 	}
 
 	fmt = txt->fmts;
@@ -926,7 +942,7 @@
 		if (strcmp(token, fmt->token) == 0) {
 			begin_new_formatted_source(txt, line_p, pos_p,
 					endpos + 1, fmt);
-			return;
+			return 0;
 		}
 		fmt = fmt->next;
 	}
@@ -935,11 +951,11 @@
 	*pos = '%';
 	*endpos = '%';
 	(*pos_p)++;
-	return;
+	return 0;
 }
 
 
-char *get_processed_text_line(text *txt,
+char *get_processed_text_line(text *txt, int headers,
 		const char *listaddr, const char *listdelim,
 		const char *listdir)
 {
@@ -951,6 +967,8 @@
 	int incision;
 	size_t len, i;
 	int directive;
+	int peeking = 0; /* for a failed conditional without an else */
+	int swallow;
 
 	for (;;) {
 		while (txt->src != NULL) {
@@ -1036,7 +1054,7 @@
 		directive = 0;
 		while (*pos != '\0') {
 			if (txt->wrapwidth != 0 && len > txt->wrapwidth &&
-					txt->skip == NULL) break;
+					txt->skip == NULL && !peeking) break;
 			if (*pos == '\r') {
 				*pos = '\0';
 				pos++;
@@ -1052,10 +1070,14 @@
 				break;
 			} else if (*pos == ' ') {
 				spc = pos;
+			} else if (*pos == '\t') {
+				/* Avoid breaking due to peeking */
 			} else if (txt->src->transparent) {
 				/* Do nothing if the file is to be included
 			 	 * transparently */
+				if (peeking && txt->skip == NULL) break;
 			} else if (*pos == '$' && txt->skip == NULL) {
+				if (peeking) break;
 				substitute_one(&line, &pos, listaddr,
 						listdelim, listdir, txt);
 				len = pos - line;
@@ -1065,9 +1087,12 @@
 				continue;
 			} else if (*pos == '%') {
 				directive = 1;
-				handle_directive(txt, &line, &pos, listdir);
+				swallow = handle_directive(txt, &line, &pos,
+						peeking, listdir);
 				len = pos - line;
 				spc = NULL;
+				if (swallow == 1) peeking = 0;
+				if (swallow == -1) break;
 				if (txt->skip != NULL) {
 					if (incision == -1) {
 						/* We have to cut a bit out
@@ -1091,6 +1116,8 @@
 				 * character to process, so continue straight
 				 * away. */
 				continue;
+			} else if (peeking && txt->skip == NULL) {
+				break;
 			}
 			len++;
 			pos++;
@@ -1116,7 +1143,7 @@
 			incision = -1;
 		}
 
-		if (txt->wrapwidth != 0) {
+		if (txt->wrapwidth != 0 && !peeking) {
 			if (len <= txt->wrapwidth) {
 				prev = line;
 				continue;
@@ -1158,13 +1185,39 @@
 			tmp = mystrdup(line);
 			myfree(line);
 			line = tmp;
-		} else if (directive) {
+		} else {
+			if (directive) {
 			pos = line;
 			while (*pos == ' ' || *pos == '\t') pos++;
 			if (*pos == '\0') {
-				/* Omit whitespace-only line with directives */
+					/* Omit whitespace-only line with
+					 * directives */
+					myfree(line);
+					continue;
+				}
+			}
+			if (*line == '\0' && !headers && !peeking) {
+				/* Non-wrapped bona fide blank line that isn't
+				 * ending the headers; peek ahead to check it's
+				 * not followed by an unsatisfied conditional
+				 * without an else */
+				peeking = 1;
 				myfree(line);
 				continue;
+			} else if (peeking) {
+				/* We found something; return preceding blank
+				 * line */
+				if (txt->src->upcoming == NULL) {
+					txt->src->upcoming = line;
+				} else {
+					tmp = txt->src->upcoming;
+					txt->src->upcoming = concatstr(3,
+							line, "\n",
+							txt->src->upcoming);
+					myfree(line);
+					myfree(tmp);
+				}
+				line = mystrdup("");
 			}
 		}
 
@@ -1275,7 +1328,7 @@
 	}
 
 	for(;;) {
-		line = get_processed_text_line(txt, listaddr, listdelim,
+		line = get_processed_text_line(txt, 1, listaddr, listdelim,
 				listdir);
 		if (!line) {
 			log_error(LOG_ARGS, "No body in listtext");
@@ -1368,7 +1421,7 @@
 	}
 
 	if (line == NULL) {
-		line = get_processed_text_line(txt, listaddr, listdelim,
+		line = get_processed_text_line(txt, 0, listaddr, listdelim,
 				listdir);
 	}
 	while(line) {
@@ -1382,7 +1435,7 @@
 				goto freeandreturn;
 			}
 		myfree(line);
-		line = get_processed_text_line(txt, listaddr, listdelim,
+		line = get_processed_text_line(txt, 0, listaddr, listdelim,
 				listdir);
 	}
 
--- a/src/send_digest.c	Tue Jan 17 14:14:21 2012 +1100
+++ b/src/send_digest.c	Tue Jan 17 14:14:26 2012 +1100
@@ -307,7 +307,7 @@
 	register_formatted(txt, "digestthreads", rewind_thread_list,
 			get_thread_list_line, tls);
 
-	line = get_processed_text_line(txt, listaddr, listdelim, listdir);
+	line = get_processed_text_line(txt, 1, listaddr, listdelim, listdir);
 
 	if (line == NULL) {
 		log_error(LOG_ARGS, "No content in digest listtext");
@@ -334,7 +334,7 @@
 		myfree(line);
 
 		/* Skip the empty line after the subject */
-		line = get_processed_text_line(txt, listaddr, listdelim,
+		line = get_processed_text_line(txt, 1, listaddr, listdelim,
 				listdir);
 		if (line == NULL || *line != '\0') {
 			log_error(LOG_ARGS, "Too many headers "
@@ -434,7 +434,7 @@
 		myfree(tmp);
 
 		for (;;) {
-			line = get_processed_text_line(txt, listaddr, listdelim,
+			line = get_processed_text_line(txt, 0, listaddr, listdelim,
 					listdir);
 			if (line == NULL) break;
 			len = strlen(line);