From: Kevin Day Date: Mon, 1 Jun 2026 01:36:43 +0000 (-0500) Subject: Progress: Begin fixing combining logic. X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=2ae1417923b29380d5904d1f6e23d3d51720916f;p=fll Progress: Begin fixing combining logic. Have to add is_combining functions to detect combining for the purpose of FSS processing. Skip past initial place holders in the skip functions. The initial combining returns `F_complete_not_utf_start` only for combining at the start. This should be then handled as a combining. Begin adding the unit tests. These should fail because the functionality that they are testing is not implemented. What needs to be done next is to have all FSS processing code look past the special characters (except new lines). Check for combining characters. --- diff --git a/build/disable/level_0/f_fss.h b/build/disable/level_0/f_fss.h index 14f5006c9..85066c34a 100644 --- a/build/disable/level_0/f_fss.h +++ b/build/disable/level_0/f_fss.h @@ -99,6 +99,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +#define _di_f_fss_skip_past_combining_ #define _di_f_fss_skip_past_delimit_ #define _di_f_fss_skip_past_space_ #define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fake.config.h b/build/stand_alone/fake.config.h index 5ce2c9a31..b46bdac3b 100644 --- a/build/stand_alone/fake.config.h +++ b/build/stand_alone/fake.config.h @@ -657,6 +657,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_identify.config.h b/build/stand_alone/fss_identify.config.h index 88702454b..3f5173698 100644 --- a/build/stand_alone/fss_identify.config.h +++ b/build/stand_alone/fss_identify.config.h @@ -510,6 +510,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +#define _di_f_fss_skip_past_combining_ #define _di_f_fss_skip_past_delimit_ #define _di_f_fss_skip_past_space_ #define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_read.config.fss_basic.h b/build/stand_alone/fss_read.config.fss_basic.h index 7b1627bab..9e124ed1a 100644 --- a/build/stand_alone/fss_read.config.fss_basic.h +++ b/build/stand_alone/fss_read.config.fss_basic.h @@ -567,6 +567,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_read.config.fss_basic_list.h b/build/stand_alone/fss_read.config.fss_basic_list.h index 6a2ee483a..bd7f0fc7e 100644 --- a/build/stand_alone/fss_read.config.fss_basic_list.h +++ b/build/stand_alone/fss_read.config.fss_basic_list.h @@ -567,6 +567,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_read.config.fss_embedded_list.h b/build/stand_alone/fss_read.config.fss_embedded_list.h index d4c26f7a9..3d38aca46 100644 --- a/build/stand_alone/fss_read.config.fss_embedded_list.h +++ b/build/stand_alone/fss_read.config.fss_embedded_list.h @@ -567,6 +567,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_read.config.fss_extended.h b/build/stand_alone/fss_read.config.fss_extended.h index 86f6837d7..b239ec1f7 100644 --- a/build/stand_alone/fss_read.config.fss_extended.h +++ b/build/stand_alone/fss_read.config.fss_extended.h @@ -567,6 +567,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_read.config.fss_extended_list.h b/build/stand_alone/fss_read.config.fss_extended_list.h index d0039047e..a8335c2ed 100644 --- a/build/stand_alone/fss_read.config.fss_extended_list.h +++ b/build/stand_alone/fss_read.config.fss_extended_list.h @@ -567,6 +567,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_read.config.fss_payload.h b/build/stand_alone/fss_read.config.fss_payload.h index 11f175548..42a5cc82d 100644 --- a/build/stand_alone/fss_read.config.fss_payload.h +++ b/build/stand_alone/fss_read.config.fss_payload.h @@ -567,6 +567,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_read.config.h b/build/stand_alone/fss_read.config.h index f50d6f853..56bdc1fb6 100644 --- a/build/stand_alone/fss_read.config.h +++ b/build/stand_alone/fss_read.config.h @@ -567,6 +567,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_write.config.fss_basic.h b/build/stand_alone/fss_write.config.fss_basic.h index 26846825a..db7d584e0 100644 --- a/build/stand_alone/fss_write.config.fss_basic.h +++ b/build/stand_alone/fss_write.config.fss_basic.h @@ -510,6 +510,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_write.config.fss_basic_list.h b/build/stand_alone/fss_write.config.fss_basic_list.h index 40fb24fa9..f598c2f94 100644 --- a/build/stand_alone/fss_write.config.fss_basic_list.h +++ b/build/stand_alone/fss_write.config.fss_basic_list.h @@ -510,6 +510,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_write.config.fss_embedded_list.h b/build/stand_alone/fss_write.config.fss_embedded_list.h index 86419a0dd..3dfc7f063 100644 --- a/build/stand_alone/fss_write.config.fss_embedded_list.h +++ b/build/stand_alone/fss_write.config.fss_embedded_list.h @@ -510,6 +510,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_write.config.fss_extended.h b/build/stand_alone/fss_write.config.fss_extended.h index 5a56a2293..53d812ab2 100644 --- a/build/stand_alone/fss_write.config.fss_extended.h +++ b/build/stand_alone/fss_write.config.fss_extended.h @@ -510,6 +510,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_write.config.fss_extended_list.h b/build/stand_alone/fss_write.config.fss_extended_list.h index 41088a876..62643ec1f 100644 --- a/build/stand_alone/fss_write.config.fss_extended_list.h +++ b/build/stand_alone/fss_write.config.fss_extended_list.h @@ -510,6 +510,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_write.config.fss_payload.h b/build/stand_alone/fss_write.config.fss_payload.h index 6bdfa83bd..f00bd1808 100644 --- a/build/stand_alone/fss_write.config.fss_payload.h +++ b/build/stand_alone/fss_write.config.fss_payload.h @@ -510,6 +510,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/fss_write.config.h b/build/stand_alone/fss_write.config.h index ed889622e..b0bcd7b48 100644 --- a/build/stand_alone/fss_write.config.h +++ b/build/stand_alone/fss_write.config.h @@ -510,6 +510,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +//#define _di_f_fss_skip_past_combining_ //#define _di_f_fss_skip_past_delimit_ //#define _di_f_fss_skip_past_space_ //#define _di_f_fss_state_flag_e_ diff --git a/build/stand_alone/status_code.config.fss.h b/build/stand_alone/status_code.config.fss.h index 7094cfeab..570caf4fa 100644 --- a/build/stand_alone/status_code.config.fss.h +++ b/build/stand_alone/status_code.config.fss.h @@ -510,6 +510,7 @@ #define _di_f_fss_simple_packetss_delete_callback_ #define _di_f_fss_simple_packetss_destroy_callback_ #define _di_f_fss_simple_packetss_t_ +#define _di_f_fss_skip_past_combining_ #define _di_f_fss_skip_past_delimit_ #define _di_f_fss_skip_past_space_ #define _di_f_fss_state_flag_e_ diff --git a/level_0/f_fss/c/fss.c b/level_0/f_fss/c/fss.c index 3bf7cda93..df7bff748 100644 --- a/level_0/f_fss/c/fss.c +++ b/level_0/f_fss/c/fss.c @@ -311,6 +311,127 @@ extern "C" { } #endif // _di_f_fss_seek_to_eol_ +#ifndef _di_f_fss_skip_past_combining_ + void f_fss_skip_past_combining(const f_string_static_t buffer, f_range_t * const range, f_state_t * const state) { + #ifndef _di_level_0_parameter_checking_ + if (!state) return; + + if (!range) { + state->status = F_status_set_error(F_parameter); + + return; + } + #endif // _di_level_0_parameter_checking_ + + if (!buffer.used || range->start > range->stop || range->start >= buffer.used) { + state->status = F_data_not; + + return; + } + + // Skip past initial place holders. + for (;; ++range->start) { + + if (range->start >= buffer.used) { + state->status = F_okay_eos; + + return; + } + + if (range->start > range->stop) { + state->status = F_okay_stop; + + return; + } + + if (buffer.string[range->start] != f_fss_placeholder_s.string[0]) break; + } // for + + uint8_t width = 0; + f_number_unsigned_t width_max = (range->stop - range->start) + 1; + + if (width_max > buffer.used - range->start) { + width_max = buffer.used - range->start; + } + + // Check that the first character is not a combining character. + state->status = f_utf_is_combining(buffer.string + range->start, width_max); + + f_fss_fail_utf_to_false(state); + if (F_status_is_error(state->status)) return; + + if (state->status == F_true) { + state->status = F_is_not; + + return; + } + + for (;;) { + + width = macro_f_utf_byte_width(buffer.string[range->start]); + + if (width > 1) { + if (range->start + width >= buffer.used) { + state->status = F_status_set_error(F_complete_not_utf_eos); + + f_fss_fail_utf(state); + + return; + } + + if (range->start + width > range->stop) { + state->status = F_status_set_error(F_complete_not_utf_stop); + + f_fss_fail_utf(state); + + return; + } + } + + range->start += width; + + if (range->start >= buffer.used) { + state->status = F_okay_eos; + + return; + } + + if (range->start > range->stop) { + state->status = F_okay_stop; + + return; + } + + width_max = (range->stop - range->start) + 1; + + if (width_max > buffer.used - range->start) { + width_max = buffer.used - range->start; + } + + if (buffer.string[range->start] == f_fss_eol_s.string[0]) { + state->status = F_okay_eol; + + return; + } + + if (buffer.string[range->start] == f_fss_placeholder_s.string[0]) { + ++range->start; + + continue; + } + + state->status = f_utf_is_combining(buffer.string + range->start, width_max); + + f_fss_fail_utf_to_false(state); + + if (state->status == F_false) break; + if (F_status_is_error(state->status)) return; + } // for + + state->status = F_okay; + } +#endif // _di_f_fss_skip_past_combining_ + #ifndef _di_f_fss_skip_past_delimit_ void f_fss_skip_past_delimit(const f_string_static_t buffer, f_range_t * const range, f_state_t * const state) { #ifndef _di_level_0_parameter_checking_ @@ -368,7 +489,26 @@ extern "C" { return; } + // Skip past initial place holders. + for (;; ++range->start) { + + if (range->start >= buffer.used) { + state->status = F_okay_eos; + + return; + } + + if (range->start > range->stop) { + state->status = F_okay_stop; + + return; + } + + if (buffer.string[range->start] != f_fss_placeholder_s.string[0]) break; + } // for + uint8_t width = 0; + f_number_unsigned_t previous = range->start; f_number_unsigned_t width_max = (range->stop - range->start) + 1; if (width_max > buffer.used - range->start) { @@ -427,11 +567,22 @@ extern "C" { f_fss_fail_utf_to_false(state); if (state->status == F_false) break; } + else { + // This is combining, so any previous white space is no longer considered white space as such. + range->start = previous; + + // Ensure previous is not a place holder. + while (range->start && buffer.string[range->start] == f_fss_placeholder_s.string[0]) --range->start; + + break; + } } } if (F_status_is_error(state->status)) return; + previous = range->start; + width = macro_f_utf_byte_width(buffer.string[range->start]); if (width > 1) { diff --git a/level_0/f_fss/c/fss.h b/level_0/f_fss/c/fss.h index a4f233d28..b668ad01b 100644 --- a/level_0/f_fss/c/fss.h +++ b/level_0/f_fss/c/fss.h @@ -340,6 +340,44 @@ extern "C" { extern void f_fss_seek_to_eol(const f_string_dynamic_t buffer, f_range_t * const range, f_state_t * const state); #endif // _di_f_fss_seek_to_eol_ +/** + * Skip past all combining characters. + * + * This will do nothing if the first character is not a combining character. + * + * This skips past place holders. + * + * This stops on end of line. + * + * @param buffer + * The string to process. + * @param range + * The start and stop positions in the buffer being processed. + * This increments range->start. + * @param state + * A state for providing flags and handling interrupts during long running operations. + * + * This alters state.status: + * F_okay on success. + * F_data_not on success but buffer.used is 0, initial range.start is greater than range.stop, or initial range.start is greater than or equal to buffer.used. + * F_is_not on success, but the first character is not a combining character. + * F_okay_eol on success and EOL was reached. + * F_okay_eos on success and EOS was reached. + * F_okay_stop on success and stop point was reached. + * + * F_complete_not_utf_eos (with error bit) if unable to get entire UTF-8 sequence due to EOS. + * F_complete_not_utf_start (with error bit) if the first character is a combining character. + * F_complete_not_utf_stop (with error bit) if unable to get entire UTF-8 sequence due to stop point reached. + * F_parameter (with error bit) if a parameter is invalid. + * + * Errors (with error bit) from: f_utf_is_combining(). + * + * @see f_utf_is_combining() + */ +#ifndef _di_f_fss_skip_past_combining_ + extern void f_fss_skip_past_combining(const f_string_static_t buffer, f_range_t * const range, f_state_t * const state); +#endif // _di_f_fss_skip_past_combining_ + /** * Skip past all delimit placeholders until a non-delimit placeholder is reached. * @@ -369,6 +407,13 @@ extern "C" { * If the first character in the given range is a combining character, then this will not skip past anything. * This is because combining characters apply from right to left. * + * White space is checked for combining characters after the white space. + * If there is a combining character after, then the white space is not consider as such. + * + * This skips past place holders. + * + * This stops on end of line. + * * @param buffer * The string to process. * @param range diff --git a/level_1/fl_fss/c/private-fss.c b/level_1/fl_fss/c/private-fss.c index 3333da780..f3c72e997 100644 --- a/level_1/fl_fss/c/private-fss.c +++ b/level_1/fl_fss/c/private-fss.c @@ -9,7 +9,14 @@ extern "C" { void private_fl_fss_basic_or_extended_read(const f_string_static_t buffer, const uint8_t flag, f_range_t * const range, f_range_t * const found, uint8_t * const quote, f_number_unsigneds_t * const delimits, f_state_t * const state) { f_fss_skip_past_space(buffer, range, state); - if (F_status_is_error(state->status) || state->status == F_data_not) return; + + if (F_status_is_error(state->status) || state->status == F_data_not) { + if (F_status_set_fine(state->status) == F_complete_not_utf_start) { + f_fss_skip_past_combining(buffer, range, state); + if (F_status_is_error(state->status) || state->status == F_data_not) return; + } + else return; + } if (state->status == F_okay_eol) { // Move the start position to after the EOL. @@ -630,7 +637,14 @@ extern "C" { void private_fl_fss_basic_write(const uint8_t flag, const f_string_static_t object, const uint8_t quote, f_range_t * const range, f_string_dynamic_t * const destination, f_state_t * const state, void * const internal) { f_fss_skip_past_space(object, range, state); - if (F_status_is_error(state->status) || state->status == F_data_not) return; + + if (F_status_is_error(state->status) || state->status == F_data_not) { + if (F_status_set_fine(state->status) == F_complete_not_utf_start) { + f_fss_skip_past_combining(object, range, state); + if (F_status_is_error(state->status) || state->status == F_data_not) return; + } + else return; + } if (state->status == F_okay_eos) { state->status = F_data_not_eos; diff --git a/level_1/fl_fss/c/private-fss.h b/level_1/fl_fss/c/private-fss.h index 639070dbc..3efe1c0e9 100644 --- a/level_1/fl_fss/c/private-fss.h +++ b/level_1/fl_fss/c/private-fss.h @@ -73,6 +73,7 @@ extern "C" { * Errors (with error bit) from: f_fss_is_graph(). * Errors (with error bit) from: f_fss_is_space(). * Errors (with error bit) from: f_fss_is_zero_width(). + * Errors (with error bit) from: f_fss_skip_past_combining(). * Errors (with error bit) from: f_fss_skip_past_delimit(). * Errors (with error bit) from: f_fss_skip_past_space(). * Errors (with error bit) from: f_utf_buffer_increment(). @@ -82,6 +83,7 @@ extern "C" { * @see f_fss_is_graph() * @see f_fss_is_space() * @see f_fss_is_zero_width() + * @see f_fss_skip_past_combining() * @see f_fss_skip_past_delimit() * @see f_fss_skip_past_space() * @see f_utf_buffer_increment() @@ -139,6 +141,7 @@ extern "C" { * F_parameter (with error bit) if a parameter is invalid. * * Errors (with error bit) from: f_fss_is_space(). + * Errors (with error bit) from: f_fss_skip_past_combining(). * Errors (with error bit) from: f_fss_skip_past_delimit(). * Errors (with error bit) from: f_fss_skip_past_space(). * Errors (with error bit) from: f_memory_array_increase(). @@ -150,6 +153,7 @@ extern "C" { * Set to NULL to not use. * * @see f_fss_is_space() + * @see f_fss_skip_past_combining() * @see f_fss_skip_past_delimit() * @see f_fss_skip_past_space() * @see f_memory_array_increase() diff --git a/level_1/fl_fss/data/tests/contents/basic-combining_read.txt b/level_1/fl_fss/data/tests/contents/basic-combining_read.txt new file mode 100644 index 000000000..bbec7e729 --- /dev/null +++ b/level_1/fl_fss/data/tests/contents/basic-combining_read.txt @@ -0,0 +1,6 @@ +valid. +and does not have embedded new line. + + +is valid. +is valid with two combiners. diff --git a/level_1/fl_fss/data/tests/matches/basic-combining_read.txt b/level_1/fl_fss/data/tests/matches/basic-combining_read.txt new file mode 100644 index 000000000..8a23f1a08 --- /dev/null +++ b/level_1/fl_fss/data/tests/matches/basic-combining_read.txt @@ -0,0 +1,6 @@ +2 +2 +1 +2 +2 +2 diff --git a/level_1/fl_fss/data/tests/objects/basic-combining_read.txt b/level_1/fl_fss/data/tests/objects/basic-combining_read.txt new file mode 100644 index 000000000..839e3bfba --- /dev/null +++ b/level_1/fl_fss/data/tests/objects/basic-combining_read.txt @@ -0,0 +1,6 @@ +first +is_second +́ +fourth ͜no_space +fifth +sixtẖ̚ diff --git a/level_1/fl_fss/data/tests/strings/basic-combining_read.txt b/level_1/fl_fss/data/tests/strings/basic-combining_read.txt new file mode 100644 index 000000000..fe24da37d --- /dev/null +++ b/level_1/fl_fss/data/tests/strings/basic-combining_read.txt @@ -0,0 +1,6 @@ +first valid. +is_second and does not have embedded new line. +́ +fourth ͜no_space +fifth is valid. +sixtẖ̚ is valid with two combiners. diff --git a/level_1/fl_fss/tests/unit/c/test-fss-basic_content_read.c b/level_1/fl_fss/tests/unit/c/test-fss-basic_content_read.c index 20bba296d..c71db0cd7 100644 --- a/level_1/fl_fss/tests/unit/c/test-fss-basic_content_read.c +++ b/level_1/fl_fss/tests/unit/c/test-fss-basic_content_read.c @@ -216,6 +216,213 @@ void test__fl_fss_basic_content_read__works(void **void_state) { } } +void test__fl_fss_basic_content_read__works_using_combining(void **void_state) { + + { + // Note: These files are required to have the same number of lines and each line should probably be at max 255 characters. + FILE *file_contents = data__file_open__named("contents", "basic", "combining_read"); + FILE *file_matches = data__file_open__named("matches", "basic", "combining_read"); + FILE *file_strings = data__file_open__named("strings", "basic", "combining_read"); + + assert_non_null(file_contents); + assert_non_null(file_matches); + assert_non_null(file_strings); + + int matches = 0; + size_t max = 0; + char *line_string = 0; + char *line_content = 0; + char *line_matches = 0; + ssize_t result = 0; + + f_string_static_t buffer_string = f_string_static_t_initialize; + + f_state_t state = f_state_t_initialize; + f_range_t range = f_range_t_initialize; + f_range_t found_object = f_range_t_initialize; + f_ranges_t found = f_ranges_t_initialize; + uint8_t quote = 0; + f_number_unsigneds_t delimits = f_number_unsigneds_t_initialize; + f_string_dynamic_t result_string = f_string_dynamic_t_initialize; + f_string_dynamic_t delimit_string = f_string_dynamic_t_initialize; + f_status_t status_object = F_okay; + + for (;;) { + + max = 255; + + result = getline(&line_matches, &max, file_matches); + assert_return_code(result, 0); + + matches = atoi(line_matches); + + max = 255; + + result = getline(&line_string, &max, file_strings); + if (result == -1) break; + + buffer_string.string = line_string; + buffer_string.used = (f_number_unsigned_t) result; + buffer_string.size = buffer_string.used; + + max = 255; + + result = getline(&line_content, &max, file_contents); + assert_return_code(result, 0); + + // The newline is copied by getline(), and so remove that newline before comparing. + line_content[result - 1] = 0; + + state.status = F_none; + range.start = 0; + range.stop = buffer_string.used - 1; + found_object.start = 1; + found_object.stop = 0; + + fl_fss_basic_object_read(buffer_string, &range, &found_object, "e, &delimits, &state); + + if (matches) { + // When matches is 2, then this matches both object and content. + if (matches == 2) { + if (!(state.status == F_fss_found_object)) { + printf("[ -------> ] --- [00] Failure with line '%s', matches=%d, status=%u.\n", line_content, matches, state.status); + } + + assert_true(state.status == F_fss_found_object); + } + + // When matches is 1, then this matches only object. + else { + if (!(state.status == F_fss_found_object_content_not)) { + printf("[ -------> ] --- [02] Failure with line '%s', matches=%d, status=%u.\n", line_content, matches, state.status); + } + + assert_true(state.status == F_fss_found_object_content_not); + } + } + else { + + // This is currently not supported. + assert_true(F_false); + } + + status_object = state.status; + state.status = F_none; + + fl_fss_basic_content_read(buffer_string, &range, &found, &delimits, &state); + + if (status_object == F_fss_found_object) { + if (!(status_object == F_fss_found_object)) { + printf("[ -------> ] --- [02] Failure with line '%s'.\n", line_content); + } + + assert_int_equal(state.status, F_fss_found_content); + } + else { + if (state.status != F_data_not) { + printf("[ -------> ] --- [03] Failure with line '%s'.\n", line_content); + } + + assert_int_equal(state.status, F_data_not); + } + + if (matches == 2) { + if (state.status == F_fss_found_content) { + if (!found.used) { + printf("[ -------> ] --- [04] Failure with line '%s'.\n", line_content); + } + + assert_true(found.used); + + { + const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string); + + if (status != F_okay) { + printf("[ -------> ] --- [05] Failure with line '%s'.\n", line_content); + } + + assert_int_equal(status, F_okay); + } + + state.status = F_none; + + f_fss_apply_delimit(delimits, &delimit_string, &state); + assert_int_equal(state.status, F_okay); + + { + const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found.array[0], &result_string); + + if (!(status == F_okay || status == F_data_not_eos)) { + printf("[ -------> ] --- [06] Failure with line '%s', status=%u.\n", line_content, status); + } + + assert_true(status == F_okay || status == F_data_not_eos); + } + + { + const f_status_t status = f_string_dynamic_terminate_after(&result_string); + + if (status != F_okay) { + printf("[ -------> ] --- [07] Failure with line '%s'.\n", line_content); + } + + assert_int_equal(status, F_okay); + } + + if (strcmp((const char *) result_string.string, (const char *) line_content)) { + printf("[ -------> ] --- [08] Failure with line '%s'; got '%s', expected '%s'.\n", line_content, result_string.string, line_content); + } + + assert_string_equal(result_string.string, line_content); + } + else { + if (found.used) { + printf("[ -------> ] --- [09] Failure with line '%s'.\n", line_content); + } + + assert_true(!found.used); + } + } + + if (line_string) free(line_string); + if (line_content) free(line_content); + if (line_matches) free(line_matches); + if (result_string.string) free(result_string.string); + if (delimit_string.string) free(delimit_string.string); + if (delimits.array) free(delimits.array); + if (found.array) free(found.array); + + line_string = 0; + line_content = 0; + line_matches = 0; + result_string.string = 0; + result_string.used = 0; + result_string.size = 0; + delimit_string.string = 0; + delimit_string.used = 0; + delimit_string.size = 0; + delimits.array = 0; + delimits.used = 0; + delimits.size = 0; + found.array = 0; + found.used = 0; + found.size = 0; + } // for + + if (file_strings) fclose(file_strings); + if (file_contents) fclose(file_contents); + if (file_matches) fclose(file_matches); + + if (delimits.array) free(delimits.array); + if (found.array) free(found.array); + if (line_string) free(line_string); + if (line_content) free(line_content); + if (line_matches) free(line_matches); + if (result_string.string) free(result_string.string); + if (delimit_string.string) free(delimit_string.string); + } +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_fss/tests/unit/c/test-fss-basic_content_read.h b/level_1/fl_fss/tests/unit/c/test-fss-basic_content_read.h index 6eb08e0c5..f648b64a7 100644 --- a/level_1/fl_fss/tests/unit/c/test-fss-basic_content_read.h +++ b/level_1/fl_fss/tests/unit/c/test-fss-basic_content_read.h @@ -31,4 +31,11 @@ extern void test__fl_fss_basic_content_read__returns_data_not(void **state); */ extern void test__fl_fss_basic_content_read__works(void **state); +/** + * Test that the function works when using combining characters. + * + * @see fl_fss_basic_content_read() + */ +extern void test__fl_fss_basic_content_read__works_using_combining(void **state); + #endif // _TEST__FL_fss_basic_content_read_h diff --git a/level_1/fl_fss/tests/unit/c/test-fss-basic_object_read.c b/level_1/fl_fss/tests/unit/c/test-fss-basic_object_read.c index 2fd4e35e4..633ac7af4 100644 --- a/level_1/fl_fss/tests/unit/c/test-fss-basic_object_read.c +++ b/level_1/fl_fss/tests/unit/c/test-fss-basic_object_read.c @@ -241,6 +241,181 @@ void test__fl_fss_basic_object_read__works(void **void_state) { } } +void test__fl_fss_basic_object_read__works_using_combining(void **void_state) { + + { + // Note: These files are required to have the same number of lines and each line should probably be at max 255 characters. + FILE *file_matches = data__file_open__named("matches", "basic", "combining_read"); + FILE *file_objects = data__file_open__named("objects", "basic", "combining_read"); + FILE *file_strings = data__file_open__named("strings", "basic", "combining_read"); + + assert_non_null(file_matches); + assert_non_null(file_objects); + assert_non_null(file_strings); + + int matches = 0; + size_t max = 0; + char *line_matches = 0; + char *line_object = 0; + char *line_string = 0; + ssize_t result = 0; + + f_string_static_t buffer_string = f_string_static_t_initialize; + + f_state_t state = f_state_t_initialize; + f_range_t range = f_range_t_initialize; + f_range_t found = f_range_t_initialize; + uint8_t quote = 0; + f_number_unsigneds_t delimits = f_number_unsigneds_t_initialize; + f_string_dynamic_t result_string = f_string_dynamic_t_initialize; + f_string_dynamic_t delimit_string = f_string_dynamic_t_initialize; + + for (;;) { + + max = 255; + + result = getline(&line_matches, &max, file_matches); + assert_return_code(result, 0); + + matches = atoi(line_matches); + + max = 255; + + result = getline(&line_string, &max, file_strings); + if (result == -1) break; + + buffer_string.string = line_string; + buffer_string.used = (f_number_unsigned_t) result; + buffer_string.size = buffer_string.used; + + max = 255; + + result = getline(&line_object, &max, file_objects); + assert_return_code(result, 0); + + // The newline is copied by getline(), and so remove that newline before comparing. + line_object[result - 1] = 0; + + state.status = F_none; + range.start = 0; + range.stop = buffer_string.used - 1; + found.start = 1; + found.stop = 0; + + fl_fss_basic_object_read(buffer_string, &range, &found, "e, &delimits, &state); + + if (matches) { + // When matches is 2, then this matches both object and content. + if (matches == 2) { + if (!(state.status == F_fss_found_object)) { + printf("[ -------> ] --- [00] Failure with line '%s', matches=%d, status=%u.\n", line_object, matches, state.status); + } + + assert_true(state.status == F_fss_found_object); + + if (!(found.start <= found.stop)) { + printf("[ -------> ] --- [01] Failure with line '%s', matches=%d, found=(%lu, %lu).\n", line_object, matches, found.start, found.stop); + } + + assert_true(found.start <= found.stop); + } + + // When matches is 1, then this matches only object. + else { + if (!(state.status == F_fss_found_object_content_not)) { + printf("[ -------> ] --- [02] Failure with line '%s', matches=%d, status=%u.\n", line_object, matches, state.status); + } + + assert_true(state.status == F_fss_found_object_content_not); + } + } + else { + + // This is currently not supported. + assert_true(F_false); + } + + + { + const f_status_t status = f_string_dynamic_append(buffer_string, &delimit_string); + + if (status != F_okay) { + printf("[ -------> ] --- [03] Failure with line '%s'.\n", line_object); + } + + assert_int_equal(status, F_okay); + } + + state.status = F_none; + + f_fss_apply_delimit(delimits, &delimit_string, &state); + + if (state.status != F_okay) { + printf("[ -------> ] --- [04] Failure with line '%s'.\n", line_object); + } + + assert_int_equal(state.status, F_okay); + + { + const f_status_t status = f_string_dynamic_partial_append_nulless(delimit_string, found, &result_string); + + if (!(status == F_okay || status == F_data_not_eos)) { + printf("[ -------> ] --- [05] Failure with line '%s', status=%u.\n", line_object, status); + } + + assert_true(status == F_okay || status == F_data_not_eos); + } + + { + const f_status_t status = f_string_dynamic_terminate_after(&result_string); + + if (status != F_okay) { + printf("[ -------> ] --- [06] Failure with line '%s'.\n", line_object); + } + + assert_int_equal(status, F_okay); + } + + if (strcmp((const char *) result_string.string, (const char *) line_object)) { + printf("[ -------> ] --- [07] Failure with line '%s'.\n", line_object); + } + + assert_string_equal(result_string.string, line_object); + + if (line_matches) free(line_matches); + if (line_object) free(line_object); + if (line_string) free(line_string); + if (result_string.string) free(result_string.string); + if (delimit_string.string) free(delimit_string.string); + if (delimits.array) free(delimits.array); + + line_matches = 0; + line_object = 0; + line_string = 0; + result_string.string = 0; + result_string.used = 0; + result_string.size = 0; + delimit_string.string = 0; + delimit_string.used = 0; + delimit_string.size = 0; + delimits.array = 0; + delimits.used = 0; + delimits.size = 0; + } // for + + if (file_matches) fclose(file_matches); + if (file_objects) fclose(file_objects); + if (file_strings) fclose(file_strings); + + if (delimits.array) free(delimits.array); + if (line_string) free(line_string); + if (line_object) free(line_object); + if (result_string.string) free(result_string.string); + if (delimit_string.string) free(delimit_string.string); + } +} + + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_fss/tests/unit/c/test-fss-basic_object_read.h b/level_1/fl_fss/tests/unit/c/test-fss-basic_object_read.h index 33e611161..f82681597 100644 --- a/level_1/fl_fss/tests/unit/c/test-fss-basic_object_read.h +++ b/level_1/fl_fss/tests/unit/c/test-fss-basic_object_read.h @@ -31,4 +31,11 @@ extern void test__fl_fss_basic_object_read__returns_data_not(void **state); */ extern void test__fl_fss_basic_object_read__works(void **state); +/** + * Test that the function works when using combining characters. + * + * @see fl_fss_basic_object_read() + */ +extern void test__fl_fss_basic_object_read__works_using_combining(void **state); + #endif // _TEST__FL_fss_basic_object_read_h diff --git a/level_1/fl_fss/tests/unit/c/test-fss.c b/level_1/fl_fss/tests/unit/c/test-fss.c index 4302d408d..c48cf3059 100644 --- a/level_1/fl_fss/tests/unit/c/test-fss.c +++ b/level_1/fl_fss/tests/unit/c/test-fss.c @@ -25,7 +25,9 @@ int main(void) { cmocka_unit_test(test__fl_fss_basic_object_write__returns_data_not), cmocka_unit_test(test__fl_fss_basic_content_read__works), + cmocka_unit_test(test__fl_fss_basic_content_read__works_using_combining), cmocka_unit_test(test__fl_fss_basic_object_read__works), + cmocka_unit_test(test__fl_fss_basic_object_read__works_using_combining), cmocka_unit_test(test__fl_fss_basic_list_content_read__returns_data_not), cmocka_unit_test(test__fl_fss_basic_list_content_write__returns_data_not),