]> Kevux Git Server - fll/commitdiff
Update: Improve status handling of fl_directory_do().
authorKevin Day <Kevin@kevux.org>
Thu, 12 Jun 2025 02:13:26 +0000 (21:13 -0500)
committerKevin Day <Kevin@kevux.org>
Thu, 12 Jun 2025 02:13:26 +0000 (21:13 -0500)
Add `F_skip` support to allow skipping the next action for some path.

Honor the `F_break`, `F_continue`, `F_done`, and the `F_interrupt` more consistently.
Make sure to consistently clean up the directory stream when these are set.

level_1/fl_directory/c/directory.c
level_1/fl_directory/c/directory.h
level_1/fl_directory/c/private-directory.c

index 42505931d36c4a505c39224ba23e8a0ca8011180..b19ccbc9e20ad4bfd338ea7daf5a116232265193 100644 (file)
@@ -73,9 +73,9 @@ extern "C" {
         recurse->state.status = F_status_set_error(F_parameter);
 
         private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_none_d);
-        if (F_status_is_error(recurse->state.status)) return;
+        if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt) return;
 
-        if (recurse->state.status == F_done) {
+        if (recurse->state.status == F_break || recurse->state.status == F_continue || recurse->state.status == F_done) {
           recurse->state.status = F_okay;
 
           return;
@@ -119,9 +119,9 @@ extern "C" {
 
     if (!path.used || F_status_is_error(recurse->state.status)) {
       private_inline_fl_directory_do_handle(recurse, path, f_directory_recurse_do_flag_path_d);
-      if (F_status_is_error(recurse->state.status)) return;
+      if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt) return;
 
-      if (recurse->state.status == F_done) {
+      if (recurse->state.status == F_break || recurse->state.status == F_continue || recurse->state.status == F_done) {
         recurse->state.status = F_okay;
 
         return;
@@ -136,15 +136,20 @@ extern "C" {
       recurse->flag & f_directory_recurse_do_flag_after_d ? f_directory_recurse_do_flag_after_d : 0,
     };
 
-    uint8_t action = 0;
-
     recurse->depth = 0;
 
-    for (action = 0; action < 3; ++action) {
+    for (uint8_t action = 0; action < 3; ++action) {
 
       if (recurse->state.interrupt) {
         recurse->state.interrupt((void *) &recurse->state, (void *) recurse);
-        if (F_status_set_fine(recurse->state.status) == F_interrupt) break;
+        if (F_status_set_fine(recurse->state.status) == F_interrupt) return;
+      }
+
+      // Support F_skip for skipping the next action.
+      if (recurse->state.status == F_skip) {
+        recurse->state.status = F_okay;
+
+        continue;
       }
 
       if (flag_actions[action]) {
@@ -158,17 +163,17 @@ extern "C" {
 
             --recurse->depth;
 
-            if (F_status_is_error(recurse->state.status)) return;
+            // Reset the path after operating on child directories.
+            recurse->path.used = path.used;
+            recurse->path.string[recurse->path.used] = 0;
+
+            if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt) return;
 
-            if (recurse->state.status == F_done) {
+            if (recurse->state.status == F_break || recurse->state.status == F_continue || recurse->state.status == F_done) {
               recurse->state.status = F_okay;
 
               return;
             }
-
-            // Reset the path after operating on child directories.
-            recurse->path.used = path.used;
-            recurse->path.string[recurse->path.used] = 0;
           }
         }
 
@@ -179,11 +184,10 @@ extern "C" {
 
           if (F_status_is_error(recurse->state.status)) {
             private_inline_fl_directory_do_handle(recurse, path, flag_actions[action] | f_directory_recurse_do_flag_directory_d);
-            if (F_status_is_error(recurse->state.status)) break;
           }
 
-          // There is nothing to continue onto, so all of these result in a break out of the loop.
-          if (recurse->state.status == F_break || recurse->state.status == F_done || recurse->state.status == F_continue || F_status_set_fine(recurse->state.status) == F_interrupt) break;
+          if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt) return;
+          if (recurse->state.status == F_break || recurse->state.status == F_continue || recurse->state.status == F_done) break;
         }
       }
     } // for
index a83ed7a3cd934be86091a83d08f298e100f85ae6..489ffe80369ab5f0aa246bcd9997d686f758f811 100644 (file)
@@ -110,6 +110,12 @@ extern "C" {
  * The action only happens if recurse.flag has f_directory_recurse_do_flag_action_d.
  * The after only happens if recurse.flag has f_directory_recurse_do_flag_after_d.
  *
+ * Setting the recurse.state.status to the following for the designated effects:
+ *   - F_break:    Break out of the current depth; Is the same as F_done at depth 0.
+ *   - F_continue: Continue to the next sibling file at the current depth; Is the same as F_done at depth 0.
+ *   - F_done:     Done all directory operations, immediately return.
+ *   - F_skip:     Skip the next action, resetting the recurse.state.status to F_okay; Is the same as F_okay if on the last action for some path.
+ *
  * The action() and handle() should check if the recurse is NULL (and any other appropraite NULL checks).
  *
  * General behavior flow:
index edf1970d74f07629f1eb15da17926a682a389967..2654057f7ec9888778904a44b7266181ae003313 100644 (file)
@@ -14,160 +14,172 @@ extern "C" {
 
     if (F_status_is_error(recurse->state.status)) {
       private_inline_fl_directory_do_handle(recurse, recurse->path, f_directory_recurse_do_flag_list_d);
-      if (F_status_is_error(recurse->state.status)) return;
+      if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt) return;
 
-      if (recurse->state.status != F_done) {
+      if (recurse->state.status != F_break && recurse->state.status != F_continue && recurse->state.status != F_done) {
         recurse->state.status = F_okay;
       }
     }
 
-    const uint64_t flag_actions[] = {
-      recurse->flag & f_directory_recurse_do_flag_before_d ? f_directory_recurse_do_flag_before_d : 0,
-      f_directory_recurse_do_flag_action_d,
-      recurse->flag & f_directory_recurse_do_flag_after_d ? f_directory_recurse_do_flag_after_d : 0,
-    };
-
     const f_number_unsigned_t used_original = recurse->path.used;
 
-    f_directory_entity_t entity = f_directory_entity_t_initialize;
-    f_string_static_t name = f_string_static_t_initialize;
+    if (recurse->state.status == F_okay) {
+      const uint64_t flag_actions[] = {
+        recurse->flag & f_directory_recurse_do_flag_before_d ? f_directory_recurse_do_flag_before_d : 0,
+        f_directory_recurse_do_flag_action_d,
+        recurse->flag & f_directory_recurse_do_flag_after_d ? f_directory_recurse_do_flag_after_d : 0,
+      };
 
-    uint64_t flag = 0;
-    uint8_t action = 0;
-    f_number_unsigned_t used_directory = 0;
+      f_directory_entity_t entity = f_directory_entity_t_initialize;
+      f_string_static_t name = f_string_static_t_initialize;
 
-    for (;;) {
-      if (recurse->state.interrupt) {
-        recurse->state.interrupt((void *) &recurse->state, (void *) recurse);
-        if (F_status_set_fine(recurse->state.status) == F_interrupt) break;
-      }
+      uint64_t flag = 0;
+      uint8_t action = 0;
+      f_number_unsigned_t used_directory = 0;
 
-      recurse->state.status = f_directory_stream_read(stream, &entity);
-      if (recurse->state.status == F_okay_eos) break;
+      for (;;) {
+        if (recurse->state.interrupt) {
+          recurse->state.interrupt((void *) &recurse->state, (void *) recurse);
+          if (F_status_set_fine(recurse->state.status) == F_interrupt) break;
+        }
 
-      if (F_status_is_error(recurse->state.status)) {
-        private_inline_fl_directory_do_handle(recurse, recurse->path, f_directory_recurse_do_flag_path_list_d);
-        if (F_status_is_error(recurse->state.status)) return;
+        recurse->state.status = f_directory_stream_read(stream, &entity);
+        if (recurse->state.status == F_okay_eos) break;
 
-        if (recurse->state.status != F_done) {
-          recurse->state.status = F_okay;
+        if (F_status_is_error(recurse->state.status)) {
+          private_inline_fl_directory_do_handle(recurse, recurse->path, f_directory_recurse_do_flag_path_list_d);
         }
-      }
 
-      // Never process the '.' and '..' paths.
-      if (!strncmp(f_directory_current_s.string, entity.d_name, f_directory_current_s.used + 1) || !strncmp(f_directory_back_s.string, entity.d_name, f_directory_back_s.used + 1)) continue;
+        if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt) return;
 
-      if (entity.d_type == DT_FIFO) {
-        flag = f_directory_recurse_do_flag_fifo_d;
-      }
-      else if (entity.d_type == DT_CHR) {
-        flag = f_directory_recurse_do_flag_character_d;
-      }
-      else if (entity.d_type == DT_DIR) {
-        flag = f_directory_recurse_do_flag_directory_d;
-      }
-      else if (entity.d_type == DT_BLK) {
-        flag = f_directory_recurse_do_flag_block_d;
-      }
-      else if (entity.d_type == DT_REG) {
-        flag = f_directory_recurse_do_flag_regular_d;
-      }
-      else if (entity.d_type == DT_LNK) {
-        flag = f_directory_recurse_do_flag_link_d;
-      }
-      else if (entity.d_type == DT_SOCK) {
-        flag = f_directory_recurse_do_flag_socket_d;
-      }
+        if (recurse->state.status == F_break || recurse->state.status == F_continue || recurse->state.status == F_done) {
+          if (recurse->state.status == F_continue) continue;
 
-      // The DT_WHT may not be defined everywhere.
-      #ifdef DT_WHT
-        else if (entity.d_type == DT_WHT) {
-          flag = f_directory_recurse_do_flag_white_out_d;
+          break;
         }
-      #endif // DT_WHT
 
-      else {
-        flag = f_directory_recurse_do_flag_unknown_d;
-      }
+        recurse->state.status = F_okay;
 
-      recurse->path.used = used_original;
+        // Never process the '.' and '..' paths.
+        if (!strncmp(f_directory_current_s.string, entity.d_name, f_directory_current_s.used + 1) || !strncmp(f_directory_back_s.string, entity.d_name, f_directory_back_s.used + 1)) continue;
 
-      name.string = entity.d_name;
-      name.used = strnlen(entity.d_name, F_directory_max_string_d);
+        if (entity.d_type == DT_FIFO) {
+          flag = f_directory_recurse_do_flag_fifo_d;
+        }
+        else if (entity.d_type == DT_CHR) {
+          flag = f_directory_recurse_do_flag_character_d;
+        }
+        else if (entity.d_type == DT_DIR) {
+          flag = f_directory_recurse_do_flag_directory_d;
+        }
+        else if (entity.d_type == DT_BLK) {
+          flag = f_directory_recurse_do_flag_block_d;
+        }
+        else if (entity.d_type == DT_REG) {
+          flag = f_directory_recurse_do_flag_regular_d;
+        }
+        else if (entity.d_type == DT_LNK) {
+          flag = f_directory_recurse_do_flag_link_d;
+        }
+        else if (entity.d_type == DT_SOCK) {
+          flag = f_directory_recurse_do_flag_socket_d;
+        }
 
-      recurse->state.status = f_memory_array_increase_by(f_path_separator_s.used + name.used + 1, sizeof(f_char_t), (void **) &recurse->path.string, &recurse->path.used, &recurse->path.size);
+        // The DT_WHT may not be defined everywhere.
+        #ifdef DT_WHT
+          else if (entity.d_type == DT_WHT) {
+            flag = f_directory_recurse_do_flag_white_out_d;
+          }
+        #endif // DT_WHT
 
-      if (F_status_is_error_not(recurse->state.status)) {
-        recurse->state.status = f_string_dynamic_append_assure(f_path_separator_s, &recurse->path);
-      }
+        else {
+          flag = f_directory_recurse_do_flag_unknown_d;
+        }
 
-      if (F_status_is_error_not(recurse->state.status)) {
-        recurse->state.status = f_string_dynamic_append_nulless(name, &recurse->path);
-      }
+        recurse->path.used = used_original;
 
-      // Guarantee NULL termination.
-      recurse->path.string[recurse->path.used] = 0;
+        name.string = entity.d_name;
+        name.used = strnlen(entity.d_name, F_directory_max_string_d);
 
-      if (F_status_is_error(recurse->state.status)) {
-        private_inline_fl_directory_do_handle(recurse, name, f_directory_recurse_do_flag_path_d);
+        recurse->state.status = f_memory_array_increase_by(f_path_separator_s.used + name.used + 1, sizeof(f_char_t), (void **) &recurse->path.string, &recurse->path.used, &recurse->path.size);
+
+        if (F_status_is_error_not(recurse->state.status)) {
+          recurse->state.status = f_string_dynamic_append_assure(f_path_separator_s, &recurse->path);
+        }
+
+        if (F_status_is_error_not(recurse->state.status)) {
+          recurse->state.status = f_string_dynamic_append_nulless(name, &recurse->path);
+        }
+
+        // Guarantee NULL termination.
+        recurse->path.string[recurse->path.used] = 0;
 
-        if (F_status_is_error(recurse->state.status)) break;
+        if (F_status_is_error(recurse->state.status)) {
+          private_inline_fl_directory_do_handle(recurse, name, f_directory_recurse_do_flag_path_d);
+        }
+
+        if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt) break;
         if (recurse->state.status == F_break || recurse->state.status == F_done) break;
         if (recurse->state.status == F_continue) continue;
-      }
 
-      for (action = 0; action < 3; ++action) {
+        for (action = 0; action < 3; ++action) {
 
-        if (recurse->state.interrupt) {
-          recurse->state.interrupt((void *) &recurse->state, (void *) recurse);
-          if (F_status_set_fine(recurse->state.status) == F_interrupt) break;
-        }
+          if (recurse->state.interrupt) {
+            recurse->state.interrupt((void *) &recurse->state, (void *) recurse);
+            if (F_status_set_fine(recurse->state.status) == F_interrupt) break;
+          }
 
-        if (flag_actions[action]) {
-          if ((flag & f_directory_recurse_do_flag_directory_d) && (flag_actions[action] & f_directory_recurse_do_flag_action_d)) {
+          // Support F_skip for skipping the next action.
+          if (recurse->state.status == F_skip) {
             recurse->state.status = F_okay;
-            used_directory = recurse->path.used;
 
-            if (recurse->depth < recurse->depth_max) {
-              ++recurse->depth;
+            continue;
+          }
 
-              private_fl_directory_do_recurse(recurse);
+          if (flag_actions[action]) {
+            if ((flag & f_directory_recurse_do_flag_directory_d) && (flag_actions[action] & f_directory_recurse_do_flag_action_d)) {
+              recurse->state.status = F_okay;
+              used_directory = recurse->path.used;
 
-              --recurse->depth;
-            }
+              if (recurse->depth < recurse->depth_max) {
+                ++recurse->depth;
 
-            if (F_status_is_error(recurse->state.status)) {
-              private_inline_fl_directory_do_handle(recurse, name, flag_actions[action] | flag);
-              if (F_status_is_error(recurse->state.status)) break;
-            }
+                private_fl_directory_do_recurse(recurse);
 
-            // Reset the path after operating on child directories.
-            recurse->path.used = used_directory;
-            recurse->path.string[recurse->path.used] = 0;
-
-            // This loop is not considered a loop for breaking and continuing.
-            if (recurse->state.status == F_break || recurse->state.status == F_done || recurse->state.status == F_continue || F_status_set_fine(recurse->state.status) == F_interrupt) break;
-          }
+                --recurse->depth;
+              }
 
-          if (flag_actions[action] != f_directory_recurse_do_flag_action_d || recurse->flag & f_directory_recurse_do_flag_action_d) {
-            recurse->state.status = F_okay;
+              if (F_status_is_error(recurse->state.status)) {
+                private_inline_fl_directory_do_handle(recurse, name, flag_actions[action] | flag);
+              }
 
-            recurse->action(recurse, name, flag_actions[action] | flag);
+              // Reset the path after operating on child directories.
+              recurse->path.used = used_directory;
+              recurse->path.string[recurse->path.used] = 0;
 
-            if (F_status_is_error(recurse->state.status)) {
-              private_inline_fl_directory_do_handle(recurse, name, flag_actions[action] | flag);
-              if (F_status_is_error(recurse->state.status)) break;
+              if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt) break;
+              if (recurse->state.status == F_break || recurse->state.status == F_done || recurse->state.status == F_continue) break;
             }
 
-            // This loop is not considered a loop for breaking and continuing.
-            if (recurse->state.status == F_break || recurse->state.status == F_done || recurse->state.status == F_continue || F_status_set_fine(recurse->state.status) == F_interrupt) break;
+            if (flag_actions[action] != f_directory_recurse_do_flag_action_d || recurse->flag & f_directory_recurse_do_flag_action_d) {
+              recurse->state.status = F_okay;
+
+              recurse->action(recurse, name, flag_actions[action] | flag);
+
+              if (F_status_is_error(recurse->state.status)) {
+                private_inline_fl_directory_do_handle(recurse, name, flag_actions[action] | flag);
+              }
+
+              if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt) break;
+              if (recurse->state.status == F_break || recurse->state.status == F_done || recurse->state.status == F_continue) break;
+            }
           }
-        }
-      } // for
+        } // for
 
-      if (F_status_is_error(recurse->state.status) || recurse->state.status == F_break || recurse->state.status == F_done) break;
-      if (recurse->state.status == F_continue) continue;
-    } // for
+        if (F_status_is_error(recurse->state.status) || F_status_set_fine(recurse->state.status) == F_interrupt || recurse->state.status == F_break || recurse->state.status == F_done) break;
+        if (recurse->state.status == F_continue) continue;
+      } // for
+    }
 
     {
       const f_status_t status_original = recurse->state.status;
@@ -176,16 +188,18 @@ extern "C" {
 
       if (F_status_is_error(recurse->state.status)) {
         private_inline_fl_directory_do_handle(recurse, recurse->path, f_directory_recurse_do_flag_clean_list_d);
-        if (F_status_is_error(recurse->state.status)) return;
+      }
+
+      if (F_status_is_error(status_original) || F_status_set_fine(status_original) == F_interrupt || status_original == F_break || status_original == F_continue || status_original == F_done) {
+        recurse->state.status = status_original;
+      }
+      else if (F_status_is_error_not(recurse->state.status)) {
+        recurse->state.status = status_original;
 
         if (recurse->state.status != F_done) {
           recurse->state.status = F_okay;
         }
       }
-
-      if (F_status_is_error(status_original) || F_status_is_error_not(recurse->state.status)) {
-        recurse->state.status = status_original;
-      }
     }
 
     recurse->path.used = used_original;