degesch: refactor wrap_text()

It wasn't very readable.
This commit is contained in:
Přemysl Eric Janouch 2015-04-25 01:34:31 +02:00
parent 6ef472beb2
commit b2cfbf1501
1 changed files with 71 additions and 69 deletions

140
degesch.c
View File

@ -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 size_t
wrap_text_for_single_line (const char *text, size_t text_len,
size_t line_len, struct str *output)
{
int eaten = 0;
// 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)
{
if (word_len)
{
str_append_data (output, text, word_len);
text += word_len;
eaten += word_len;
line_len -= word_len;
}
// Find the next word's end
word_start = text + strspn (text, " ");
word_end = word_start + strcspn (word_start, " ");
word_len = word_end - text;
}
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
while (true)
{
const char *next = utf8_next (text, text_len - eaten);
hard_assert (next);
size_t char_len = next - text;
if (char_len > line_len)
break;
str_append_data (output, text, char_len);
text += char_len;
eaten += char_len;
line_len -= char_len;
}
return eaten;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static bool
wrap_text (const char *message,
wrap_message (const char *message,
int line_max, struct str_vector *output, struct error **e)
{
// Initialize to the first word, even if it's empty
const char *word_end = message + strcspn (message, " ");
if (line_max <= 0)
goto error;
for (int message_left = strlen (message); message_left; )
for (size_t message_left = strlen (message); message_left; )
{
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)
size_t eaten = wrap_text_for_single_line (message,
MIN ((size_t) line_max, message_left), message_left, &m);
if (!eaten)
{
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;
}
if (!empty)
{
// Discard whitespace between words if split
message_left -= word_start - message;
message = word_start;
str_vector_add (output, m.str);
str_free (&m);
continue;
goto error;
}
// 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);
int char_len = next - message;
if (char_len > part_left)
break;
str_append_data (&m, message, char_len);
message += char_len;
message_left -= char_len;
part_left -= char_len;
empty = false;
}
if (!empty)
str_vector_add (output, m.str);
str_free (&m);
if (!empty)
continue;
// Well, that's just weird
error_set (e,
"Message splitting was unsuccessful as there was "
"too little room for UTF-8 characters");
return false;
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;
}