]> Kevux Git Server - fll/commitdiff
Progress: Handle basic list combining/joiner at start and fix unit test.
authorKevin Day <Kevin@kevux.org>
Wed, 14 Oct 2026 02:38:51 +0000 (21:38 -0500)
committerKevin Day <Kevin@kevux.org>
Wed, 14 Oct 2026 03:26:24 +0000 (22:26 -0500)
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
level_1/fl_fss/c/fss/embedded_list.c
level_1/fl_fss/c/fss/extended_list.c
level_1/fl_fss/tests/unit/c/test-fss-basic_list_content_read.c

index 7c725b960eb5f61d62bfea5c118a92311a0e1987..5958cc4c46cfcb01447b9df30630f039a510e54a 100644 (file)
@@ -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;
index 2e403a7018121484a5e77d4093f05045a5202d57..1481b436636b343c85a8dc196e003365cab9c8e6 100644 (file)
@@ -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++;
index bde48a57c3c56b86011b5f700b00b5243272cef2..c3fc0bfadab486a9a16e4f0d399631bf425a9bc0 100644 (file)
@@ -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;
 
index 0448bb61b9711b82bd931a828b1447057b26c597..cb5347ab8544d70410c7aab41ee36bc949324cb7 100644 (file)
@@ -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);
           }