From b2cfbf1501e5649dd2cf5348aaced0e9a4231cc4 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch <p.janouch@gmail.com>
Date: Sat, 25 Apr 2015 01:34:31 +0200
Subject: degesch: refactor wrap_text()

It wasn't very readable.
---
 degesch.c | 134 +++++++++++++++++++++++++++++++-------------------------------
 1 file changed, 68 insertions(+), 66 deletions(-)

diff --git a/degesch.c b/degesch.c
index d624731..70c6ae0 100644
--- a/degesch.c
+++ b/degesch.c
@@ -2406,89 +2406,91 @@ irc_process_message (const struct irc_message *msg,
 // This is the most basic acceptable algorithm; something like ICU with proper
 // locale specification would be needed to make it work better.
 
-static bool
-wrap_text (const char *message,
-	int line_max, struct str_vector *output, struct error **e)
+static size_t
+wrap_text_for_single_line (const char *text, size_t text_len,
+	size_t line_len, struct str *output)
 {
-	// Initialize to the first word, even if it's empty
-	const char *word_end = message + strcspn (message, " ");
+	int eaten = 0;
 
-	for (int message_left = strlen (message); message_left; )
+	// First try going word by word
+	const char *word_start;
+	const char *word_end = text + strcspn (text, " ");
+	size_t word_len = word_end - text;
+	while (line_len && word_len <= line_len)
 	{
-		struct str m;
-		str_init (&m);
-
-		int part_left = MIN (line_max, message_left);
-		bool empty = true;
-
-		// First try going word by word
-		const char *word_start;
-		int word_len = word_end - message;
-		while (part_left && word_len <= part_left)
+		if (word_len)
 		{
-			if (word_len)
-			{
-				str_append_data (&m, message, word_len);
-				message += word_len;
-				message_left -= word_len;
-				part_left -= word_len;
-				empty = false;
-			}
-
-			// Find the next word's end
-			word_start = message + strspn (message, " ");
-			word_end = word_start + strcspn (word_start, " ");
-			word_len = word_end - message;
+			str_append_data (output, text, word_len);
+
+			text += word_len;
+			eaten += word_len;
+			line_len -= word_len;
 		}
 
-		if (!empty)
-		{
-			// Discard whitespace between words if split
-			message_left -= word_start - message;
-			message = word_start;
+		// Find the next word's end
+		word_start = text + strspn (text, " ");
+		word_end = word_start + strcspn (word_start, " ");
+		word_len = word_end - text;
+	}
 
-			str_vector_add (output, m.str);
-			str_free (&m);
-			continue;
-		}
+	if (eaten)
+		// Discard whitespace between words if split
+		return eaten + (word_start - text);
 
-		// And if that doesn't help, cut the longest valid block of characters.
-		// Note that we never get to the end of the word, so "word_end" stays.
-		while (true)
-		{
-			const char *next = utf8_next (message, message_left);
-			hard_assert (next);
+	// And if that doesn't help, cut the longest valid block of characters
+	while (true)
+	{
+		const char *next = utf8_next (text, text_len - eaten);
+		hard_assert (next);
 
-			int char_len = next - message;
-			if (char_len > part_left)
-				break;
+		size_t char_len = next - text;
+		if (char_len > line_len)
+			break;
 
-			str_append_data (&m, message, char_len);
+		str_append_data (output, text, char_len);
 
-			message += char_len;
-			message_left -= char_len;
-			part_left -= char_len;
-			empty = false;
-		}
+		text += char_len;
+		eaten += char_len;
+		line_len -= char_len;
+	}
+	return eaten;
+}
 
-		if (!empty)
-			str_vector_add (output, m.str);
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
-		str_free (&m);
+static bool
+wrap_message (const char *message,
+	int line_max, struct str_vector *output, struct error **e)
+{
+	if (line_max <= 0)
+		goto error;
 
-		if (!empty)
-			continue;
+	for (size_t message_left = strlen (message); message_left; )
+	{
+		struct str m;
+		str_init (&m);
 
-		// Well, that's just weird
-		error_set (e,
-			"Message splitting was unsuccessful as there was "
-			"too little room for UTF-8 characters");
-		return false;
+		size_t eaten = wrap_text_for_single_line (message,
+			MIN ((size_t) line_max, message_left), message_left, &m);
+		if (!eaten)
+		{
+			str_free (&m);
+			goto error;
+		}
+
+		str_vector_add_owned (output, str_steal (&m));
+		message += eaten;
+		message_left -= eaten;
 	}
 	return true;
-}
 
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+error:
+	// Well, that's just weird
+	error_set (e,
+		"Message splitting was unsuccessful as there was "
+		"too little room for UTF-8 characters");
+	return false;
+}
 
 /// Automatically splits messages that arrive at other clients with our prefix
 /// so that they don't arrive cut off by the server
@@ -2507,7 +2509,7 @@ irc_autosplit_message (struct app_context *ctx, const char *message,
 	// However we don't always have the full info for message splitting
 	if (!space_in_one_message)
 		str_vector_add (output, message);
-	else if (!wrap_text (message, space_in_one_message, output, e))
+	else if (!wrap_message (message, space_in_one_message, output, e))
 		return false;
 	return true;
 }
-- 
cgit v1.2.3-70-g09d2