From a97f7f0213c1bc0b3aacfb025b4069c7588129e8 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Tue, 13 Oct 2026 21:38:51 -0500 Subject: [PATCH] Progress: Handle basic list combining/joiner at start and fix unit test. For lists, if the start of a line is a combining/joiner, then it must be treated as Content even if it would otherwise be a valid Object on that line. The unit test actually has to handle when `F_okay_eos` or `F_okay_stop` is returned on content read. The basic list doesn't know if the content is a valid object or not. It can be assumed, but the function does not do this. The caller must handle incrementing found.used when either `F_okay_eos` or `F_okay_stop` is returned. Update the comment on this as well. Properly verify that `newline_last` is in fact a new line by checking it against the `begin` position. The basic list already has `begin`, but extended list has `begin` added to perform this check. --- level_1/fl_fss/c/fss/basic_list.c | 22 +++++++++++++--- level_1/fl_fss/c/fss/embedded_list.c | 16 ++++++++++++ level_1/fl_fss/c/fss/extended_list.c | 25 ++++++++++++++++--- .../unit/c/test-fss-basic_list_content_read.c | 6 +++++ 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/level_1/fl_fss/c/fss/basic_list.c b/level_1/fl_fss/c/fss/basic_list.c index 7c725b960..5958cc4c4 100644 --- a/level_1/fl_fss/c/fss/basic_list.c +++ b/level_1/fl_fss/c/fss/basic_list.c @@ -58,6 +58,13 @@ extern "C" { uint8_t flag_fl = ___fl_flag_has_graph_first___; + // The start position with a combining/joiner must be treated as Content and not as an Object. + if (f_fss_is_combining_joiner(buffer, *range, state) == F_true) { + f_fss_seek_to_eol(buffer, range, state); + } + + if (F_status_is_error(state->status)) return; + // Identify where the content ends. while (range->start <= range->stop && range->start < buffer.used) { @@ -79,6 +86,15 @@ extern "C" { flag_fl &= ~___fl_flag_has_delimit_comment___; ++range->start; + // Any line that starts with a combining/joiner must be treated as Content and not as an Object. + f_fss_skip_past_delimit(buffer, range, state); + + if (F_status_is_error_not(state->status) && f_fss_is_combining_joiner(buffer, *range, state) == F_true) { + f_fss_seek_to_eol(buffer, range, state); + } + + if (F_status_is_error(state->status)) break; + continue; } @@ -221,9 +237,9 @@ extern "C" { if (F_status_is_error(state->status)) break; if (range->start > range->stop || range->start >= buffer.used) break; - // Found a valid object, set stop point to last newline. + // Found a valid object, set stop point to last newline (if newline_last is begin, there newline_last is not a new line). if (state->status == F_okay_eol) { - if (newline_last == found->array[found->used].start) { + if (begin != newline_last && newline_last == found->array[found->used].start) { found->array[found->used].start = 1; found->array[found->used++].stop = 0; range->start = newline_last; @@ -304,7 +320,7 @@ extern "C" { return; } - // The EOS and stop cases only happen here when content is not found, so do not increment found.used. + // The EOS and stop cases only happen here when the next object is not found, so do not increment found.used and let caller handle. if (range->start >= buffer.used) { found->array[found->used].stop = buffer.used - 1; state->status = F_okay_eos; diff --git a/level_1/fl_fss/c/fss/embedded_list.c b/level_1/fl_fss/c/fss/embedded_list.c index 2e403a701..1481b4366 100644 --- a/level_1/fl_fss/c/fss/embedded_list.c +++ b/level_1/fl_fss/c/fss/embedded_list.c @@ -84,6 +84,13 @@ extern "C" { cache->slashes->array[0] = 0; cache->slashes->used = 1; + // The start position with a combining/joiner must be treated as Content and not as an Object. + if (f_fss_is_combining_joiner(buffer, *range, state) == F_true) { + f_fss_seek_to_eol(buffer, range, state); + } + + if (F_status_is_error(state->status)) return; + while (range->start <= range->stop && range->start < buffer.used) { if (state->interrupt) { @@ -102,6 +109,15 @@ extern "C" { newline_last = previous = range->start++; line_start = range->start; flag_fl |= ___fl_flag_has_graph_first___; + + // Any line that starts with a combining/joiner must be treated as Content and not as an Object. + f_fss_skip_past_delimit(buffer, range, state); + + if (F_status_is_error_not(state->status) && f_fss_is_combining_joiner(buffer, *range, state) == F_true) { + f_fss_seek_to_eol(buffer, range, state); + } + + if (F_status_is_error(state->status)) break; } else if (buffer.string[range->start] == f_fss_slash_s.string[0] && (flag_fl & ___fl_flag_has_graph_first___)) { previous = range->start++; diff --git a/level_1/fl_fss/c/fss/extended_list.c b/level_1/fl_fss/c/fss/extended_list.c index bde48a57c..c3fc0bfad 100644 --- a/level_1/fl_fss/c/fss/extended_list.c +++ b/level_1/fl_fss/c/fss/extended_list.c @@ -39,11 +39,12 @@ extern "C" { #define ___fl_flag_has_slash___ 0x1 + const f_number_unsigned_t begin = range->start; const f_number_unsigned_t delimits_used = delimits->used; const f_number_unsigned_t comments_used = comments->used; - f_number_unsigned_t line_start = range->start; - f_number_unsigned_t newline_last = range->start; + f_number_unsigned_t line_start = begin; + f_number_unsigned_t newline_last = begin; f_number_unsigned_t previous = 0; f_number_unsigned_t slash_first = 0; f_number_unsigned_t comment_start = 0; @@ -52,6 +53,13 @@ extern "C" { found->array[found->used].start = range->start; + // The start position with a combining/joiner must be treated as Content and not as an Object. + if (f_fss_is_combining_joiner(buffer, *range, state) == F_true) { + f_fss_seek_to_eol(buffer, range, state); + } + + if (F_status_is_error(state->status)) return; + // Identify where the content ends. while (range->start <= range->stop && range->start < buffer.used) { @@ -76,6 +84,15 @@ extern "C" { newline_last = range->start++; line_start = range->start; + // Any line that starts with a combining/joiner must be treated as Content and not as an Object. + f_fss_skip_past_delimit(buffer, range, state); + + if (F_status_is_error_not(state->status) && f_fss_is_combining_joiner(buffer, *range, state) == F_true) { + f_fss_seek_to_eol(buffer, range, state); + } + + if (F_status_is_error(state->status)) break; + continue; } @@ -195,8 +212,8 @@ extern "C" { ++range->start; - // If the last newline is the entire start, then there is no Content. - if (newline_last == found->array[found->used].start) { + // If the last newline is the entire start, then there is no Content (if newline_last is begin, there newline_last is not a new line). + if (begin != newline_last && newline_last == found->array[found->used].start) { found->array[found->used].start = 1; found->array[found->used++].stop = 0; diff --git a/level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c b/level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c index 0448bb61b..cb5347ab8 100644 --- a/level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c +++ b/level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c @@ -523,6 +523,12 @@ void test__fl_fss_basic_list_content_read__works_using_combining(void **void_sta assert_true(state.status == F_fss_found_content || state.status == F_okay_eos || state.status == F_okay_stop || state.status == F_data_not); if (state.status == F_fss_found_content || state.status == F_okay_eos || state.status == F_okay_stop) { + + // The caller must handle these cases (for basic list only) and the unit test is expecting this. + if (state.status == F_okay_eos || state.status == F_okay_stop) { + ++found_content.used; + } + if (!found_content.used) { printf("[ -------> ] --- [12] Failure with fl_fss_basic_list_content_read(), with set %lu, expected found_content.used (%lu) <> 0.\n", set, found_content.used); } -- 2.52.0