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,89 +2406,91 @@ irc_process_message (const struct irc_message *msg,
|
|||||||
// This is the most basic acceptable algorithm; something like ICU with proper
|
// This is the most basic acceptable algorithm; something like ICU with proper
|
||||||
// locale specification would be needed to make it work better.
|
// 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
|
static bool
|
||||||
wrap_text (const char *message,
|
wrap_message (const char *message,
|
||||||
int line_max, struct str_vector *output, struct error **e)
|
int line_max, struct str_vector *output, struct error **e)
|
||||||
{
|
{
|
||||||
// Initialize to the first word, even if it's empty
|
if (line_max <= 0)
|
||||||
const char *word_end = message + strcspn (message, " ");
|
goto error;
|
||||||
|
|
||||||
for (int message_left = strlen (message); message_left; )
|
for (size_t message_left = strlen (message); message_left; )
|
||||||
{
|
{
|
||||||
struct str m;
|
struct str m;
|
||||||
str_init (&m);
|
str_init (&m);
|
||||||
|
|
||||||
int part_left = MIN (line_max, message_left);
|
size_t eaten = wrap_text_for_single_line (message,
|
||||||
bool empty = true;
|
MIN ((size_t) line_max, message_left), message_left, &m);
|
||||||
|
if (!eaten)
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
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);
|
str_free (&m);
|
||||||
continue;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// And if that doesn't help, cut the longest valid block of characters.
|
str_vector_add_owned (output, str_steal (&m));
|
||||||
// Note that we never get to the end of the word, so "word_end" stays.
|
message += eaten;
|
||||||
while (true)
|
message_left -= eaten;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
if (!empty)
|
error:
|
||||||
str_vector_add (output, m.str);
|
|
||||||
|
|
||||||
str_free (&m);
|
|
||||||
|
|
||||||
if (!empty)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Well, that's just weird
|
// Well, that's just weird
|
||||||
error_set (e,
|
error_set (e,
|
||||||
"Message splitting was unsuccessful as there was "
|
"Message splitting was unsuccessful as there was "
|
||||||
"too little room for UTF-8 characters");
|
"too little room for UTF-8 characters");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
|
|
||||||
/// Automatically splits messages that arrive at other clients with our prefix
|
/// Automatically splits messages that arrive at other clients with our prefix
|
||||||
/// so that they don't arrive cut off by the server
|
/// 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
|
// However we don't always have the full info for message splitting
|
||||||
if (!space_in_one_message)
|
if (!space_in_one_message)
|
||||||
str_vector_add (output, 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 false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user