From ac3911ffe3f86b27a6ae7a3b9fe09ae222fea165 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 13 Nov 2021 10:07:53 -0600 Subject: [PATCH] Bugfix: The print safely functions are not fully UTF-8 aware. The f_print_character_safely_get() can only handle a single byte. This makes it impossible to be UTF-8 aware. Provide a new function f_print_safely_get() that accepts a string and a max width. This string is intended to represent a single character, but can be multi-byte based on max width. This function checks to see if the character is invalid or a control character, in which case it is replaced. --- level_0/f_print/c/print.c | 138 ++++++++++------------------------- level_0/f_print/c/print.h | 32 ++++++++ level_0/f_print/c/print_to.c | 130 ++++++++------------------------- level_0/f_print/c/private-print.c | 119 +++++++++--------------------- level_0/f_print/c/private-print.h | 42 +++++++++++ level_0/f_print/c/private-print_to.c | 126 ++++++-------------------------- 6 files changed, 202 insertions(+), 385 deletions(-) diff --git a/level_0/f_print/c/print.c b/level_0/f_print/c/print.c index 53bec2c..e8cc5c6 100644 --- a/level_0/f_print/c/print.c +++ b/level_0/f_print/c/print.c @@ -51,7 +51,7 @@ extern "C" { } else if (macro_f_utf_character_t_width_is(character) > 1 || character > 0x1f) { if (fwrite_unlocked(&character, 1, 1, output) != -1) { - return F_none; + return F_utf; } } else { @@ -491,6 +491,12 @@ extern "C" { } #endif // _di_f_print_safely_ +#ifndef _di_f_print_safely_get_ + f_string_t f_print_safely_get(const f_string_t character, const f_array_length_t width_max) { + return private_f_print_safely_get(character, width_max); + } +#endif // _di_f_print_safely_get_ + #ifndef _di_f_print_safely_terminated_ f_status_t f_print_safely_terminated(const f_string_t string, FILE *output) { #ifndef _di_level_0_parameter_checking_ @@ -501,8 +507,6 @@ extern "C" { return F_data_not; } - f_status_t status = F_none; - f_array_length_t start = 0; f_array_length_t total = 0; @@ -512,133 +516,67 @@ extern "C" { for (register f_array_length_t i = 0; string[i]; ) { - width = macro_f_utf_character_t_width_is(string[i]); - - if (width) { - if (width > 1) { - if (string[i + 1]) { - if (width > 2) { - if (string[i + 2]) { - if (width > 3) { - if (string[i + 3]) { - status = f_utf_is_control(string + i, 4); - } - else { - status = F_utf; - } - } - else { - status = f_utf_is_control(string + i, 3); + safe = 0; + width = macro_f_utf_character_t_width(string[i]); + + if (width > 1) { + if (string[i + 1]) { + if (width > 2) { + if (string[i + 2]) { + if (width > 3) { + if (!string[i + 3]) { + safe = (f_string_t) f_print_sequence_unknown_s; } } - else { - status = F_utf; - } } else { - status = f_utf_is_control(string + i, 2); + safe = (f_string_t) f_print_sequence_unknown_s; } } - else { - status = F_utf; - } } else { - status = f_utf_is_control(string + i, 1); - } - - if (status == F_false && total + width < F_print_write_max_d) { - total += width; - i += width; - - continue; + safe = (f_string_t) f_print_sequence_unknown_s; } } - else { - if ((string[i] > 0x1f && string[i] != 0x7f) && total < F_print_write_max_d) { - ++total; - ++i; - continue; - } - - status = F_none; + if (!safe) { + safe = private_f_print_safely_get(string + i, width); } - if (total) { - if (fwrite_unlocked(string + start, 1, total, output) == -1) { - return F_status_set_error(F_output); - } - - total = 0; - } + if (safe) { + if (total) { + if (fwrite_unlocked(string + start, 1, total, output) == -1) { + return F_status_set_error(F_output); + } - if (status == F_true || F_status_set_fine(status) == F_utf) { - if (fwrite_unlocked(f_print_sequence_unknown_s, 1, 3, output) != -1) { - return F_status_set_error(F_output); + total = 0; } - for (start = 0; string[start] && start < width; ) { - ++start; - } // while - - if (start != width) break; - - i += width; - } - else if (status == F_false) { - if (fwrite_unlocked(string + start, 1, width, output) == -1) { + if (fwrite_unlocked(safe, 1, 3, output) == -1) { return F_status_set_error(F_output); } - for (start = 0; string[start] && start < width; ) { - ++start; - } // while - - if (start != width) break; - i += width; + start = i; + continue; } - else { - safe = private_f_print_character_safely_get(string[i]); - if (safe) { - if (fwrite_unlocked(safe, 1, 3, output) == -1) { + if (total + width >= F_print_write_max_d) { + if (total) { + if (fwrite_unlocked(string + start, 1, total, output) == -1) { return F_status_set_error(F_output); } - } - else { - status = f_utf_is_valid(string + i, width); - - if (F_status_is_error(status) || status == F_false) { - if (fwrite_unlocked(f_print_sequence_unknown_s, 1, 3, output) == -1) { - return F_status_set_error(F_output); - } - - for (start = 0; string[start] && start < width; ) { - ++start; - } // while - if (start != width) break; - } - else { - for (start = 0; string[start] && start < width; ) { - ++start; - } // while - - if (start != width) break; - - total = width; - start = i; - i += width; - continue; - } + total = 0; } i += width; + start = i - 1; + continue; } - start = i; + total += width; + i += width; } // for if (total) { diff --git a/level_0/f_print/c/print.h b/level_0/f_print/c/print.h index 23799cb..480df70 100644 --- a/level_0/f_print/c/print.h +++ b/level_0/f_print/c/print.h @@ -95,6 +95,9 @@ extern "C" { * UTF-8 sequences with invalid widths are converted to the unknown character '�'. * This can result in the 1-byte character being substituted with a 3-byte character when printing. * + * For UTF-8 characters, this cannot detect if the UTF-8 character is a control or anything else. + * This is, in genereal, not safe for printing UTF-8 characters given that a character is 1-byte. + * * This should only be called for the first 1-byte character of a multibyte character. * * @param character @@ -104,6 +107,7 @@ extern "C" { * * @return * F_none on success. + * F_utf on success, but character is a UTF-8 character. * F_data_not if there is nothing to print. * * F_output (with error bit) on failure. @@ -1094,6 +1098,34 @@ extern "C" { #endif // _di_f_print_safely_ /** + * Get a safe representation of the character if the character is considered unsafe. + * + * Control characters are converted to the Unicode control character symbols, including NULL. + * UTF-8 sequences with a width of 1 are converted to the unknown character '�'. + * For all other UTF-8 sequences, 0 is returned because it cannot be processed via a single 8-byte character. + * + * The returned string will either be NULL (for characters that are already safe) or a string representing the replacement. + * This can result in a 3-byte character being returned as a string of 3 1-bytes. + * + * This should only be called for the first 1-byte character of a multibyte character. + * + * @param character + * The character to verify as safe or not and then print. + * @param width_max + * This is set to the max number of bytes available. + * This is then updated to represent the max bytes used if enough space is available. + * + * @return + * NULL is returned if the character is already safe or if the character has a UTF-8 width of 2 or greater. + * A non-NULL string is returned if the character needs safe replacement. + * The non-NULL strings returned are NULL terminated. + * The non-NULL strings returned are the 3-byte characters used as placeholder symbols. + */ +#ifndef _di_f_print_safely_get_ + extern f_string_t f_print_safely_get(const f_string_t character, const f_array_length_t width_max); +#endif // _di_f_print_safely_get_ + +/** * Similar to a c-library printf. * * Control characters are converted to the Unicode control character symbols, excluding NULL. diff --git a/level_0/f_print/c/print_to.c b/level_0/f_print/c/print_to.c index fab6fa8..e29f189 100644 --- a/level_0/f_print/c/print_to.c +++ b/level_0/f_print/c/print_to.c @@ -506,8 +506,6 @@ static inline f_status_t private_inline_f_print_to_error() { return F_data_not; } - f_status_t status = F_none; - f_array_length_t start = 0; f_array_length_t total = 0; @@ -517,133 +515,67 @@ static inline f_status_t private_inline_f_print_to_error() { for (register f_array_length_t i = 0; string[i]; ) { - width = macro_f_utf_character_t_width_is(string[i]); - - if (width) { - if (width > 1) { - if (string[i + 1]) { - if (width > 2) { - if (string[i + 2]) { - if (width > 3) { - if (string[i + 3]) { - status = f_utf_is_control(string + i, 4); - } - else { - status = F_utf; - } - } - else { - status = f_utf_is_control(string + i, 3); + safe = 0; + width = macro_f_utf_character_t_width(string[i]); + + if (width > 1) { + if (string[i + 1]) { + if (width > 2) { + if (string[i + 2]) { + if (width > 3) { + if (!string[i + 3]) { + safe = (f_string_t) f_print_sequence_unknown_s; } } - else { - status = F_utf; - } } else { - status = f_utf_is_control(string + i, 2); + safe = (f_string_t) f_print_sequence_unknown_s; } } - else { - status = F_utf; - } } else { - status = f_utf_is_control(string + i, 1); - } - - if (status == F_false && total + width < F_print_write_max_d) { - total += width; - i += width; - - continue; + safe = (f_string_t) f_print_sequence_unknown_s; } } - else { - if ((string[i] > 0x1f && string[i] != 0x7f) && total < F_print_write_max_d) { - ++total; - ++i; - continue; - } - - status = F_none; + if (!safe) { + safe = private_f_print_safely_get(string + i, width); } - if (total) { - if (write(id, string + start, total) == -1) { - return private_inline_f_print_to_error(); - } - - total = 0; - } + if (safe) { + if (total) { + if (write(id, string + start, total) == -1) { + return private_inline_f_print_to_error(); + } - if (status == F_true || F_status_set_fine(status) == F_utf) { - if (write(id, f_print_sequence_unknown_s, 3) == -1) { - return private_inline_f_print_to_error(); + total = 0; } - for (start = 0; string[start] && start < width; ) { - ++start; - } // while - - if (start != width) break; - - i += width; - } - else if (status == F_false) { - if (write(id, string + start, width) == -1) { + if (write(id, safe, 3) == -1) { return private_inline_f_print_to_error(); } - for (start = 0; string[start] && start < width; ) { - ++start; - } // while - - if (start != width) break; - i += width; + start = i; + continue; } - else { - safe = private_f_print_character_safely_get(string[i]); - if (safe) { - if (write(id, safe, 3) == -1) { + if (total + width >= F_print_write_max_d) { + if (total) { + if (write(id, string + start, total) == -1) { return private_inline_f_print_to_error(); } - } - else { - status = f_utf_is_valid(string + i, width); - - if (F_status_is_error(status) || status == F_false) { - if (write(id, f_print_sequence_unknown_s, 3) == -1) { - return private_inline_f_print_to_error(); - } - - for (start = 0; string[start] && start < width; ) { - ++start; - } // while - - if (start != width) break; - } - else { - for (start = 0; string[start] && start < width; ) { - ++start; - } // while - if (start != width) break; - - total = width; - start = i; - i += width; - continue; - } + total = 0; } i += width; + start = i - 1; + continue; } - start = i; + total += width; + i += width; } // for if (total) { diff --git a/level_0/f_print/c/private-print.c b/level_0/f_print/c/private-print.c index 393124b..8251c4f 100644 --- a/level_0/f_print/c/private-print.c +++ b/level_0/f_print/c/private-print.c @@ -44,10 +44,12 @@ extern "C" { if (character == 0x7f) { return (f_string_t) f_print_sequence_delete_s; } - else if (macro_f_utf_character_t_width_is(character) == 1) { + + if (macro_f_utf_character_t_width_is(character) == 1) { return (f_string_t) f_print_sequence_unknown_s; } - else if (macro_f_utf_character_t_width_is(character) > 1 || character > 0x1f) { + + if (macro_f_utf_character_t_width_is(character) > 1 || character > 0x1f) { return 0; } @@ -302,7 +304,9 @@ extern "C" { } if (string[i]) { - safe = private_f_print_character_safely_get(string[i]); + width = macro_f_utf_character_t_width(string[i]); + + safe = private_f_print_safely_get(string + i, width); } else { if (total) { @@ -317,8 +321,6 @@ extern "C" { continue; } - width = macro_f_utf_character_t_width(string[i]); - if (safe) { if (total) { if (fwrite_unlocked(string + start, 1, total, output) == -1) { @@ -337,33 +339,6 @@ extern "C" { continue; } - status = f_utf_is_valid(string + i, width); - - if (F_status_is_error(status) || status == F_false || i + width >= stop) { - if (total) { - if (fwrite_unlocked(string + start, 1, total, output) == -1) { - return F_status_set_error(F_output); - } - - total = 0; - } - - if (fwrite_unlocked(f_print_sequence_unknown_s, 1, 3, output) == -1) { - return F_status_set_error(F_output); - } - - if (F_status_is_error(status) || status == F_false) { - i += width; - start = i; - } - else { - i = stop; - start = stop; - } - - continue; - } - if (total + width >= F_print_write_max_d) { if (fwrite_unlocked(string + start, 1, total, output) == -1) { return F_status_set_error(F_output); @@ -469,7 +444,9 @@ extern "C" { } if (string[i]) { - safe = private_f_print_character_safely_get(string[i]); + width = macro_f_utf_character_t_width(string[i]); + + safe = private_f_print_safely_get(string + i, width); } else { if (total) { @@ -504,33 +481,6 @@ extern "C" { continue; } - status = f_utf_is_valid(string + i, width); - - if (F_status_is_error(status) || status == F_false || i + width >= stop) { - if (total) { - if (fwrite_unlocked(string + start, 1, total, output) == -1) { - return F_status_set_error(F_output); - } - - total = 0; - } - - if (fwrite_unlocked(f_print_sequence_unknown_s, 1, 3, output) == -1) { - return F_status_set_error(F_output); - } - - if (F_status_is_error(status) || status == F_false) { - i += width; - start = i; - } - else { - i = stop; - start = stop; - } - - continue; - } - if (total + width >= F_print_write_max_d) { if (fwrite_unlocked(string + start, 1, total, output) == -1) { return F_status_set_error(F_output); @@ -607,7 +557,9 @@ extern "C" { while (i < length) { if (string[i]) { - safe = private_f_print_character_safely_get(string[i]); + width = macro_f_utf_character_t_width(string[i]); + + safe = private_f_print_safely_get(string + i, width); } else { if (total) { @@ -622,8 +574,6 @@ extern "C" { continue; } - width = macro_f_utf_character_t_width(string[i]); - if (safe) { if (total) { if (fwrite_unlocked(string + start, 1, total, output) == -1) { @@ -642,26 +592,6 @@ extern "C" { continue; } - status = f_utf_is_valid(string + i, width); - - if (F_status_is_error(status) || status == F_false) { - if (total) { - if (fwrite_unlocked(string + start, 1, total, output) == -1) { - return F_status_set_error(F_output); - } - - total = 0; - } - - if (fwrite_unlocked(f_print_sequence_unknown_s, 1, 3, output) == -1) { - return F_status_set_error(F_output); - } - - i += width; - start = i; - continue; - } - if (total + width >= F_print_write_max_d) { if (fwrite_unlocked(string + start, 1, total, output) == -1) { return F_status_set_error(F_output); @@ -685,6 +615,29 @@ extern "C" { } #endif // !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_dynamic_) || !defined(_di_f_print_safely_dynamic_partial_) +#if !defined(_di_f_print_character_safely_get_) || !defined(_di_f_print_dynamic_partial_safely_) || !defined(_di_f_print_dynamic_safely_) || !defined(_di_f_print_except_dynamic_partial_safely_) || !defined(_di_f_print_except_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_partial_safely_) || !defined(_di_f_print_except_in_safely_) || !defined(_di_f_print_except_safely_) || !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_terminated_) || !defined(_di_f_print_to_dynamic_partial_safely_) || !defined(_di_f_print_to_dynamic_safely_) || !defined(_di_f_print_to_except_dynamic_partial_safely_) || !defined(_di_f_print_to_except_dynamic_safely_) || !defined(_di_f_print_to_except_in_dynamic_safely_) || !defined(_di_f_print_to_except_in_dynamic_partial_safely_) || !defined(_di_f_print_to_except_in_safely_) || !defined(_di_f_print_to_except_safely_) || !defined(_di_f_print_to_safely_) + f_string_t private_f_print_safely_get(const f_string_t character, const f_array_length_t width_max) { + + if (character[0] == 0x7f) { + return (f_string_t) f_print_sequence_delete_s; + } + + if (macro_f_utf_character_t_width_is(character[0])) { + if (f_utf_is_valid(character, width_max) != F_true || f_utf_is_control(character, width_max)) { + return (f_string_t) f_print_sequence_unknown_s; + } + + return 0; + } + + if (character[0] > 0x1f) { + return 0; + } + + return (f_string_t) f_print_sequence_set_control_s[character[0]]; + } +#endif // !defined(_di_f_print_character_safely_get_) || !defined(_di_f_print_dynamic_partial_safely_) || !defined(_di_f_print_dynamic_safely_) || !defined(_di_f_print_except_dynamic_partial_safely_) || !defined(_di_f_print_except_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_partial_safely_) || !defined(_di_f_print_except_in_safely_) || !defined(_di_f_print_except_safely_) || !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_terminated_) || !defined(_di_f_print_to_dynamic_partial_safely_) || !defined(_di_f_print_to_dynamic_safely_) || !defined(_di_f_print_to_except_dynamic_partial_safely_) || !defined(_di_f_print_to_except_dynamic_safely_) || !defined(_di_f_print_to_except_in_dynamic_safely_) || !defined(_di_f_print_to_except_in_dynamic_partial_safely_) || !defined(_di_f_print_to_except_in_safely_) || !defined(_di_f_print_to_except_safely_) || !defined(_di_f_print_to_safely_) + #if !defined(_di_f_print_terminated_) || !defined(_di_f_print_raw_terminated_) f_status_t private_f_print_terminated(const f_string_t string, FILE *output) { diff --git a/level_0/f_print/c/private-print.h b/level_0/f_print/c/private-print.h index 6a53edc..f3752e6 100644 --- a/level_0/f_print/c/private-print.h +++ b/level_0/f_print/c/private-print.h @@ -393,6 +393,48 @@ extern "C" { #endif // !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_dynamic_) || !defined(_di_f_print_safely_dynamic_partial_) /** + * Private implementation of f_print_safely_get(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param character + * A string representing an ASCII or a UTF-8 character to get safe representation. + * @param width_max + * This is set to the max number of bytes available. + * This is then updated to represent the max bytes used if enough space is available. + * + * @return + * NULL is returned if the character is already safe. + * A non-NULL string is returned if the character needs safe replacement. + * The non-NULL strings returned are NULL terminated. + * The non-NULL strings returned are the 3-byte characters used as placeholder symbols. + * + * @see f_print_character_safely_get() + * @see f_print_dynamic_partial_safely() + * @see f_print_dynamic_safely() + * @see f_print_except_dynamic_partial_safely() + * @see f_print_except_dynamic_safely() + * @see f_print_except_in_dynamic_safely() + * @see f_print_except_in_dynamic_partial_safely() + * @see f_print_except_in_safely_ + * @see f_print_except_safely() + * @see f_print_safely() + * @see f_print_safely_terminated() + * @see f_print_to_dynamic_partial_safely() + * @see f_print_to_dynamic_safely() + * @see f_print_to_except_dynamic_partial_safely() + * @see f_print_to_except_dynamic_safely() + * @see f_print_to_except_in_dynamic_safely() + * @see f_print_to_except_in_dynamic_partial_safely() + * @see f_print_to_except_in_safely_ + * @see f_print_to_except_safely() + * @see f_print_to_safely() + */ +#if !defined(_di_f_print_character_safely_get_) || !defined(_di_f_print_dynamic_partial_safely_) || !defined(_di_f_print_dynamic_safely_) || !defined(_di_f_print_except_dynamic_partial_safely_) || !defined(_di_f_print_except_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_partial_safely_) || !defined(_di_f_print_except_in_safely_) || !defined(_di_f_print_except_safely_) || !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_terminated_) || !defined(_di_f_print_to_dynamic_partial_safely_) || !defined(_di_f_print_to_dynamic_safely_) || !defined(_di_f_print_to_except_dynamic_partial_safely_) || !defined(_di_f_print_to_except_dynamic_safely_) || !defined(_di_f_print_to_except_in_dynamic_safely_) || !defined(_di_f_print_to_except_in_dynamic_partial_safely_) || !defined(_di_f_print_to_except_in_safely_) || !defined(_di_f_print_to_except_safely_) || !defined(_di_f_print_to_safely_) + extern f_string_t private_f_print_safely_get(const f_string_t character, const f_array_length_t width_max) F_attribute_visibility_internal_d; +#endif // !defined(_di_f_print_character_safely_get_) || !defined(_di_f_print_dynamic_partial_safely_) || !defined(_di_f_print_dynamic_safely_) || !defined(_di_f_print_except_dynamic_partial_safely_) || !defined(_di_f_print_except_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_partial_safely_) || !defined(_di_f_print_except_in_safely_) || !defined(_di_f_print_except_safely_) || !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_terminated_) || !defined(_di_f_print_to_dynamic_partial_safely_) || !defined(_di_f_print_to_dynamic_safely_) || !defined(_di_f_print_to_except_dynamic_partial_safely_) || !defined(_di_f_print_to_except_dynamic_safely_) || !defined(_di_f_print_to_except_in_dynamic_safely_) || !defined(_di_f_print_to_except_in_dynamic_partial_safely_) || !defined(_di_f_print_to_except_in_safely_) || !defined(_di_f_print_to_except_safely_) || !defined(_di_f_print_to_safely_) + +/** * Private implementation of f_print_terminated(). * * Intended to be shared to each of the different implementation variations. diff --git a/level_0/f_print/c/private-print_to.c b/level_0/f_print/c/private-print_to.c index 00c81ce..c2d309d 100644 --- a/level_0/f_print/c/private-print_to.c +++ b/level_0/f_print/c/private-print_to.c @@ -215,7 +215,9 @@ static inline f_status_t private_inline_f_print_to_error() { } if (string[i]) { - safe = private_f_print_character_safely_get(string[i]); + width = macro_f_utf_character_t_width(string[i]); + + safe = private_f_print_safely_get(string + i, width); } else { if (total) { @@ -247,39 +249,7 @@ static inline f_status_t private_inline_f_print_to_error() { continue; } - width = macro_f_utf_character_t_width(string[i]); - - status = f_utf_is_valid(string + i, width); - - if (F_status_is_error(status) || status == F_false || i + width >= stop) { - if (total) { - if (write(id, string + start, total) == -1) { - return private_inline_f_print_to_error(); - } - - total = 0; - } - - if (write(id, f_print_sequence_unknown_s, 3) == -1) { - return private_inline_f_print_to_error(); - } - - if (F_status_is_error(status) || status == F_false) { - i += width; - start = i; - } - else { - i = stop; - start = stop; - } - - continue; - } - - total += width; - i += width; - - if (total >= F_print_write_max_d) { + if (total + width >= F_print_write_max_d) { if (write(id, string + start, total) == -1) { return private_inline_f_print_to_error(); } @@ -287,6 +257,9 @@ static inline f_status_t private_inline_f_print_to_error() { total = 0; start = i; } + + total += width; + i += width; } // while if (total) { @@ -495,7 +468,9 @@ static inline f_status_t private_inline_f_print_to_error() { } if (string[i]) { - safe = private_f_print_character_safely_get(string[i]); + width = macro_f_utf_character_t_width(string[i]); + + safe = private_f_print_safely_get(string + i, width); } else { if (total) { @@ -527,39 +502,7 @@ static inline f_status_t private_inline_f_print_to_error() { continue; } - width = macro_f_utf_character_t_width(string[i]); - - status = f_utf_is_valid(string + i, width); - - if (F_status_is_error(status) || status == F_false || i + width >= stop) { - if (total) { - if (write(id, string + start, total) == -1) { - return private_inline_f_print_to_error(); - } - - total = 0; - } - - if (write(id, f_print_sequence_unknown_s, 3) == -1) { - return private_inline_f_print_to_error(); - } - - if (F_status_is_error(status) || status == F_false) { - i += width; - start = i; - } - else { - i = stop; - start = stop; - } - - continue; - } - - total += width; - i += width; - - if (total >= F_print_write_max_d) { + if (total + width >= F_print_write_max_d) { if (write(id, string + start, total) == -1) { return private_inline_f_print_to_error(); } @@ -567,6 +510,9 @@ static inline f_status_t private_inline_f_print_to_error() { total = 0; start = i; } + + total += width; + i += width; } // while if (total) { @@ -638,7 +584,9 @@ static inline f_status_t private_inline_f_print_to_error() { while (i < length) { if (string[i]) { - safe = private_f_print_character_safely_get(string[i]); + width = macro_f_utf_character_t_width(string[i]); + + safe = private_f_print_safely_get(string + i, width); } else { if (total) { @@ -666,43 +614,12 @@ static inline f_status_t private_inline_f_print_to_error() { return private_inline_f_print_to_error(); } - start = ++i; - continue; - } - - width = macro_f_utf_character_t_width(string[i]); - - status = f_utf_is_valid(string + i, width); - - if (F_status_is_error(status) || status == F_false || i + width >= length) { - if (total) { - if (write(id, string + start, total) == -1) { - return private_inline_f_print_to_error(); - } - - total = 0; - } - - if (write(id, f_print_sequence_unknown_s, 3) == -1) { - return private_inline_f_print_to_error(); - } - - if (F_status_is_error(status) || status == F_false) { - i += width; - start = i; - } - else { - i = length; - start = length; - } - + i += width; + start = i; continue; } - total += width; - i += width; - - if (total >= F_print_write_max_d) { + if (total + width >= F_print_write_max_d) { if (write(id, string + start, total) == -1) { return private_inline_f_print_to_error(); } @@ -710,6 +627,9 @@ static inline f_status_t private_inline_f_print_to_error() { total = 0; start = i; } + + total += width; + i += width; } // while if (total) { -- 1.8.3.1