From 5959327193000ab98b6f660a9fb632e6c3cfc8b6 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 9 Apr 2023 18:21:10 -0500 Subject: [PATCH] Progress: Focus on directory recursion related changes and Featureless Make. I decided to offload some of the design in fl_directory_do(). The caller provides a callback and handles the combining of the path and the base file name. This should allow for more optimization in string allocation and reduce some of the overhead of recursion. The recursion now only records the used string rather than allocate an array of the path each time. This should ideally reduce the amount of memory in the recursion. The caller can now provide a custom variable to pass local data to the callbacks. Rename 'first' and 'last' into 'before' and 'after', respectively, to be more semantically accurate. Initial implementation of callbacks for action and handle. I may have more work to do in the error handling, but I decided now is a good place to stop and save the progress. --- build/level_0/settings | 14 +- build/monolithic/settings | 14 +- level_0/f_directory/c/directory/common.h | 12 +- level_0/f_directory/c/directory/type.c | 6 + level_0/f_directory/c/directory/type.h | 67 +++++-- level_1/fl_directory/c/directory.c | 144 +++++++++------ level_1/fl_directory/c/directory.h | 25 ++- level_1/fl_directory/c/private-directory.c | 261 ++++++++++++++++---------- level_1/fl_directory/c/private-directory.h | 28 +++ level_3/fake/c/main/build.c | 283 ++++++++++++++++++++++------- level_3/fake/c/main/build.h | 50 +++++ level_3/fake/c/main/build/print/message.c | 13 ++ level_3/fake/c/main/build/print/message.h | 24 +++ level_3/fake/c/main/build/print/verbose.c | 8 +- level_3/fake/c/main/build/print/verbose.h | 6 +- level_3/fake/c/main/common/print.c | 2 + level_3/fake/c/main/common/print.h | 2 + level_3/fake/c/main/common/type.c | 3 + level_3/fake/c/main/common/type.h | 4 + level_3/fake/c/main/print/error.c | 34 +++- level_3/fake/c/main/print/error.h | 45 ++++- 21 files changed, 772 insertions(+), 273 deletions(-) diff --git a/build/level_0/settings b/build/level_0/settings index d7e88d8..65a6e2a 100644 --- a/build/level_0/settings +++ b/build/level_0/settings @@ -75,8 +75,18 @@ build_sources_library string/triple.c string/triples.c string/tripless.c build_sources_library type_array/array_length.c type_array/cell.c type_array/fll_id.c type_array/int8.c type_array/int16.c type_array/int32.c type_array/int64.c type_array/int128.c type_array/state.c type_array/status.c type_array/uint8.c type_array/uint16.c type_array/uint32.c type_array/uint64.c type_array/uint128.c build_sources_library type_array/private-array_length.c type_array/private-cell.c type_array/private-fll_id.c type_array/private-int8.c type_array/private-int16.c type_array/private-int32.c type_array/private-int64.c type_array/private-int128.c type_array/private-state.c type_array/private-status.c type_array/private-uint8.c type_array/private-uint16.c type_array/private-uint32.c type_array/private-uint64.c type_array/private-uint128.c build_sources_library utf.c private-utf.c private-utf_alphabetic.c private-utf_combining.c private-utf_control.c private-utf_digit.c private-utf_emoji.c private-utf_numeric.c private-utf_phonetic.c private-utf_private.c private-utf_punctuation.c private-utf_subscript.c private-utf_superscript.c private-utf_symbol.c private-utf_unassigned.c private-utf_valid.c private-utf_whitespace.c private-utf_wide.c private-utf_word.c private-utf_zero_width.c -build_sources_library utf/common.c utf/convert.c utf/dynamic.c utf/dynamics.c utf/dynamicss.c utf/is.c utf/is_character.c utf/map.c utf/maps.c utf/mapss.c utf/map_multi.c utf/map_multis.c utf/map_multiss.c utf/static.c utf/statics.c utf/staticss.c utf/string.c utf/triple.c utf/triples.c utf/tripless.c -build_sources_library utf/private-dynamic.c utf/private-dynamics.c utf/private-dynamicss.c utf/private-maps.c utf/private-mapss.c utf/private-map_multis.c utf/private-map_multiss.c utf/private-string.c utf/private-triples.c utf/private-tripless.c +build_sources_library utf/common.c utf/convert.c +build_sources_library utf/dynamic.c utf/dynamics.c utf/dynamicss.c +build_sources_library utf/is.c utf/is_character.c +build_sources_library utf/map.c utf/maps.c utf/mapss.c +build_sources_library utf/map_multi.c utf/map_multis.c utf/map_multiss.c +build_sources_library utf/static.c utf/statics.c utf/staticss.c +build_sources_library utf/string.c utf/triple.c utf/triples.c utf/tripless.c +build_sources_library utf/private-dynamic.c utf/private-dynamics.c utf/private-dynamicss.c +build_sources_library utf/private-maps.c utf/private-mapss.c +build_sources_library utf/private-map_multis.c utf/private-map_multiss.c +build_sources_library utf/private-string.c +build_sources_library utf/private-triples.c utf/private-tripless.c build_sources_library-thread thread.c private-thread.c thread/attribute.c thread/barrier.c thread/barrier_attribute.c thread/condition.c thread/condition_attribute.c thread/id.c thread/key.c thread/lock.c thread/lock_attribute.c thread/mutex.c thread/mutex_attribute.c thread/once.c thread/semaphore.c thread/set.c thread/spin.c diff --git a/build/monolithic/settings b/build/monolithic/settings index c735cbd..3ad08b3 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -75,8 +75,18 @@ build_sources_library level_0/string/triple.c level_0/string/triples.c level_0/s build_sources_library level_0/type_array/array_length.c level_0/type_array/cell.c level_0/type_array/fll_id.c level_0/type_array/int8.c level_0/type_array/int16.c level_0/type_array/int32.c level_0/type_array/int64.c level_0/type_array/int128.c level_0/type_array/state.c level_0/type_array/status.c level_0/type_array/uint8.c level_0/type_array/uint16.c level_0/type_array/uint32.c level_0/type_array/uint64.c level_0/type_array/uint128.c build_sources_library level_0/type_array/private-array_length.c level_0/type_array/private-cell.c level_0/type_array/private-fll_id.c level_0/type_array/private-int8.c level_0/type_array/private-int16.c level_0/type_array/private-int32.c level_0/type_array/private-int64.c level_0/type_array/private-int128.c level_0/type_array/private-state.c level_0/type_array/private-status.c level_0/type_array/private-uint8.c level_0/type_array/private-uint16.c level_0/type_array/private-uint32.c level_0/type_array/private-uint64.c level_0/type_array/private-uint128.c build_sources_library level_0/utf.c level_0/private-utf.c level_0/private-utf_alphabetic.c level_0/private-utf_combining.c level_0/private-utf_control.c level_0/private-utf_digit.c level_0/private-utf_emoji.c level_0/private-utf_numeric.c level_0/private-utf_phonetic.c level_0/private-utf_private.c level_0/private-utf_punctuation.c level_0/private-utf_subscript.c level_0/private-utf_superscript.c level_0/private-utf_symbol.c level_0/private-utf_unassigned.c level_0/private-utf_valid.c level_0/private-utf_whitespace.c level_0/private-utf_wide.c level_0/private-utf_word.c level_0/private-utf_zero_width.c -build_sources_library level_0/utf/common.c level_0/utf/convert.c level_0/utf/dynamic.c level_0/utf/dynamics.c level_0/utf/dynamicss.c level_0/utf/is.c level_0/utf/is_character.c level_0/utf/map.c level_0/utf/maps.c level_0/utf/mapss.c level_0/utf/map_multi.c level_0/utf/map_multis.c level_0/utf/map_multiss.c level_0/utf/static.c level_0/utf/statics.c level_0/utf/staticss.c level_0/utf/string.c level_0/utf/triple.c level_0/utf/triples.c level_0/utf/tripless.c -build_sources_library level_0/utf/private-dynamic.c level_0/utf/private-dynamics.c level_0/utf/private-dynamicss.c level_0/utf/private-maps.c level_0/utf/private-mapss.c level_0/utf/private-map_multis.c level_0/utf/private-map_multiss.c level_0/utf/private-string.c level_0/utf/private-triples.c level_0/utf/private-tripless.c +build_sources_library level_0/utf/common.c level_0/utf/convert.c +build_sources_library level_0/utf/dynamic.c level_0/utf/dynamics.c level_0/utf/dynamicss.c +build_sources_library level_0/utf/is.c level_0/utf/is_character.c +build_sources_library level_0/utf/map.c level_0/utf/maps.c level_0/utf/mapss.c +build_sources_library level_0/utf/map_multi.c level_0/utf/map_multis.c level_0/utf/map_multiss.c +build_sources_library level_0/utf/static.c level_0/utf/statics.c level_0/utf/staticss.c +build_sources_library level_0/utf/string.c level_0/utf/triple.c level_0/utf/triples.c level_0/utf/tripless.c +build_sources_library level_0/utf/private-dynamic.c level_0/utf/private-dynamics.c level_0/utf/private-dynamicss.c +build_sources_library level_0/utf/private-maps.c level_0/utf/private-mapss.c +build_sources_library level_0/utf/private-map_multis.c level_0/utf/private-map_multiss.c +build_sources_library level_0/utf/private-string.c +build_sources_library level_0/utf/private-triples.c level_0/utf/private-tripless.c build_sources_library level_1/control_group.c build_sources_library level_1/conversion.c level_1/private-conversion.c level_1/conversion/common.c diff --git a/level_0/f_directory/c/directory/common.h b/level_0/f_directory/c/directory/common.h index a7062b9..85a4251 100644 --- a/level_0/f_directory/c/directory/common.h +++ b/level_0/f_directory/c/directory/common.h @@ -132,9 +132,9 @@ extern "C" { * f_directory_recurse_do_flag_*_e: * For the recurse flag property. * - none: No flags are set. + * - after: Perform this action after recursion befo a single directory path. + * - before: Perform this action before recursion on a single directory path. * - dereference: Dereference symbolic links rather than operating on the link itself. - * - first: Operate on directory first (before recursion). - * - last: Operate on directory last (after recursion). * - top: Operate on top-most directory, or for the callback parameter, designate that this is the top path. * * For the actiona and handle callback parameter: @@ -143,7 +143,7 @@ extern "C" { * - directory: File is a directory. * - fifo: File is a file-in/file-out. * - link: File is a link. - * - path: The "name" represents a path rather than a file name (generally used for error handling or when not processing a recursed file). + * - path: The "name" represents a path rather than a file name (generally used for error handling or when not processing a recursed file). * - regular: File is a regular file. * - socket: File is a socket. * - unknown: File is an unknown type. @@ -153,9 +153,9 @@ extern "C" { // For the recurse flag property. f_directory_recurse_do_flag_none_e = 0, - f_directory_recurse_do_flag_dereference_e = 0x1, - f_directory_recurse_do_flag_first_e = 0x2, - f_directory_recurse_do_flag_last_e = 0x4, + f_directory_recurse_do_flag_after_e = 0x1, + f_directory_recurse_do_flag_before_e = 0x2, + f_directory_recurse_do_flag_dereference_e = 0x4, f_directory_recurse_do_flag_top_e = 0x8, // For the action callback parameter. diff --git a/level_0/f_directory/c/directory/type.c b/level_0/f_directory/c/directory/type.c index bd7c6b6..ad1fc92 100644 --- a/level_0/f_directory/c/directory/type.c +++ b/level_0/f_directory/c/directory/type.c @@ -75,6 +75,9 @@ extern "C" { f_directory_listing_delete(&recurse->listing); + f_string_dynamic_resize(0, &recurse->path); + f_string_dynamic_resize(0, &recurse->path_cache); + return F_none; } #endif // _di_f_directory_recurse_do_delete_ @@ -87,6 +90,9 @@ extern "C" { f_directory_listing_destroy(&recurse->listing); + f_string_dynamic_adjust(0, &recurse->path); + f_string_dynamic_adjust(0, &recurse->path_cache); + return F_none; } #endif // _di_f_directory_recurse_do_destroy_ diff --git a/level_0/f_directory/c/directory/type.h b/level_0/f_directory/c/directory/type.h index 1a18786..01e505c 100644 --- a/level_0/f_directory/c/directory/type.h +++ b/level_0/f_directory/c/directory/type.h @@ -219,46 +219,60 @@ extern "C" { /** * A structure containing directory recursion information. * - * The action() callbacks provide full access to this f_directory_recurse_do_t structure. - * The callback must take care to properly modify the structure or they could cause security, integrity, or functionality problems. + * The action() callback provide full access to this f_directory_recurse_do_t structure. * The action callback may set any of the following on the state.status to have the following effects: * - Any status (with error bit set): Immediately return as error. * - F_break: Break out of the current loop. * - F_continue: Skip to the next iteration in the current loop. * - F_done: Immedately return as success but do nothing else in this recursion. + * * The action parameters are: * - recurse: Must be of type f_directory_recurse_do_t and represents this data. - * - name: The name of the file or directory the action is being performed on (does not have the directory path). + * - name: The name of the file or directory the action is being performed on (does not have the parent directory path) (may be empty at the top level). * - flag: A flag representing the particular action being performed. * + * The handle() callback provides a callback identical to the handle() except that it is for handling exceptions in place of state.handle(). + * The handle() provides additional information not provided by state.handle() but if it is NULL, then state.handle() is called. * The state.handle() and state.interrupt() callbacks internal parameter must be of type f_directory_recurse_do_t. - * The state.handle() is called only when handle is NULL. * - * max_depth: The maximum recursion depth to use. + * The callbacks must take care to properly modify the structure or they could cause security, integrity, or functionality problems. + * * depth: A number representing the depth recursed thus far (generally assigned internally). + * depth_max: The maximum recursion depth to use. * flag: A set of flags used exclusively by the directory recurse process (not to be confused with state.flag). + * mode: A file mode flag to use when working on files, such as when copying a file. + * * state: A pointer to the state information, where state.interrupt() and state.handle() are called appopriately. * listing: A directory listing structure used internally to help reduce repeated memory allocation overhead. - * path: A pointer to the current path string, used for error handling and printing (generally assigned internally). - * path_top: A pointer to the top path string, used for error handling and printing (generally assigned internally). - * action: A callback used for performing some action (this is required to do anything). - * handle: A callback used for performing error handling during recursion directly relating to a file. + * + * path: A path representing the current directory path being operated on and usually represents the parent path of some file or directory (generally assigned internally). + * path_cache: A path-related cache made available for the caller to use, such as combining the path and the file name in the action callback. + * path_top: A pointer to the top path string, used for error handling and printing (generally assigned internally). + * + * custom: Custom data defined by and used by the caller. Set to NULL to not use. + * + * action: A callback used for performing some action (this is required to do anything). + * handle: A callback used for performing error handling during recursion directly relating to a file. * * The macro_f_directory_recurse_do_t_initialize_1() all arguments. * The macro_f_directory_recurse_do_t_initialize_2() all arguments except for internally managed source, destination, mode, and depth. */ #ifndef _di_f_directory_recurse_do_t_ typedef struct { - f_number_unsigned_t max_depth; f_array_length_t depth; + f_number_unsigned_t depth_max; uint16_t flag; + f_mode_t mode; f_state_t state; f_directory_listing_t listing; - const f_string_static_t *path; + f_string_dynamic_t path; + f_string_dynamic_t path_cache; const f_string_static_t *path_top; + void *custom; + void (*action)(void * const recurse, const f_string_static_t name, const uint16_t flag); void (*handle)(void * const recurse, const f_string_static_t name, const uint16_t flag); } f_directory_recurse_do_t; @@ -267,34 +281,43 @@ extern "C" { F_directory_max_recurse_depth_d, \ 0, \ f_directory_recurse_do_flag_none_e, \ + f_mode_t_initialize, \ f_state_t_initialize, \ f_directory_listing_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ 0, \ 0, \ 0, \ 0, \ } - #define macro_f_directory_recurse_do_t_initialize_1(max_depth, depth, flag, state, listing, path, path_top, action, handle) { \ - max_depth, \ + #define macro_f_directory_recurse_do_t_initialize_1(depth, depth_max, flag, mode, state, listing, path, path_cache, path_top, custom, action, handle) { \ depth, \ + depth_max, \ flag, \ + mode, \ state, \ listing, \ path, \ + path_cache, \ path_top, \ + custom, \ action, \ handle, \ } - #define macro_f_directory_recurse_do_t_initialize_2(max_depth, depth, flag, state, action, handle) { \ - max_depth, \ + #define macro_f_directory_recurse_do_t_initialize_2(depth, depth_max, flag, mode, state, custom, action, handle) { \ depth,\ + depth_max \ flag, \ + mode, \ state, \ f_directory_listing_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ 0, \ - 0, \ + custom, \ action, \ handle, \ } @@ -387,9 +410,11 @@ extern "C" { * * F_parameter (with error bit) if a parameter is invalid. * - * Errors (with error bit) from: f_string_dynamics_resize(). + * Errors (with error bit) from: f_directory_listing_delete(). + * Errors (with error bit) from: f_string_dynamic_resize(). * - * @see f_string_dynamics_resize() + * @see f_directory_listing_delete() + * @see f_string_dynamic_resize() */ #ifndef _di_f_directory_recurse_do_delete_ extern f_status_t f_directory_recurse_do_delete(f_directory_recurse_do_t * const recurse); @@ -406,9 +431,11 @@ extern "C" { * * F_parameter (with error bit) if a parameter is invalid. * - * Errors (with error bit) from: f_string_dynamics_adjust(). + * Errors (with error bit) from: f_directory_listing_destroy(). + * Errors (with error bit) from: f_string_dynamic_adjust(). * - * @see f_string_dynamics_adjust() + * @see f_directory_listing_destroy() + * @see f_string_dynamic_adjust() */ #ifndef _di_f_directory_recurse_do_destroy_ extern f_status_t f_directory_recurse_do_destroy(f_directory_recurse_do_t * const recurse); diff --git a/level_1/fl_directory/c/directory.c b/level_1/fl_directory/c/directory.c index ce2e47c..dd51dbb 100644 --- a/level_1/fl_directory/c/directory.c +++ b/level_1/fl_directory/c/directory.c @@ -198,38 +198,30 @@ extern "C" { void fl_directory_do(const f_string_static_t path, f_directory_recurse_do_t * const recurse) { #ifndef _di_level_1_parameter_checking_ if (!recurse) return; - - if (!recurse->action) { - recurse->state.status = F_status_set_error(F_parameter); - - if (recurse->handle) { - recurse->handle((void *) recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e); - } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); - } - - return; - } #endif // _di_level_1_parameter_checking_ - recurse->path = recurse->path_top; + recurse->path.used = 0; + recurse->path_cache.used = 0; recurse->path_top = &path; recurse->depth = 0; recurse->state.status = F_none; recurse->state.data = (void *) recurse; - if (!recurse->path_top->used) { - recurse->state.status = F_data_not; + // Guarantee initialization even for parameter checking failures. + #ifndef _di_level_1_parameter_checking_ + if (!recurse->action) { + recurse->state.status = F_status_set_error(F_parameter); - if (recurse->handle) { - recurse->handle((void *) recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e); - } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); + private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e); + if (F_status_is_error(recurse->state.status)) return; } + #endif // _di_level_1_parameter_checking_ - return; + if (!recurse->path_top->used) { + recurse->state.status = F_data_not; + + private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e); + if (F_status_is_error(recurse->state.status)) return; } recurse->state.status = f_directory_exists(*recurse->path_top); @@ -239,65 +231,97 @@ extern "C" { } if (F_status_is_error(recurse->state.status)) { - if (recurse->handle) { - recurse->handle((void *) recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e); - } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); + private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e); + if (F_status_is_error(recurse->state.status)) return; + } + + if ((recurse->flag & f_directory_recurse_do_flag_top_e) && (recurse->flag & f_directory_recurse_do_flag_before_e)) { + recurse->state.status = F_none; + + recurse->action((void *) recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e | f_directory_recurse_do_flag_before_e); + + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e | f_directory_recurse_do_flag_before_e); + if (F_status_is_error(recurse->state.status)) return; } - return; - } + if (recurse->state.status == F_done) { + recurse->state.status = F_none; - if ((recurse->flag & f_directory_recurse_do_flag_top_e) && (recurse->flag & f_directory_recurse_do_flag_first_e)) { - recurse->action((void *) recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_first_e | f_directory_recurse_do_flag_path_e); + return; + } } - if (F_status_is_error_not(recurse->state.status)) { - if (recurse->max_depth) { - f_array_length_t i = recurse->path_top->used; + if (recurse->depth_max) { + recurse->state.status = f_string_dynamic_append_nulless(path, &recurse->path); - // Do not allow null termination or trailing path separators in the string's length calculation. - for (; i > 0; --i) { - - if (!recurse->path_top->string[i - 1]) continue; - if (recurse->path_top->string[i - 1] == f_path_separator_s.string[0]) continue; + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e); + if (F_status_is_error(recurse->state.status)) return; + } - break; - } // for + // Do not allow trailing path separators in the string's length calculation, except root directory '/'. + for (; recurse->path.used; --recurse->path.used) { + if (recurse->path_top->string[recurse->path.used - 1] != f_path_separator_s.string[0]) break; + } // for - const f_string_static_t static_path = macro_f_string_static_t_initialize(recurse->path_top->string, recurse->path_top->size, i); + recurse->depth = 1; - recurse->path = &static_path; - recurse->depth = 1; + private_fl_directory_do_recurse(recurse); - private_fl_directory_do_recurse(recurse); + recurse->path.used = path.used; + recurse->depth = 0; - recurse->path = recurse->path_top; - recurse->depth = 0; - } - else { - recurse->state.status = F_none; + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e | f_directory_recurse_do_flag_before_e); + if (F_status_is_error(recurse->state.status)) return; } } + else { + recurse->state.status = f_directory_exists(path); - if (F_status_is_error_not(recurse->state.status)) { - if ((recurse->flag & f_directory_recurse_do_flag_top_e) && (recurse->flag & f_directory_recurse_do_flag_last_e)) { - recurse->action((void *) recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_last_e | f_directory_recurse_do_flag_path_e); + if (F_status_is_error_not(recurse->state.status) && recurse->state.status != F_true) { + if (recurse->state.status == F_false) { + recurse->state.status = F_status_set_error(F_directory_not); + } + else { + recurse->state.status = F_status_set_error(recurse->state.status); + } } - } - if (F_status_is_error(recurse->state.status)) { - if (recurse->handle) { - recurse->handle((void *) recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e); + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_directory_e); + if (F_status_is_error(recurse->state.status)) return; } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); + + recurse->state.status = F_none; + + recurse->action((void *) recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_directory_e); + + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_directory_e); + if (F_status_is_error(recurse->state.status)) return; + } + + if (recurse->state.status == F_done) { + recurse->state.status = F_none; + + return; } } - else { + + if ((recurse->flag & f_directory_recurse_do_flag_top_e) && (recurse->flag & f_directory_recurse_do_flag_after_e)) { recurse->state.status = F_none; + + recurse->action((void *) recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e | f_directory_recurse_do_flag_after_e); + } + + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e | f_directory_recurse_do_flag_after_e); + if (F_status_is_error(recurse->state.status)) return; } + + recurse->state.status = F_none; } #endif // _di_fl_directory_do_ diff --git a/level_1/fl_directory/c/directory.h b/level_1/fl_directory/c/directory.h index 24cb42c..df6f74d 100644 --- a/level_1/fl_directory/c/directory.h +++ b/level_1/fl_directory/c/directory.h @@ -158,6 +158,17 @@ extern "C" { * * This is intended to be used as an alternative to functions like fl_directory_list(), giving more control over the recursion process. * + * When recursing the directory, except for the top directory, handle() with the before and after flags set is called after the recurse.path is updated. + * For the top directory, handle() is called with the before and after flags set when the path is not updated (that is, the path should be + * + * This function is designed and intended to be used on directories. + * If depth is 0, the operations callacks are still called but done at the top level. + * + * The action callback must set the error bit to ensure that the handle callbacks are called or not set the error bit to prevent this behavior. + * + * This exists on error if, after the handle callback is called, that the recurse.state.status still has the error bit set. + * This allows for the caller to inform this function to effectively ignore any errors. + * * @param path * The directory file path. * Must be NULL terminated. @@ -174,19 +185,25 @@ extern "C" { * * Errors (with error bit) from: f_directory_create(). * Errors (with error bit) from: f_directory_exists(). - * Errors (with error bit) from: f_string_dynamic_resize(). - * Errors (with error bit) from: f_string_dynamics_resize(). * Errors (with error bit) from: f_file_mode_set(). * Errors (with error bit) from: f_file_role_change(). * Errors (with error bit) from: f_file_stat(). + * Errors (with error bit) from: f_string_dynamic_append_assure(). + * Errors (with error bit) from: f_string_dynamic_append_nulless(). + * Errors (with error bit) from: f_string_dynamic_increase_by(). + * Errors (with error bit) from: f_string_dynamic_resize(). + * Errors (with error bit) from: f_string_dynamics_resize(). * * @see f_directory_create() * @see f_directory_exists() - * @see f_string_dynamic_resize() - * @see f_string_dynamics_resize() * @see f_file_mode_set() * @see f_file_role_change() * @see f_file_stat() + * @see f_string_dynamic_append_assure() + * @see f_string_dynamic_append_nulless() + * @see f_string_dynamic_increase_by() + * @see f_string_dynamic_resize() + * @see f_string_dynamics_resize() */ #ifndef _di_fl_directory_do_ extern void fl_directory_do(const f_string_static_t path, f_directory_recurse_do_t * const recurse); diff --git a/level_1/fl_directory/c/private-directory.c b/level_1/fl_directory/c/private-directory.c index b5ee156..30e901e 100644 --- a/level_1/fl_directory/c/private-directory.c +++ b/level_1/fl_directory/c/private-directory.c @@ -66,7 +66,7 @@ extern "C" { if (F_status_set_fine(recurse->state.status) == F_interrupt) break; } - private_fl_directory_copy_recurse_file(list[i]->array[j], recurse); + private_fl_directory_copy_recurse_file(list[j]->array[i], recurse); } // for list[i]->used = 0; @@ -79,10 +79,10 @@ extern "C" { for (j = 0; j < list[i]->used; ++j) { - list[i]->array[j].used = 0; + list[j]->array[i].used = 0; - if (list[i]->array[j].size > F_directory_max_string_d) { - recurse->state.status = f_string_dynamic_resize(F_directory_max_string_d, &list[i]->array[j]); + if (list[j]->array[i].size > F_directory_max_string_d) { + recurse->state.status = f_string_dynamic_resize(F_directory_max_string_d, &list[j]->array[i]); if (F_status_is_error(recurse->state.status)) break; } } // for @@ -322,28 +322,28 @@ extern "C" { recurse->listing.socket.used = 0; recurse->listing.unknown.used = 0; - recurse->state.status = private_fl_directory_list(*recurse->path, 0, 0, recurse->flag & f_directory_recurse_do_flag_dereference_e, &recurse->listing); + recurse->state.status = private_fl_directory_list(recurse->path, 0, 0, recurse->flag & f_directory_recurse_do_flag_dereference_e, &recurse->listing); if (F_status_is_error(recurse->state.status)) { - if (recurse->handle) { - recurse->handle((void *) recurse, *recurse->path, f_directory_recurse_do_flag_path_e); - } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); - } + private_inline_fl_directory_do_handle(recurse, f_string_empty_s, f_directory_recurse_do_flag_path_e); // Only the directory is to be freed because all others are preserved between recursions. - f_string_dynamics_resize(0, &recurse->listing.directory); + if (F_status_is_error(recurse->state.status)) { + f_string_dynamics_resize(0, &recurse->listing.directory); - recurse->listing.directory.array = directories_original.array; - recurse->listing.directory.used = directories_original.used; - recurse->listing.directory.size = directories_original.size; + recurse->listing.directory.array = directories_original.array; + recurse->listing.directory.used = directories_original.used; + recurse->listing.directory.size = directories_original.size; - return; + return; + } } recurse->state.status = F_none; + f_array_length_t i = 0; + f_array_length_t used_original = 0; + { f_string_dynamics_t * const list[] = { &recurse->listing.block, @@ -365,165 +365,224 @@ extern "C" { f_directory_recurse_do_flag_unknown_e, }; - f_array_length_t j = 0; + for (uint8_t j = 0; j < 7; ++j) { - for (uint8_t i = 0; i < 7; ++i) { - - for (j = 0; j < list[i]->used; ++j) { + for (i = 0; i < list[j]->used; ++i) { if (recurse->state.interrupt) { recurse->state.interrupt((void *) &recurse->state, (void *) recurse); if (F_status_set_fine(recurse->state.status) == F_interrupt) break; } - recurse->state.status = F_none; + used_original = recurse->path.used; - recurse->action((void *) recurse, list[i]->array[j], flags[i]); + recurse->state.status = f_string_dynamic_increase_by(f_path_separator_s.used + list[j]->array[i].used + 1, &recurse->path); - if (F_status_is_error(recurse->state.status)) { - if (recurse->handle) { - recurse->handle((void *) recurse, list[i]->array[j], flags[i]); - } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); - } + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append_assure(f_path_separator_s, &recurse->path); + } - break; + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append_nulless(list[j]->array[i], &recurse->path); } - if (recurse->state.status == F_break) break; - if (recurse->state.status == F_done) break; - } // for + // Guarantee NULL termination. + recurse->path.string[recurse->path.used] = 0; - if (F_status_is_error(recurse->state.status)) break; - if (recurse->state.status == F_done) break; + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, list[j]->array[i], f_directory_recurse_do_flag_directory_e); + if (F_status_is_error(recurse->state.status)) break; + } - list[i]->used = 0; + if (recurse->state.status == F_break || recurse->state.status == F_done) { + recurse->path.used = used_original; - // Use an upper limit when retaining memory between recursion calls. - if (list[i]->size > F_directory_max_list_d) { - recurse->state.status = f_string_dynamics_resize(F_directory_max_list_d, list[i]); + break; + } - if (F_status_is_error(recurse->state.status)) { - if (recurse->handle) { - recurse->handle((void *) recurse, list[i]->array[j], flags[i]); - } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); - } + if (recurse->state.status == F_continue) { + recurse->path.used = used_original; - break; + continue; } - } - for (j = 0; j < list[i]->used; ++j) { + recurse->state.status = F_none; - list[i]->array[j].used = 0; + recurse->action((void *) recurse, list[j]->array[i], flags[j]); - if (list[i]->array[j].size > F_directory_max_string_d) { - recurse->state.status = f_string_dynamic_resize(F_directory_max_string_d, &list[i]->array[j]); + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, list[j]->array[i], flags[j]); if (F_status_is_error(recurse->state.status)) { - if (recurse->handle) { - recurse->handle((void *) recurse, list[i]->array[j], flags[i]); - } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); - } + recurse->path.used = used_original; break; } } + + recurse->path.used = used_original; + + if (recurse->state.status == F_break || recurse->state.status == F_done || recurse->state.status == F_failure) break; + if (recurse->state.status == F_continue) continue; } // for + + if (F_status_is_error(recurse->state.status) || recurse->state.status == F_done) break; } // for } if (recurse->state.status != F_done && F_status_is_error_not(recurse->state.status)) { - for (f_array_length_t i = 0; i < recurse->listing.directory.used; ++i) { + for (i = 0; i < recurse->listing.directory.used; ++i) { if (recurse->state.interrupt) { recurse->state.interrupt((void *) &recurse->state, (void *) recurse); if (F_status_set_fine(recurse->state.status) == F_interrupt) break; } - f_string_static_t path_sub = f_string_static_t_initialize; - - path_sub.used = recurse->path->used + recurse->listing.directory.array[i].used + 1; - path_sub.size = path_sub.used; + used_original = recurse->path.used; - f_char_t path_full_sub[path_sub.used + 1]; + recurse->state.status = f_string_dynamic_increase_by(f_path_separator_s.used + recurse->listing.directory.array[i].used + 1, &recurse->path); - memcpy(path_full_sub, recurse->path->string, sizeof(f_char_t) * recurse->path->used); - memcpy(path_full_sub + recurse->path->used + 1, recurse->listing.directory.array[i].string, sizeof(f_char_t) * recurse->listing.directory.array[i].used); + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append_assure(f_path_separator_s, &recurse->path); + } - path_full_sub[recurse->path->used] = f_path_separator_s.string[0]; - path_full_sub[path_sub.used] = 0; + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append_nulless(recurse->listing.directory.array[i], &recurse->path); + } - path_sub.string = path_full_sub; + // Guarantee NULL termination. + recurse->path.string[recurse->path.used] = 0; - recurse->state.status = f_directory_exists(path_sub); + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_directory_exists(recurse->path); - if (recurse->state.status == F_false) { - recurse->state.status = F_status_set_error(F_directory_not); + if (recurse->state.status == F_false) { + recurse->state.status = F_status_set_error(F_directory_not); + } } if (F_status_is_error(recurse->state.status)) { - if (recurse->handle) { - recurse->handle((void *) recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_directory_e); - } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); + private_inline_fl_directory_do_handle(recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_directory_e); + + if (F_status_is_error(recurse->state.status)) { + recurse->path.used = used_original; + + break; } + } + + if (recurse->state.status == F_break || recurse->state.status == F_done) { + recurse->path.used = used_original; break; } - if (recurse->flag & f_directory_recurse_do_flag_first_e) { - recurse->action((void *) recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_first_e); + if (recurse->state.status == F_continue) { + recurse->path.used = used_original; + + continue; } - if (recurse->depth < recurse->max_depth) { - recurse->path = (f_string_static_t * const) & path_sub; + if (recurse->flag & f_directory_recurse_do_flag_before_e) { + recurse->state.status = F_none; + + recurse->action((void *) recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_before_e | f_directory_recurse_do_flag_directory_e); + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_before_e | f_directory_recurse_do_flag_directory_e); + + if (F_status_is_error(recurse->state.status)) { + recurse->state.status = F_failure; + + break; + } + } + } + + if (recurse->state.status == F_break || recurse->state.status == F_done) { + recurse->path.used = used_original; + + break; + } + + if (recurse->state.status == F_continue) { + recurse->path.used = used_original; + + continue; + } + + if (recurse->depth < recurse->depth_max) { ++recurse->depth; private_fl_directory_do_recurse(recurse); - // Data must be restored after recursion. - recurse->path = (f_string_static_t * const) & path_sub; + --recurse->depth; - // Success inside the recursed function is handled inside the recursed function, so handle at the current depth. - if (recurse->state.status == F_none) { - --recurse->depth; + if (recurse->state.status == F_done || recurse->state.status == F_failure) { + recurse->path.used = used_original; + + break; } + } + else { + recurse->state.status = F_none; - // Errors in the recursed function are handled outside the recursed function here. - else if (F_status_is_error(recurse->state.status)) { - if (recurse->handle) { - recurse->handle((void *) recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_directory_e); - } - else if (recurse->state.handle) { - recurse->state.handle(&recurse->state, (void *) recurse); - } + recurse->action((void *) recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_directory_e); - recurse->state.status = F_failure; + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_directory_e); + + if (F_status_is_error(recurse->state.status)) { + recurse->path.used = used_original; + + break; + } } - // Error is now handled or is done, so update the depth and exit. - if (recurse->state.status == F_done || recurse->state.status == F_failure) { - --recurse->depth; + if (recurse->state.status == F_break || recurse->state.status == F_done || recurse->state.status == F_failure) { + recurse->path.used = used_original; break; } + + if (recurse->state.status == F_continue) { + recurse->path.used = used_original; + + continue; + } } - recurse->state.status = F_none; + if (recurse->flag & f_directory_recurse_do_flag_after_e) { + recurse->state.status = F_none; + + recurse->action((void *) recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_after_e | f_directory_recurse_do_flag_directory_e); - if (recurse->flag & f_directory_recurse_do_flag_last_e) { - recurse->action((void *) recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_last_e); + if (F_status_is_error(recurse->state.status)) { + private_inline_fl_directory_do_handle(recurse, recurse->listing.directory.array[i], f_directory_recurse_do_flag_after_e | f_directory_recurse_do_flag_directory_e); + + if (F_status_is_error(recurse->state.status)) { + recurse->state.status = F_failure; + recurse->path.used = used_original; + + break; + } + } + + if (recurse->state.status == F_break || recurse->state.status == F_done || recurse->state.status == F_failure) { + recurse->path.used = used_original; + + break; + } + + if (recurse->state.status == F_continue) { + recurse->path.used = used_original; + + continue; + } } recurse->state.status = F_none; + recurse->path.used = used_original; } // for } diff --git a/level_1/fl_directory/c/private-directory.h b/level_1/fl_directory/c/private-directory.h index facc945..c151642 100644 --- a/level_1/fl_directory/c/private-directory.h +++ b/level_1/fl_directory/c/private-directory.h @@ -75,6 +75,34 @@ extern "C" { #endif // !defined(_di_fl_directory_do_) /** + * Private inline function for use by fl_directory_do(). + * + * Intended to simplify code similar to using a macro function. + * + * This calls the handle callback as is appropriate. + * + * @param recurse + * The directory recurse data. + * + * @return + * F_none on success. + * + * F_failure (with error bit) for any other failure, failures might be populated with individual status codes. + * + * @see fl_directory_do() + */ +#if !defined(_di_fl_directory_do_) + static inline void private_inline_fl_directory_do_handle(f_directory_recurse_do_t * const recurse, const f_string_static_t path, const uint16_t flag) { + if (recurse->handle) { + recurse->handle((void *) recurse, path, flag); + } + else if (recurse->state.handle) { + recurse->state.handle(&recurse->state, (void *) recurse); + } + } +#endif // !defined(_di_fl_directory_do_) + +/** * A special function intended to be used directly by fl_directory_list(). * * @param path diff --git a/level_3/fake/c/main/build.c b/level_3/fake/c/main/build.c index 8c3fee6..22612a8 100644 --- a/level_3/fake/c/main/build.c +++ b/level_3/fake/c/main/build.c @@ -167,45 +167,38 @@ extern "C" { fake_main_t * const main = data->main; - f_directory_statuss_t failures = f_directory_statuss_t_initialize; - f_string_dynamic_t path_source = f_string_dynamic_t_initialize; // @todo move this to a shared buffer. - f_string_dynamic_t destination_file = f_string_dynamic_t_initialize; - f_string_dynamic_t destination_directory = f_string_dynamic_t_initialize; + fake_string_dynamic_reset(&main->cache_argument); + f_string_static_t buffer = f_string_static_t_initialize; - fake_local_t local = macro_fake_local_t_initialize_1(main, &failures, 0); + f_status_t failed = F_none; + fake_local_t local = macro_fake_local_t_initialize_1(main, &main->cache_map, &failed); - if (main->program.message.verbosity != f_console_verbosity_quiet_e && main->program.message.verbosity != f_console_verbosity_error_e) { - fll_print_format("%r%[Copying %Q.%]%r", main->program.message.to, f_string_eol_s, main->program.context.set.important, label, main->program.context.set.important, f_string_eol_s); - } + fake_build_print_message_copying(&main->program.message, label); - main->setting.state.status = f_string_dynamic_resize(source.used, &path_source); + main->setting.state.status = f_string_dynamic_append_nulless(source, &main->cache_argument); if (F_status_is_error(main->setting.state.status)) { - fake_print_error(&main->program.error, macro_fake_f(f_string_dynamic_resize)); - - f_string_dynamic_resize(0, &path_source); + fake_print_error(&main->program.error, macro_fake_f(f_string_dynamic_append_nulless)); return; } - memcpy(path_source.string, source.string, sizeof(f_char_t) * source.used); - - f_directory_recurse_copy_t recurse = f_directory_recurse_copy_t_initialize; - recurse.verbose = &fake_print_verbose_recursive_copy; + f_directory_recurse_do_t recurse = f_directory_recurse_do_t_initialize; + recurse.action = &fake_build_copy_action; + recurse.handle = &fake_build_copy_handle; recurse.state.custom = (void *) &local; recurse.state.code = fake_state_code_local_e; + recurse.flag = f_directory_recurse_do_flag_top_e & f_directory_recurse_do_flag_before_e & f_directory_recurse_do_flag_after_e; recurse.mode = mode; - f_array_length_t j = 0; - for (f_array_length_t i = 0; i < files.used; ++i) { if (fake_signal_check(main)) break; if (!files.array[i].used) continue; - path_source.used = source.used; + main->cache_argument.used = source.used; - main->setting.state.status = f_string_dynamic_append_nulless(files.array[i], &path_source); + main->setting.state.status = f_string_dynamic_append_nulless(files.array[i], &main->cache_argument); if (F_status_is_error(main->setting.state.status)) { fake_print_error(&main->program.error, macro_fake_f(f_string_dynamic_append_nulless)); @@ -213,12 +206,12 @@ extern "C" { break; } - main->setting.state.status = f_directory_is(path_source); + main->setting.state.status = f_directory_is(main->cache_argument); if (main->setting.state.status == F_true) { - destination_directory.used = 0; + main->cache_map.name.used = 0; - main->setting.state.status = f_string_dynamic_append_nulless(destination, &destination_directory); + main->setting.state.status = f_string_dynamic_append_nulless(destination, &main->cache_map.name); if (F_status_is_error(main->setting.state.status)) { fake_print_error(&main->program.error, macro_fake_f(f_string_dynamic_append_nulless)); @@ -226,7 +219,7 @@ extern "C" { break; } - main->setting.state.status = f_file_name_base(path_source, &destination_directory); + main->setting.state.status = f_file_name_base(main->cache_argument, &main->cache_map.name); if (F_status_is_error(main->setting.state.status)) { fake_print_error(&main->program.error, macro_fake_f(f_file_name_base)); @@ -234,33 +227,14 @@ extern "C" { break; } - // @todo replace fl_directory_copy() with fl_directory_do() because it has better error handling. - // @todo once this is done, then consider removing fl_directory_copy() entirely. - // @todo consider providing a copy/clone/move callback in FLL in place of fl_directory_copy() that can be passed to fl_directory_do(). - fl_directory_copy(path_source, destination_directory, &recurse); - - if (F_status_is_error(main->setting.state.status)) { - if (main->program.error.verbosity >= f_console_verbosity_verbose_e) { - for (j = 0; j < failures.used; ++j) { - fake_print_error_build_operation_file(&main->program.error, macro_fake_f(fl_directory_copy), fake_common_file_directory_copy_s, f_file_operation_to_s, path_source, destination_directory, F_true); - } // for - - if (F_status_set_fine(main->setting.state.status) != F_failure) { - fake_print_error(&main->program.error, macro_fake_f(fl_directory_copy)); - } - } - else if (main->program.error.verbosity > f_console_verbosity_quiet_e) { - fake_print_error_build_operation_file(&main->program.error, macro_fake_f(fl_directory_copy), fake_common_file_directory_copy_s, f_file_operation_to_s, path_source, destination_directory, F_true); - } - - break; - } + fl_directory_do(main->cache_argument, &recurse); + if (F_status_is_error(main->setting.state.status)) break; } else if (main->setting.state.status == F_false) { - destination_file.used = 0; - destination_directory.used = 0; + fake_string_dynamic_reset(&main->cache_map.name); + fake_string_dynamic_reset(&main->cache_map.value); - main->setting.state.status = f_string_dynamic_append_nulless(destination, &destination_file); + main->setting.state.status = f_string_dynamic_append_nulless(destination, &main->cache_map.value); if (F_status_is_error(main->setting.state.status)) { fake_print_error(&main->program.error, macro_fake_f(f_string_dynamic_append_nulless)); @@ -268,8 +242,8 @@ extern "C" { break; } - if (perserve_offset && perserve_offset < path_source.used) { - main->setting.state.status = f_string_dynamic_append_nulless(destination, &destination_directory); + if (perserve_offset && perserve_offset < main->cache_argument.used) { + main->setting.state.status = f_string_dynamic_append_nulless(destination, &main->cache_map.name); if (F_status_is_error(main->setting.state.status)) { fake_print_error(&main->program.error, macro_fake_f(f_string_dynamic_append_nulless)); @@ -277,10 +251,10 @@ extern "C" { break; } - buffer.string = path_source.string + perserve_offset; - buffer.used = path_source.used - perserve_offset; + buffer.string = main->cache_argument.string + perserve_offset; + buffer.used = main->cache_argument.used - perserve_offset; - main->setting.state.status = f_file_name_directory(buffer, &destination_directory); + main->setting.state.status = f_file_name_directory(buffer, &main->cache_map.name); if (F_status_is_error(main->setting.state.status)) { fake_print_error(&main->program.error, macro_fake_f(f_file_name_directory)); @@ -288,15 +262,15 @@ extern "C" { break; } - main->setting.state.status = fl_directory_create(destination_directory, F_file_mode_all_rwx_d); + main->setting.state.status = fl_directory_create(main->cache_map.name, F_file_mode_all_rwx_d); if (F_status_is_error(main->setting.state.status)) { - fake_print_error_file(&main->program.error, macro_fake_f(fl_directory_create), destination_directory, f_file_operation_create_s, fll_error_file_type_directory_e); + fake_print_error_file(&main->program.error, macro_fake_f(fl_directory_create), main->cache_map.name, f_file_operation_create_s, fll_error_file_type_directory_e); break; } - main->setting.state.status = f_string_append(path_source.string + perserve_offset, path_source.used - perserve_offset, &destination_file); + main->setting.state.status = f_string_append(main->cache_argument.string + perserve_offset, main->cache_argument.used - perserve_offset, &main->cache_map.value); if (F_status_is_error(main->setting.state.status)) { fake_print_error(&main->program.error, macro_fake_f(f_string_append)); @@ -305,7 +279,7 @@ extern "C" { } } else { - main->setting.state.status = f_file_name_base(path_source, &destination_file); + main->setting.state.status = f_file_name_base(main->cache_argument, &main->cache_map.value); if (F_status_is_error(main->setting.state.status)) { fake_print_error(&main->program.error, macro_fake_f(f_file_name_base)); @@ -314,18 +288,18 @@ extern "C" { } } - main->setting.state.status = f_file_copy(path_source, destination_file, mode, F_file_default_read_size_d, f_file_stat_flag_reference_e); + fake_build_print_verbose_copying(&main->program.message, main->cache_argument, main->cache_map.value); + + main->setting.state.status = f_file_copy(main->cache_argument, main->cache_map.value, mode, F_file_default_read_size_d, f_file_stat_flag_reference_e); if (F_status_is_error(main->setting.state.status)) { - fake_print_error_build_operation_file(&main->program.error, macro_fake_f(f_file_copy), f_file_operation_copy_s, f_file_operation_to_s, path_source, destination_file, F_true); + fake_print_error_build_operation_file(&main->program.error, macro_fake_f(f_file_copy), f_file_operation_copy_s, f_file_operation_to_s, main->cache_argument, main->cache_map.value, F_true); break; } - - fake_build_print_verbose_copied_file(&main->program.message, path_source, destination_file); } else if (F_status_is_error(main->setting.state.status)) { - fake_print_error_file(&main->program.error, macro_fake_f(f_directory_is), path_source, f_file_operation_create_s, fll_error_file_type_file_e); + fake_print_error_file(&main->program.error, macro_fake_f(f_directory_is), main->cache_argument, f_file_operation_create_s, fll_error_file_type_file_e); break; } @@ -333,18 +307,191 @@ extern "C" { main->setting.state.status = F_none; } // for - f_directory_recurse_copy_delete(&recurse); - - f_string_dynamic_resize(0, &path_source); - f_string_dynamic_resize(0, &destination_file); - f_string_dynamic_resize(0, &destination_directory); + if (F_status_is_error(failed)) { + main->setting.state.status = F_status_set_error(F_failure); + } - f_directory_statuss_resize(0, &failures); + f_directory_recurse_do_delete(&recurse); fake_build_touch(data, file_stage); } #endif // _di_fake_build_copy_ +#ifndef _di_fake_build_copy_action_ + void fake_build_copy_action(void * const void_recurse, const f_string_static_t name, const uint16_t flag) { + + if (!void_recurse) return; + + f_directory_recurse_do_t * const recurse = (f_directory_recurse_do_t *) void_recurse; + + if (!recurse->custom) return; + + fake_local_t * const local = (fake_local_t *) recurse->custom; + + if (!local->custom_1) { + recurse->state.status = F_status_set_error(F_parameter); + + return; + } + + f_string_map_t * const map_destination = (f_string_map_t *) local->custom_1; + + if (flag & f_directory_recurse_do_flag_top_e) { + fake_string_dynamic_reset(&map_destination->value); + + recurse->state.status = F_none; + + return; + } + + if (flag & f_directory_recurse_do_flag_before_e) { + + // Push the name on the path stack (the destination path is expected to be pre-populated). + recurse->state.status = f_string_dynamic_increase_by(f_path_separator_s.used + name.used + 1, &map_destination->name); + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append(f_path_separator_s, &map_destination->name); + } + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append_nulless(name, &map_destination->name); + } + + // Guaranetee NULL terminated string. + map_destination->name.string[map_destination->name.used] = 0; + + return; + } + + if (flag & f_directory_recurse_do_flag_after_e) { + + // Pop the current path off of the path stack. + map_destination->name.used -= f_path_separator_s.used + name.used; + + recurse->state.status = F_none; + + return; + } + + fake_string_dynamic_reset(&recurse->path_cache); + fake_string_dynamic_reset(&map_destination->value); + + recurse->state.status = f_string_dynamic_increase_by(recurse->path.used + f_path_separator_s.used + name.used + 1, &recurse->path_cache); + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append_nulless(map_destination->name, &recurse->path_cache); + } + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append(f_path_separator_s, &recurse->path_cache); + } + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append_nulless(name, &recurse->path_cache); + } + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_increase_by(map_destination->name.used + f_path_separator_s.used + name.used + 1, &map_destination->value); + } + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append_nulless(map_destination->name, &map_destination->value); + } + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append(f_path_separator_s, &map_destination->value); + } + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = f_string_dynamic_append_nulless(name, &map_destination->value); + } + + // Guaranetee NULL terminated strings. + recurse->path_cache.string[recurse->path_cache.used] = 0; + map_destination->value.string[map_destination->value.used] = 0; + + if (F_status_is_error(recurse->state.status)) { + fake_string_dynamic_reset(&map_destination->value); + + return; + } + + fake_build_print_verbose_copying(&local->main->program.message, recurse->path_cache, map_destination->value); + + recurse->state.status = f_file_copy(recurse->path_cache, map_destination->value, recurse->mode, F_file_default_read_size_d, f_file_stat_flag_reference_e); + } +#endif // _di_fake_build_copy_action_ + +#ifndef _di_fake_build_copy_handle_ + void fake_build_copy_handle(void * const void_recurse, const f_string_static_t name, const uint16_t flag) { + + if (!void_recurse) return; + + f_directory_recurse_do_t * const recurse = (f_directory_recurse_do_t *) void_recurse; + + // Do not print any errors on interrupts. + if (F_status_set_fine(recurse->state.status) == F_interrupt) return; + + if (!recurse->custom) return; + + fake_local_t * const local = (fake_local_t *) recurse->custom; + + if (!local->main || !local->custom_1 || !local->custom_2) return; + + *((f_status_t *) local->custom_2) = F_status_set_error(F_failure); + + if (flag & f_directory_recurse_do_flag_top_e) { + local->main->setting.state.status = recurse->state.status; + + if (flag == (f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e)) { + fake_print_error_file(&local->main->program.error, macro_fake_f(fl_directory_do), *recurse->path_top, f_file_operation_copy_s, fll_error_file_type_directory_e); + } + else if (flag == (f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_before_e | f_directory_recurse_do_flag_path_e)) { + fake_print_error_file(&local->main->program.error, macro_fake_f(f_directory_exists), *recurse->path_top, f_file_operation_copy_s, fll_error_file_type_directory_e); + } + else if (flag == (f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_after_e | f_directory_recurse_do_flag_path_e)) { + fake_print_error_file(&local->main->program.error, macro_fake_f(fl_directory_do), *recurse->path_top, f_file_operation_copy_s, fll_error_file_type_directory_e); + } + + return; + } + + f_string_map_t * const map_destination = (f_string_map_t *) local->custom_1; + + if (flag == (flag & f_directory_recurse_do_flag_path_e)) { + // @todo this is old and may not be correct anymore. + fake_print_error_build_operation_file_recurse(&local->main->program.error, macro_fake_f(fl_directory_list), f_file_operation_copy_s, f_file_operation_to_s, recurse->path, name, map_destination->name, name, F_true); + + return; + } + + if (flag & f_directory_recurse_do_flag_directory_e) { + // @todo + + //fake_print_error_build_operation_file_recurse(&local->main->program.error, macro_fake_f(f_file_copy), f_file_operation_copy_s, f_file_operation_to_s, recurse->path, name, map_destination->name, name, F_true); + + return; + } + + // The value.used is set to 0 on allocation related failures so that better error messaging can be performed. + if (map_destination->value.used) { + fake_print_error_build_operation_file_recurse(&local->main->program.error, macro_fake_f(f_file_copy), f_file_operation_copy_s, f_file_operation_to_s, recurse->path, name, map_destination->name, name, F_true); + } + else if (map_destination->name.used) { + f_char_t destination[map_destination->name.used + f_path_separator_s.used + name.used]; + + memcpy(destination, map_destination->name.string, map_destination->name.used); + memcpy(destination + map_destination->name.used, f_path_separator_s.string, f_path_separator_s.used); + memcpy(destination + map_destination->name.used + f_path_separator_s.used, name.string, name.used); + + fake_print_error_build_operation_file_recurse(&local->main->program.error, macro_fake_f(f_file_copy), f_file_operation_copy_s, f_file_operation_to_s, recurse->path, name, map_destination->name, name, F_true); + } + else { + fake_print_error_build_operation_file_recurse(&local->main->program.error, macro_fake_f(fl_directory_do), f_file_operation_copy_s, f_file_operation_to_s, recurse->path, name, f_string_empty_s, f_string_empty_s, F_true); + } + } +#endif // _di_fake_build_copy_handle_ + #ifndef _di_fake_build_execute_process_script_ int fake_build_execute_process_script(fake_data_t * const data, fake_build_data_t * const data_build, const f_string_static_t process_script, const f_string_static_t file_stage) { diff --git a/level_3/fake/c/main/build.h b/level_3/fake/c/main/build.h index b579f88..b457cfa 100644 --- a/level_3/fake/c/main/build.h +++ b/level_3/fake/c/main/build.h @@ -56,10 +56,12 @@ extern "C" { * Errors (with error bit) from: f_file_name_base() * Errors (with error bit) from: f_file_name_directory() * Errors (with error bit) from: f_string_append() + * Errors (with error bit) from: f_string_dynamic_append() * Errors (with error bit) from: f_string_dynamic_append_nulless() * Errors (with error bit) from: f_string_dynamic_resize() * Errors (with error bit) from: fl_directory_create() * Errors (with error bit) from: fl_directory_copy() + * Errors (with error bit) from: fl_directory_do() * @param mode * The modes for each file type. * @param label @@ -91,6 +93,7 @@ extern "C" { * @see f_string_dynamic_resize() * @see fl_directory_create() * @see fl_directory_copy() + * @see fl_directory_do() * @see fll_program_print_signal_received() */ #ifndef _di_fake_build_copy_ @@ -98,6 +101,53 @@ extern "C" { #endif // _di_fake_build_copy_ /** + * Callback for performing an action regarding the copy operation for fake_build_copy(). + * + * @param recurse + * The recuse structure. + * Must be of type f_directory_recurse_do_t. + * + * This does not alter local.main.setting.state.status. + * + * This alters data.main->setting.state.status: + * @todo document this. + * @param name + * The directory name currently being process based on the flag. + * @param flag + * The flags representing the action. + * + * @see f_string_dynamic_append() + * @see f_string_dynamic_increase_by() + * + * @see fake_build_copy() + */ +#ifndef _di_fake_build_copy_action_ + extern void fake_build_copy_action(void * const recurse, const f_string_static_t name, const uint16_t flag); +#endif // _di_fake_build_copy_action_ + +/** + * Callback for handling an error regarding the copy operation for fake_build_copy(). + * + * @param recurse + * The recuse structure. + * Must be of type f_directory_recurse_do_t. + * + * This alters local.main.setting.state.status: + * Assigns value from recurse.state.status. + * + * This does not alter recurse.state.status. + * @param name + * The directory name currently being process based on the flag. + * @param flag + * The flags representing the action. + * + * @see fake_build_copy() + */ +#ifndef _di_fake_build_copy_handle_ + extern void fake_build_copy_handle(void * const recurse, const f_string_static_t name, const uint16_t flag); +#endif // _di_fake_build_copy_handle_ + +/** * Execute the Pre-Process or Post-pocess build script. * * @param data diff --git a/level_3/fake/c/main/build/print/message.c b/level_3/fake/c/main/build/print/message.c index b18885f..3f7b0a0 100644 --- a/level_3/fake/c/main/build/print/message.c +++ b/level_3/fake/c/main/build/print/message.c @@ -4,6 +4,19 @@ extern "C" { #endif +#ifndef _di_fake_build_print_message_copying_ + f_status_t fake_build_print_message_copying(fl_print_t * const print, const f_string_static_t path) { + + if (!print) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_normal_e) return F_output_not; + + fll_print_dynamic_raw(f_string_eol_s, print->to); + fake_print_context_important_simple_variable(print, "Copying ", path, 0); + + return F_none; + } +#endif // _di_fake_build_print_message_copying_ + #ifndef _di_fake_build_print_message_skeleton_build_base_ f_status_t fake_build_print_message_skeleton_build_base(fl_print_t * const print) { diff --git a/level_3/fake/c/main/build/print/message.h b/level_3/fake/c/main/build/print/message.h index 63f0ffd..8312d62 100644 --- a/level_3/fake/c/main/build/print/message.h +++ b/level_3/fake/c/main/build/print/message.h @@ -17,6 +17,30 @@ extern "C" { #endif /** + * Print message when copying. + * + * @param print + * The output structure to print to. + * + * This requires print.custom to be fake_main_t. + * + * This does not alter print.custom.setting.state.status. + * @param path + * The path being copied. + * + * @return + * F_none on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fake_print_context_important_simple_variable() + */ +#ifndef _di_fake_build_print_message_copying_ + extern f_status_t fake_build_print_message_copying(fl_print_t * const print, const f_string_static_t path); +#endif // _di_fake_build_print_message_copying_ + +/** * Print message when building base skeleton directories. * * @param print diff --git a/level_3/fake/c/main/build/print/verbose.c b/level_3/fake/c/main/build/print/verbose.c index 9a84613..ae8bf1c 100644 --- a/level_3/fake/c/main/build/print/verbose.c +++ b/level_3/fake/c/main/build/print/verbose.c @@ -4,17 +4,17 @@ extern "C" { #endif -#ifndef _di_fake_build_print_verbose_copied_file_ - f_status_t fake_build_print_verbose_copied_file(fl_print_t * const print, const f_string_static_t source, const f_string_static_t destination) { +#ifndef _di_fake_build_print_verbose_copying_ + f_status_t fake_build_print_verbose_copying(fl_print_t * const print, const f_string_static_t source, const f_string_static_t destination) { if (!print) return F_status_set_error(F_output_not); if (print->verbosity < f_console_verbosity_verbose_e) return F_output_not; - fake_print_common_wrapped_variables(print, "Copied file ", source, " to ", destination, f_string_empty_s.string); + fake_print_common_wrapped_variables(print, "Copying file ", source, " to ", destination, f_string_empty_s.string); return F_none; } -#endif // _di_fake_build_print_verbose_copied_file_ +#endif // _di_fake_build_print_verbose_copying_ #ifndef _di_fake_build_print_verbose_create_directory_ f_status_t fake_build_print_verbose_create_directory(fl_print_t * const print, const f_string_static_t directory) { diff --git a/level_3/fake/c/main/build/print/verbose.h b/level_3/fake/c/main/build/print/verbose.h index 87cf9e2..97100d7 100644 --- a/level_3/fake/c/main/build/print/verbose.h +++ b/level_3/fake/c/main/build/print/verbose.h @@ -38,9 +38,9 @@ extern "C" { * * @see fake_print_common_wrapped_variables() */ -#ifndef _di_fake_build_print_verbose_copied_file_ - extern f_status_t fake_build_print_verbose_copied_file(fl_print_t * const print, const f_string_static_t source, const f_string_static_t destination); -#endif // _di_fake_build_print_verbose_create_directory_ +#ifndef _di_fake_build_print_verbose_copying_ + extern f_status_t fake_build_print_verbose_copying(fl_print_t * const print, const f_string_static_t source, const f_string_static_t destination); +#endif // _di_fake_build_print_verbose_copying_ /** * Print verbose message about _di_fake_build_print_verbose_copied_file_ a directory. diff --git a/level_3/fake/c/main/common/print.c b/level_3/fake/c/main/common/print.c index 28ba08c..5838024 100644 --- a/level_3/fake/c/main/common/print.c +++ b/level_3/fake/c/main/common/print.c @@ -72,6 +72,8 @@ extern "C" { "fl_conversion_dynamic_to_unsigned_detect", "fl_directory_copy", "fl_directory_create", + "fl_directory_do", + "fl_directory_list", "fl_environment_load_name", "fl_environment_load_names", "fl_iki_read", diff --git a/level_3/fake/c/main/common/print.h b/level_3/fake/c/main/common/print.h index 7db7373..4ed4cc3 100644 --- a/level_3/fake/c/main/common/print.h +++ b/level_3/fake/c/main/common/print.h @@ -105,6 +105,8 @@ extern "C" { fake_f_fl_conversion_dynamic_to_unsigned_detect_e, fake_f_fl_directory_copy_e, fake_f_fl_directory_create_e, + fake_f_fl_directory_do_e, + fake_f_fl_directory_list_e, fake_f_fl_environment_load_name_e, fake_f_fl_environment_load_names_e, fake_f_fl_iki_read_e, diff --git a/level_3/fake/c/main/common/type.c b/level_3/fake/c/main/common/type.c index 1a92d91..3f2aa0d 100644 --- a/level_3/fake/c/main/common/type.c +++ b/level_3/fake/c/main/common/type.c @@ -193,6 +193,9 @@ extern "C" { f_string_dynamic_resize(0, &main->cache_argument); f_string_dynamics_resize(0, &main->cache_arguments); + f_string_dynamic_resize(0, &main->cache_map.name); + f_string_dynamic_resize(0, &main->cache_map.value); + f_iki_data_delete(&main->cache_iki); } #endif // _di_fake_main_data_delete_ diff --git a/level_3/fake/c/main/common/type.h b/level_3/fake/c/main/common/type.h index ce65a34..cdf05a1 100644 --- a/level_3/fake/c/main/common/type.h +++ b/level_3/fake/c/main/common/type.h @@ -131,6 +131,8 @@ extern "C" { * cache_argument: A string cache for some argument. * cache_argument: A string cache for some path. * cache_arguments: An array of strings cache for arguments. + * cache_map: A string map cache. + * cach_iki: IKI data cache. */ #ifndef _di_fake_main_t_ typedef struct { @@ -142,6 +144,7 @@ extern "C" { f_string_dynamic_t cache_2; f_string_dynamic_t cache_argument; f_string_dynamics_t cache_arguments; + f_string_map_t cache_map; f_iki_data_t cache_iki; } fake_main_t; @@ -154,6 +157,7 @@ extern "C" { f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamics_t_initialize, \ + f_string_map_t_initialize, \ f_iki_data_t_initialize, \ } #endif // _di_fake_main_t_ diff --git a/level_3/fake/c/main/print/error.c b/level_3/fake/c/main/print/error.c index 83b1a64..310f299 100644 --- a/level_3/fake/c/main/print/error.c +++ b/level_3/fake/c/main/print/error.c @@ -33,7 +33,7 @@ extern "C" { #ifndef _di_fake_print_error_build_operation_file_ f_status_t fake_print_error_build_operation_file(fl_print_t * const print, const f_string_t function, const f_string_static_t operation, const f_string_static_t source, const f_string_static_t destination, const f_string_static_t how, const bool fallback) { - if (!print->custom) return F_status_set_error(F_output_not); + if (!print || !print->custom) return F_status_set_error(F_output_not); if (print->verbosity < f_console_verbosity_error_e) return F_output_not; fake_main_t * const main = (fake_main_t *) print->custom; @@ -205,6 +205,7 @@ extern "C" { #ifndef _di_fake_print_error_build_operation_file_partial_ void fake_print_error_build_operation_file_partial(fl_print_t * const print, const f_string_static_t operation, const f_string_static_t source, const f_string_static_t destination, const f_string_static_t how) { + if (!print) return; if (print->verbosity < f_console_verbosity_error_e || !source.used) return; fl_print_format("%[while trying to %Q '%]", print->to, print->context, operation, print->context); @@ -219,6 +220,37 @@ extern "C" { } #endif // _di_fake_print_error_build_operation_file_partial_ +#ifndef _di_fake_print_error_build_operation_file_recurse_ + f_status_t fake_print_error_build_operation_file_recurse(fl_print_t * const print, const f_string_t function, const f_string_static_t operation, const f_string_static_t source_path, const f_string_static_t source_name, const f_string_static_t destination_path, const f_string_static_t destination_name, const f_string_static_t how, const bool fallback) { + + if (!print) return F_status_set_error(F_output_not); + + f_char_t source_array[source_path.used + source_name.used + 1]; + source_array[source_path.used + source_name.used] = 0; + + memcpy(source_array, source_path.string, source_path.used); + memcpy(source_array + source_path.used, f_path_separator_s.string, f_path_separator_s.used); + memcpy(source_array + source_path.used + f_path_separator_s.used, source_name.string, source_name.used); + + const f_string_static_t source = macro_f_string_static_t_initialize(source_array, 0, source_path.used + f_path_separator_s.used + source_name.used); + + if (destination_path.used || destination_name.used) { + f_char_t destination_array[destination_path.used + destination_name.used + 1]; + destination_array[destination_path.used + destination_name.used] = 0; + + memcpy(destination_array, destination_path.string, destination_path.used); + memcpy(destination_array + destination_path.used, f_path_separator_s.string, f_path_separator_s.used); + memcpy(destination_array + destination_path.used + f_path_separator_s.used, destination_name.string, destination_name.used); + + const f_string_static_t destination = macro_f_string_static_t_initialize(source_array, 0, destination_path.used + f_path_separator_s.used + destination_name.used); + + return fake_print_error_build_operation_file(print, function, operation, source, destination, how, fallback); + } + + return fake_print_error_build_operation_file(print, function, operation, source, f_string_empty_s, how, fallback); + } +#endif // _di_fake_print_error_build_operation_file_recurse_ + #ifndef _di_fake_print_error_directory_create_parent_missing_ f_status_t fake_print_error_directory_create_parent_missing(fl_print_t * const print, const f_string_static_t path) { diff --git a/level_3/fake/c/main/print/error.h b/level_3/fake/c/main/print/error.h index 7d9dbe4..957d455 100644 --- a/level_3/fake/c/main/print/error.h +++ b/level_3/fake/c/main/print/error.h @@ -96,7 +96,7 @@ extern "C" { * F_false is returned on successful print of known errors. * F_output_not on success, but no printing is performed. * - * F_output_not (with error bit) if setting is NULL. + * F_output_not (with error bit) if print is NULL. * * @see f_file_stream_lock() * @see f_file_stream_unlock() @@ -137,7 +137,7 @@ extern "C" { * F_none on success. * F_output_not on success, but no printing is performed. * - * F_output_not (with error bit) if setting is NULL. + * F_output_not (with error bit) if print is NULL. * * @see f_file_stream_lock() * @see f_file_stream_unlock() @@ -179,6 +179,47 @@ extern "C" { #endif // _di_fake_print_error_build_operation_file_partial_ /** + * Print build operation file error messages for recursive functions that have separate path and name variables. + * + * @param setting + * The main program settings. + * + * This does not alter setting.state.status. + * @param print + * Designates the how and where to print. + * @param function + * The name of the function where the error happened. + * @param operation + * The operation performed. + * @param source_path + * The operation source directory path. + * @param source_name + * The operation source base file name. + * @param destination_path + * The operation destination directory name, if applicable. + * Set destination_path.used and destination_name.used to 0 to disable. + * @param destination_name + * The operation destination base file name, if applicable. + * Set destination_path.used and destination_name.used to 0 to disable. + * @param how + * The how the operation is perform, such as "to" in "copy" source "to" destination. + * @param fallback + * Set to F_true to print the fallback error message for unknown errors. + * + * @return + * F_true is returned if the status code has no print message. + * F_false is returned on successful print of known errors. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if print is NULL. + * + * @see fake_print_error_build_operation_file() + */ +#ifndef _di_fake_print_error_build_operation_file_recurse_ + extern f_status_t fake_print_error_build_operation_file_recurse(fl_print_t * const print, const f_string_t function, const f_string_static_t operation, const f_string_static_t source_path, const f_string_static_t source_name, const f_string_static_t destination_path, const f_string_static_t destination_name, const f_string_static_t how, const bool fallback); +#endif // _di_fake_print_error_build_operation_file_recurse_ + +/** * Print error message regarding file create directory failure due to a missing or invalid parent directory. * * @param setting -- 1.8.3.1