degesch: refactor wrap_text()
It wasn't very readable.
This commit is contained in:
parent
6ef472beb2
commit
b2cfbf1501
130
degesch.c
130
degesch.c
@ -2406,90 +2406,92 @@ 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;
|
||||
str_vector_add_owned (output, str_steal (&m));
|
||||
message += eaten;
|
||||
message_left -= eaten;
|
||||
}
|
||||
return true;
|
||||
|
||||
if (!empty)
|
||||
str_vector_add (output, m.str);
|
||||
|
||||
str_free (&m);
|
||||
|
||||
if (!empty)
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
/// Automatically splits messages that arrive at other clients with our prefix
|
||||
/// so that they don't arrive cut off by the server
|
||||
static bool
|
||||
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user