]> Kevux Git Server - fll/commitdiff
Progress: Focus on directory recursion related changes and Featureless Make.
authorKevin Day <kevin@kevux.org>
Sun, 9 Apr 2023 23:21:10 +0000 (18:21 -0500)
committerKevin Day <kevin@kevux.org>
Sun, 9 Apr 2023 23:21:10 +0000 (18:21 -0500)
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.

21 files changed:
build/level_0/settings
build/monolithic/settings
level_0/f_directory/c/directory/common.h
level_0/f_directory/c/directory/type.c
level_0/f_directory/c/directory/type.h
level_1/fl_directory/c/directory.c
level_1/fl_directory/c/directory.h
level_1/fl_directory/c/private-directory.c
level_1/fl_directory/c/private-directory.h
level_3/fake/c/main/build.c
level_3/fake/c/main/build.h
level_3/fake/c/main/build/print/message.c
level_3/fake/c/main/build/print/message.h
level_3/fake/c/main/build/print/verbose.c
level_3/fake/c/main/build/print/verbose.h
level_3/fake/c/main/common/print.c
level_3/fake/c/main/common/print.h
level_3/fake/c/main/common/type.c
level_3/fake/c/main/common/type.h
level_3/fake/c/main/print/error.c
level_3/fake/c/main/print/error.h

index d7e88d8ac66563809a73caea45c27f68daa48540..65a6e2a8034be0eb15d2314162984d1da0bdda60 100644 (file)
@@ -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
 
index c735cbdc603a823ca8fc6bceb13370f4839eadc1..3ad08b3d83fd0aca6780ace63a58665e14b54019 100644 (file)
@@ -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
index a7062b97f76653031af2439d896ebac30f100216..85a4251782e7f5761298f8601eece241cf3a2fd4 100644 (file)
@@ -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.
index bd7c6b613f1bccc7d32c5e7a2a8d0e63780a2815..ad1fc922a57d850d1491c8f6333ff37d22f8f749 100644 (file)
@@ -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_
index 1a18786efef2cd67c01cfcc02c4aa4a6538b2d48..01e505ccc48f0cce77faee71a07c845e7d3929f6 100644 (file)
@@ -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);
index ce2e47ceac6933f78946969d59dcd1658acee4ed..dd51dbb36511b4e5db55081b52fdb891210f1e8b 100644 (file)
@@ -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_
 
index 24cb42ce830feca36ec9f6f55580812a172e7a0b..df6f74dcf26d44743dfea9e57f76c7c579fb1a1a 100644 (file)
@@ -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);
index b5ee156270cef0af6a3d50d225d4424a64a10aed..30e901e922994a0d0016e9585fdcbdb829e610ac 100644 (file)
@@ -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
     }
 
index facc94510f9caedd96ddae18c6f157c24c306fba..c1516422e01ed4b164ec1ff1820a16655f5bcf1f 100644 (file)
@@ -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
index 8c3fee6fa4d2472896b4c3cab514af8423f1db5f..22612a82c6234d05af7a7cb39b6b302bfc190939 100644 (file)
@@ -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) {
 
index b579f88ea33541e7375bb2b64e88f11ad2fd03d0..b457cfae0c513a54050c90c79d40d86239d5dda3 100644 (file)
@@ -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
index b18885ff3e28ff0f03e06d91732078351a214cd3..3f7b0a0a20269fb188eae4eac7d28d319f149f63 100644 (file)
@@ -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) {
 
index 63f0ffd9d6683afd9997f4f1b6baa0c2737b156d..8312d6206f0fa091bd1199abeeb806b9082cc548 100644 (file)
@@ -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
index 9a846133a03c41df0b215274ec941812983bb024..ae8bf1cbc3c56bdec8e7296643a118bee7941046 100644 (file)
@@ -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) {
index 87cf9e28d9761a5c6a5cfc3696c8a271e92721ad..97100d74683aebafc67e198bb0a901f5fab6fc32 100644 (file)
@@ -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.
index 28ba08ca368055f90404993a8b2d32fe512dc0da..5838024ecf5a671186f10d4d49a5bd10a71a189d 100644 (file)
@@ -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",
index 7db7373b1ecab40fd0500f2d4bde278e3b02017f..4ed4cc3d64ea37f14a522c4b842ee287df14c27d 100644 (file)
@@ -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,
index 1a92d91673fca7666d3f40b9a20dd1ba94006f97..3f2aa0d104a999fb81157e1a309fac23a2785dfa 100644 (file)
@@ -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_
index ce65a34453bd20343beb898f0a4b2f2a4e9625a7..cdf05a19201edbb45c22d12c8477e5c71255ecc3 100644 (file)
@@ -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_
index 83b1a64e913a9834f74ed08f19a320ea3cc3aaa5..310f29990a8338b20faebf537c3bbf8bd81538cc 100644 (file)
@@ -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) {
 
index 7d9dbe4b73d79f47f3df40d564fcd3f24a841c88..957d455a3412622951113aaa92b5c111452696b0 100644 (file)
@@ -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