]> Kevux Git Server - fll/commitdiff
Update: Implement the fss_embedded_read depth logic using recursion.
authorKevin Day <Kevin@kevux.org>
Thu, 7 Nov 2024 02:20:38 +0000 (20:20 -0600)
committerKevin Day <Kevin@kevux.org>
Thu, 7 Nov 2024 02:20:38 +0000 (20:20 -0600)
I only did cursory review of the code and functionality.
I need to do more extended review to make sure there are no mistakes or logic flaws.
I need to write unit tests to identify these cases.

level_3/fss_read/c/embedded_list/process.c
level_3/fss_read/c/embedded_list/process.h

index ee7ecd94a46f5808ce7606ed468bae3bdc2a1489..5ec425f56191c2ed0e041a6adeec7cb8ad2ae533 100644 (file)
@@ -52,8 +52,6 @@ extern "C" {
     fss_read_embedded_list_process_determine_depth(main);
     if (F_status_is_error(main->setting.state.status)) return;
 
-    // @todo everything below here will need to be reviewed and updated.
-
     const f_number_unsigneds_t * const delimits_object = !(main->setting.flag & fss_read_main_flag_original_d) && fss_read_delimit_object_is(main, 0) ? &main->setting.delimits_object : &fss_read_except_none_c;
     const f_number_unsigneds_t * const delimits_content = !(main->setting.flag & fss_read_main_flag_original_d) && fss_read_delimit_content_is(main, 0) ? &main->setting.delimits_content : &fss_read_except_none_c;
 
@@ -124,65 +122,190 @@ extern "C" {
 
     if (!main || !main->setting.nest.used || !main->setting.nest.depth[0].used || !main->setting.depths.used) return;
 
-    f_number_unsigned_t depth = main->setting.depths.array[0].depth;
-
-    if (depth >= main->setting.nest.used) {
+    if (main->setting.depths.array[0].depth >= main->setting.nest.used) {
       main->setting.state.status = F_status_set_error(F_parameter);
 
       return;
     }
 
-    if ((main->setting.flag & fss_read_main_flag_depth_d) && depth && main->setting.nest.used > 1) {
+    if ((main->setting.flag & fss_read_main_flag_depth_d) && (main->setting.depths.array[0].depth || main->setting.depths.used > 1) && main->setting.nest.used > 1) {
       f_number_unsigned_t i = 0;
 
-      // @todo make an array of depths based on size.
-      // @todo determine which ones have --at or --name used for them.
+      // Pre-process depths to confirm if any requested i is out of range.
+      for (; i < main->setting.depths.used; ++i) {
+
+        if (main->setting.depths.array[i].depth >= main->setting.nest.used) {
+          main->setting.state.status = F_status_set_error(F_parameter);
+
+          return;
+        }
+      } // for
 
-      //if (main->setting.nest.depth[depth].array[main->setting.objects.used].content.used) {
+      if (F_status_is_error_not(main->setting.state.status)) {
+        f_number_unsigned_t j = 0;
+        fss_read_depth_t * const the = &main->setting.depths.array[0];
 
-      //main->setting.depth
-      //main->setting.nest.depth
+        for (i = 0; i < main->setting.nest.depth[the->depth].used; ++i) {
 
-      //for (; i < main->setting.objects.used; ++i) {
-      //} // for
+          if (main->setting.depths.used > 1) {
 
-      // @todo determine depth and dynamically construct the objects and therefore content based on any of --at, --depth, and --name.
-      //return;
+            // The name and at conditions are only to be matched if not at the last depth.
+            if (the->index_name) {
+              if (f_compare_dynamic_partial_trim_string(the->value_name.string, main->setting.buffer, the->value_name.used, main->setting.nest.depth[the->depth].array[i].object) != F_equal_to) continue;
+            }
+
+            if (the->index_at) {
+              if (j != the->value_at) {
+                if (++j > the->value_at) break;
+
+                continue;
+              }
+            }
+
+            fss_read_embedded_list_process_determine_depth_nest_recurse(main, i, 1);
+            if (F_status_is_error(main->setting.state.status)) break;
+          }
+          else {
+            fss_read_embedded_list_process_determine_depth_save(main, &main->setting.nest.depth[the->depth].array[i]);
+            if (F_status_is_error(main->setting.state.status)) break;
+          }
+        } // for
+
+        if (F_status_is_error_not(main->setting.state.status)) {
+          fss_read_ensure_quotes_length(main);
+
+          if (F_status_is_error_not(main->setting.state.status)) {
+            main->setting.state.status = F_okay;
+          }
+        }
+      }
+
+      if (main->setting.depths.used > 1) {
+        main->setting.depth = main->setting.depths.array[main->setting.depths.used - 1];
+      }
+
+      return;
     }
 
-    main->setting.state.status = f_memory_array_resize(main->setting.nest.depth[depth].used, sizeof(f_range_t), (void **) &main->setting.objects.array, &main->setting.objects.used, &main->setting.objects.size);
-    if (F_status_is_error(main->setting.state.status)) return;
+    {
+      const f_number_unsigned_t depth = main->setting.depths.array[0].depth;
 
-    main->setting.state.status = f_memory_array_resize(main->setting.nest.depth[depth].used, sizeof(f_range_t), (void **) &main->setting.closes.array, &main->setting.closes.used, &main->setting.closes.size);
-    if (F_status_is_error(main->setting.state.status)) return;
+      main->setting.state.status = f_memory_array_resize(main->setting.nest.depth[depth].used, sizeof(f_range_t), (void **) &main->setting.objects.array, &main->setting.objects.used, &main->setting.objects.size);
 
-    main->setting.state.status = f_memory_array_resize(main->setting.nest.depth[depth].used, sizeof(f_ranges_t), (void **) &main->setting.contents.array, &main->setting.contents.used, &main->setting.contents.size);
-    if (F_status_is_error(main->setting.state.status)) return;
+      if (F_status_is_error_not(main->setting.state.status)) {
+        main->setting.state.status = f_memory_array_resize(main->setting.nest.depth[depth].used, sizeof(f_range_t), (void **) &main->setting.closes.array, &main->setting.closes.used, &main->setting.closes.size);
+      }
 
-    for (; main->setting.objects.used < main->setting.nest.depth[depth].used; ++main->setting.objects.used) {
+      if (F_status_is_error_not(main->setting.state.status)) {
+        main->setting.state.status = f_memory_array_resize(main->setting.nest.depth[depth].used, sizeof(f_ranges_t), (void **) &main->setting.contents.array, &main->setting.contents.used, &main->setting.contents.size);
+      }
+
+      if (F_status_is_error(main->setting.state.status)) return;
 
-      main->setting.objects.array[main->setting.objects.used] = main->setting.nest.depth[depth].array[main->setting.objects.used].object;
-      main->setting.closes.array[main->setting.objects.used] = main->setting.nest.depth[depth].array[main->setting.objects.used].close;
+      for (; main->setting.objects.used < main->setting.nest.depth[depth].used; ++main->setting.objects.used) {
 
-      // Use a static array for the inner Content that points to the depth, and so ensure the size is 0 to designate this is not dynamically allocated here.
-      if (main->setting.nest.depth[depth].array[main->setting.objects.used].content.used) {
-        main->setting.contents.array[main->setting.objects.used].array = main->setting.nest.depth[depth].array[main->setting.objects.used].content.array;
-        main->setting.contents.array[main->setting.objects.used].used = main->setting.nest.depth[depth].array[main->setting.objects.used].content.used;
-        main->setting.contents.array[main->setting.objects.used].size = 0;
+        main->setting.objects.array[main->setting.objects.used] = main->setting.nest.depth[depth].array[main->setting.objects.used].object;
+        main->setting.closes.array[main->setting.objects.used] = main->setting.nest.depth[depth].array[main->setting.objects.used].close;
+
+        // Use a static array for the inner Content that points to the depth, and so ensure the size is 0 to designate this is not dynamically allocated here.
+        if (main->setting.nest.depth[depth].array[main->setting.objects.used].content.used) {
+          main->setting.contents.array[main->setting.objects.used].array = main->setting.nest.depth[depth].array[main->setting.objects.used].content.array;
+          main->setting.contents.array[main->setting.objects.used].used = main->setting.nest.depth[depth].array[main->setting.objects.used].content.used;
+          main->setting.contents.array[main->setting.objects.used].size = 0;
+        }
+        else {
+          main->setting.contents.array[main->setting.objects.used].array = 0;
+          main->setting.contents.array[main->setting.objects.used].used = 0;
+          main->setting.contents.array[main->setting.objects.used].size = 0;
+        }
+      } // for
+
+      main->setting.closes.used = main->setting.objects.used;
+      main->setting.contents.used = main->setting.objects.used;
+    }
+
+    fss_read_ensure_quotes_length(main);
+
+    if (F_status_is_error_not(main->setting.state.status)) {
+      main->setting.state.status = F_okay;
+    }
+  }
+#endif // _di_fss_read_embedded_list_process_determine_depth_
+
+#ifndef _di_fss_read_embedded_list_process_determine_depth_nest_recurse_
+  void fss_read_embedded_list_process_determine_depth_nest_recurse(fss_read_main_t * const main, const f_number_unsigned_t parent, const f_number_unsigned_t next) {
+
+    if (!main || !next || next >= main->setting.depths.used) return;
+
+    f_number_unsigned_t i = 0;
+    f_number_unsigned_t j = 0;
+    fss_read_depth_t * const the = &main->setting.depths.array[next];
+
+    for (; F_status_is_error_not(main->setting.state.status) && i < main->setting.nest.depth[the->depth].used; ++i) {
+
+      if (main->setting.nest.depth[the->depth].array[i].parent != parent) continue;
+
+      if (next + 1 < main->setting.depths.used) {
+
+        // The name and at conditions are only to be matched if not at the last depth.
+        if (the->index_name) {
+          if (f_compare_dynamic_partial_trim_string(the->value_name.string, main->setting.buffer, the->value_name.used, main->setting.nest.depth[the->depth].array[i].object) != F_equal_to) continue;
+        }
+
+        if (the->index_at) {
+          if (j != the->value_at) {
+            if (++j > the->value_at) break;
+
+            continue;
+          }
+        }
+
+        fss_read_embedded_list_process_determine_depth_nest_recurse(main, i, next + 1);
       }
       else {
-        main->setting.contents.array[main->setting.objects.used].array = 0;
-        main->setting.contents.array[main->setting.objects.used].used = 0;
-        main->setting.contents.array[main->setting.objects.used].size = 0;
+        fss_read_embedded_list_process_determine_depth_save(main, &main->setting.nest.depth[the->depth].array[i]);
       }
     } // for
+  }
+#endif // _di_fss_read_embedded_list_process_determine_depth_nest_recurse_
 
-    main->setting.closes.used = main->setting.objects.used;
-    main->setting.contents.used = main->setting.objects.used;
+#ifndef _di_fss_read_embedded_list_process_determine_depth_save_
+  void fss_read_embedded_list_process_determine_depth_save(fss_read_main_t * const main, f_fss_item_t * const item) {
 
-    fss_read_ensure_quotes_length(main);
+    if (!main || !item) return;
+
+    main->setting.state.status = f_memory_array_increase(main->setting.state.step_small, sizeof(f_range_t), (void **) &main->setting.objects.array, &main->setting.objects.used, &main->setting.objects.size);
+
+    if (F_status_is_error_not(main->setting.state.status)) {
+      main->setting.state.status = f_memory_array_increase(main->setting.state.step_small, sizeof(f_range_t), (void **) &main->setting.closes.array, &main->setting.closes.used, &main->setting.closes.size);
+    }
+
+    if (F_status_is_error_not(main->setting.state.status)) {
+      main->setting.state.status = f_memory_array_increase(main->setting.state.step_small, sizeof(f_ranges_t), (void **) &main->setting.contents.array, &main->setting.contents.used, &main->setting.contents.size);
+    }
+
+    if (F_status_is_error_not(main->setting.state.status)) {
+      main->setting.objects.array[main->setting.objects.used] = item->object;
+      main->setting.closes.array[main->setting.closes.used] = item->close;
+
+      // Use a static array for the inner Content that points to the depth, and so ensure the size is 0 to designate this is not dynamically allocated here.
+      if (item->content.used) {
+        main->setting.contents.array[main->setting.contents.used].array = item->content.array;
+        main->setting.contents.array[main->setting.contents.used].used = item->content.used;
+        main->setting.contents.array[main->setting.contents.used].size = 0;
+      }
+      else {
+        main->setting.contents.array[main->setting.contents.used].array = 0;
+        main->setting.contents.array[main->setting.contents.used].used = 0;
+        main->setting.contents.array[main->setting.contents.used].size = 0;
+      }
+
+      ++main->setting.objects.used;
+      ++main->setting.closes.used;
+      ++main->setting.contents.used;
+    }
   }
-#endif // _di_fss_read_embedded_list_process_determine_depth_
+#endif // _di_fss_read_embedded_list_process_determine_depth_save_
 
 #ifdef __cplusplus
 } // extern "C"
index 047dd44dbbd4a627004919326dec2e038eafda0c..eb7f7b1cb874e5ff348e4966437271df65c195f1 100644 (file)
@@ -49,15 +49,69 @@ extern "C" {
  *
  *     Errors (with error bit) from: fss_read_signal_check().
  *
- * @return
- *   The depth to use.
- *
  * @see fss_read_signal_check()
  */
 #ifndef _di_fss_read_embedded_list_process_determine_depth_
   extern void fss_read_embedded_list_process_determine_depth(fss_read_main_t * const main);
 #endif // _di_fss_read_embedded_list_process_determine_depth_
 
+/**
+ * Recursively determine the depth.
+ *
+ * This is intended to be directly called by fss_read_embedded_list_process_determine_depth().
+ *
+ * @param main
+ *   The program and settings data.
+ *
+ *   Must not be NULL.
+ *
+ *   This alters main.setting.state.status:
+ *     F_okay on success.
+ *
+ *     Errors (with error bit) from: fss_read_signal_check().
+ * @param parent
+ *   The index position of the parent element.
+ *   This is needed because the items array for some depth is tied to the parent via a property.
+ * @param next
+ *   The next index position in the depths array to process.
+ *
+ *   Must be greater than 0.
+ *
+ * @see fss_read_signal_check()
+ */
+#ifndef _di_fss_read_embedded_list_process_determine_depth_nest_recurse_
+  extern void fss_read_embedded_list_process_determine_depth_nest_recurse(fss_read_main_t * const main, const f_number_unsigned_t parent, const f_number_unsigned_t next);
+#endif // _di_fss_read_embedded_list_process_determine_depth_nest_recurse_
+
+/**
+ * Save the given item, appending the parts to the appropriate settings arrays.
+ *
+ * This is intended to be directly called by fss_read_embedded_list_process_determine_depth() and fss_read_embedded_list_process_determine_depth_nest_recurse().
+ *
+ * @param main
+ *   The program and settings data.
+ *
+ *   Must not be NULL.
+ *
+ *   This alters main.setting.state.status:
+ *     F_okay on success.
+ *
+ *     Errors (with error bit) from: f_memory_array_increase().
+ *
+ * @param item
+ *   The item to save.
+ *
+ *   Must not be NULL.
+ *
+ * @see f_memory_array_increase()
+ *
+ * @see fss_read_embedded_list_process_determine_depth()
+ * @see fss_read_embedded_list_process_determine_depth_nest_recurse()
+ */
+#ifndef _di_fss_read_embedded_list_process_determine_depth_save_
+  extern void fss_read_embedded_list_process_determine_depth_save(fss_read_main_t * const main, f_fss_item_t * const item);
+#endif // _di_fss_read_embedded_list_process_determine_depth_save_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif