From f6a2374f3bf4082d5a41669c73810fd668554e31 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Wed, 6 Nov 2024 20:20:38 -0600 Subject: [PATCH] Update: Implement the fss_embedded_read depth logic using recursion. 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 | 195 +++++++++++++++++++++++------ level_3/fss_read/c/embedded_list/process.h | 60 ++++++++- 2 files changed, 216 insertions(+), 39 deletions(-) diff --git a/level_3/fss_read/c/embedded_list/process.c b/level_3/fss_read/c/embedded_list/process.c index ee7ecd9..5ec425f 100644 --- a/level_3/fss_read/c/embedded_list/process.c +++ b/level_3/fss_read/c/embedded_list/process.c @@ -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" diff --git a/level_3/fss_read/c/embedded_list/process.h b/level_3/fss_read/c/embedded_list/process.h index 047dd44..eb7f7b1 100644 --- a/level_3/fss_read/c/embedded_list/process.h +++ b/level_3/fss_read/c/embedded_list/process.h @@ -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 -- 1.8.3.1