Progress: Continue working on completing the remove program.
authorKevin Day <Kevin@kevux.org>
Wed, 19 Feb 2025 03:03:07 +0000 (21:03 -0600)
committerKevin Day <Kevin@kevux.org>
Wed, 19 Feb 2025 03:06:00 +0000 (21:06 -0600)
Update the remove documentation.

Add support for the remember parameter.

Stub out the memory cache processing for when the remember parameter is set to yes (enabled).

15 files changed:
documents/readme.remove.txt
sources/c/program/kevux/tools/remove/main/common.c
sources/c/program/kevux/tools/remove/main/common/define.h
sources/c/program/kevux/tools/remove/main/common/enumeration.h
sources/c/program/kevux/tools/remove/main/common/string.c
sources/c/program/kevux/tools/remove/main/common/string.h
sources/c/program/kevux/tools/remove/main/common/type.c
sources/c/program/kevux/tools/remove/main/common/type.h
sources/c/program/kevux/tools/remove/main/convert.h
sources/c/program/kevux/tools/remove/main/operate.c
sources/c/program/kevux/tools/remove/main/operate.h
sources/c/program/kevux/tools/remove/main/preprocess.c
sources/c/program/kevux/tools/remove/main/print/error.c
sources/c/program/kevux/tools/remove/main/print/error.h
sources/c/program/kevux/tools/remove/main/print/message.c

index 82e72a611266ac7d7867a1fe57c4a889431bf8c0..fde68a5e98e1580619fdcbdedfd327e46374663c 100644 (file)
 Remove Readme Documentation:
   The bold:"remove" is a program for removing files and directories.
 
-  This program is similar to code:"rm", code:"rmdir", and code:"unlink".
-  Compatibility helpers are provided for code:"rm", code:"rmdir", and code:"unlink" programs to closely match functionality.
-  Not everything may be supported but these compatibility helpers should help ease the transition.
+  This program is similar to the common programs code:"rm", code:"rmdir", and code:"unlink".
+  Compatibility helper programs are provided to closely match functionality of their respectively named common program.
+  Not every functionality of those programs may be supported by these compatibility helpers but they should closely resembly most of the common functionality.
 
   The default behavior is to remove all non-directory files and to fail when a directory is attempted to be removed.
   When any of the file type parameters are specified, then the default behavior is completely overwritten.
   Once a single file type parameter is specified, then the removals happen for all specified file type parameters combined.
+  This default behavior is not used by the compatibility helper programs which define their own defaults and parameters.
 
   The bold:"remove" program has the following arguments\:
 
-  The code:"--block" (code:"-b") parameter is a file type parameter that restricts removal to block device files.
-  The code:"--character" (code:"-c") parameter is a file type parameter that restricts removal to character device files.
-  The code:"--date" (code:"-D") parameter accepts three additional parameters and restricts removal based on the relationship to some date.
-  The code:"--different" (code:"-O") parameter restricts removal of files whose owner is not the user of the caller of the program.
-  The code:"--directory" (code:"-d") parameter is a file type parameter that restricts removal to directory files.
-  The code:"--empty" (code:"-e") parameter to remove empty directories.
-  The code:"--empty_fail" (code:"-y") parameter to fail on empty directories.
-  The code:"--empty_fail_not" (code:"-Y") parameter to fail on not empty directories.
-  The code:"--empty_not" (code:"-E") parameter to fail on not-empty directories.
-  The code:"--follow" (code:"-F") parameter alters removal to remove the files pointed to by a symbolic link rather than the link itself.
-  The code:"--force" (code:"-f") parameter to never prompt and ignore non-existent files and arguments.
-  The code:"--group" (code:"-g") parameter accepts two additional parameters that restrict removal to the given group identifier.
-  The code:"--link" (code:"-l") parameter is a file type parameter that restricts removal to a symbolic link file.
-  The code:"--mode" (code:"-m") parameter accepts two additional parameters that restrict removal to the given file mode.
-  The code:"--prompt" (code:"-p") parameter accepts one additional parameter that designates operating in interactive mode and prompts the user for input.
-  The code:"--recurse" (code:"-g") parameter remove directories and their contents recursively.
-  The code:"--regular" (code:"-R") parameter is a file type parameter that restricts removal to regular files (commonly referred to as just bold:"file").
-  The code:"--same" (code:"-s") parameter restricts removal of files whose owner is the user of the caller of the program.
-  The code:"--simulate" (code:"-S") parameter designates that the program operates in simulation mode, never removing anything and instead printing what would have been mode (unless in quiet mode).
-  The code:"--socket" (code:"-k") parameter is a file type parameter that restricts removal to socket files.
-  The code:"--tree" (code:"-t") parameter designates that the specified directory tree is also deleted (may require --force and --recurse if directory tree is not empty).
-  The code:"--user" (code:"-u") parameter accepts two additional parameters that restrict removal to the given group identifier.
+    The code:"--block" (code:"-b") parameter is a file type parameter that restricts removal to block device files.
+    The code:"--character" (code:"-c") parameter is a file type parameter that restricts removal to character device files.
+    The code:"--date" (code:"-D") parameter accepts three additional parameters and restricts removal based on the relationship to some date.
+    The code:"--different" (code:"-O") parameter restricts removal of files whose owner is not the user of the caller of the program.
+    The code:"--directory" (code:"-d") parameter is a file type parameter that restricts removal to directory files.
+    The code:"--empty" (code:"-e") parameter to remove empty directories.
+    The code:"--empty_fail" (code:"-y") parameter to fail on empty directories.
+    The code:"--empty_fail_not" (code:"-Y") parameter to fail on not empty directories.
+    The code:"--empty_not" (code:"-E") parameter to fail on not-empty directories.
+    The code:"--follow" (code:"-F") parameter alters removal to remove the files pointed to by a symbolic link rather than the link itself.
+    The code:"--force" (code:"-f") parameter to never prompt and ignore non-existent files and arguments.
+    The code:"--group" (code:"-g") parameter accepts two additional parameters that restrict removal to the given group identifier.
+    The code:"--link" (code:"-l") parameter is a file type parameter that restricts removal to a symbolic link file.
+    The code:"--mode" (code:"-m") parameter accepts two additional parameters that restrict removal to the given file mode.
+    The code:"--prompt" (code:"-p") parameter accepts one additional parameter that designates operating in interactive mode and prompts the user for input.
+    The code:"--recurse" (code:"-g") parameter remove directories and their contents recursively.
+    The code:"--regular" (code:"-R") parameter is a file type parameter that restricts removal to regular files (commonly referred to as just bold:"file").
+    The code:"--remember" parameter to remember paths of files already deleted so as to not potentially error out on already removed path.
+    The code:"--same" (code:"-s") parameter restricts removal of files whose owner is the user of the caller of the program.
+    The code:"--simulate" (code:"-S") parameter designates that the program operates in simulation mode, never removing anything and instead printing what would have been mode (unless in quiet mode).
+    The code:"--socket" (code:"-k") parameter is a file type parameter that restricts removal to socket files.
+    The code:"--tree" (code:"-t") parameter designates that the specified directory tree is also deleted (may require --force and --recurse if directory tree is not empty).
+    The code:"--user" (code:"-u") parameter accepts two additional parameters that restrict removal to the given group identifier.
 
   The code:"--date" (code:"-d") parameter's arguments three are (and in this order)\:
+
     1) Either bold:"create" or bold:"modify" to represent file created date or file modified date.
     2) One of bold:"<", bold:"<=", bold:"==", bold:">=", and bold:">" to represent the relationship between the date in argument 3.
     3) The date (can be in Time format, such as code:"2020:86.4 TT" and code:"2020:86400000000000" (copy the documentation from Featureless Make and/or Controller to describe this)).
index a6791d50f3a52ca90c9e22d6c3ccf4896a6e6bcb..c9b40b0f312945c92c851ac464b236aa4f885f7a 100644 (file)
@@ -470,6 +470,43 @@ extern "C" {
       }
     }
 
+    if (main->program.parameters.array[kt_remove_parameter_remember_e].result & f_console_result_found_e) {
+      if (main->program.parameters.array[kt_remove_parameter_remember_e].result & f_console_result_value_e) {
+        total_arguments = main->program.parameters.array[kt_remove_parameter_remember_e].values.used;
+
+        if (main->program.parameters.array[kt_remove_parameter_remember_e].locations.used != total_arguments) {
+          main->setting.state.status = F_status_set_error(F_parameter);
+
+          kt_remove_print_error_parameter_missing_value_requires_yesno(&main->program.error, f_console_symbol_long_normal_s, kt_remove_long_remember_s);
+
+          return;
+        }
+
+        index = main->program.parameters.array[kt_remove_parameter_remember_e].values.array[total_arguments - 1];
+
+        if (f_compare_dynamic(kt_remove_yes_s, main->program.parameters.arguments.array[index]) == F_equal_to) {
+          main->setting.flag |= kt_remove_main_flag_remember_d;
+        }
+        else if (f_compare_dynamic(kt_remove_no_s, main->program.parameters.arguments.array[index]) == F_equal_to) {
+          main->setting.flag &= ~kt_remove_main_flag_remember_d;
+        }
+        else {
+          main->setting.state.status = F_status_set_error(F_parameter);
+
+          kt_remove_print_error_parameter_unknown_value(&main->program.error, f_console_symbol_long_normal_s, kt_remove_long_remember_s, main->program.parameters.arguments.array[index]);
+
+          return;
+        }
+      }
+      else {
+        main->setting.state.status = F_status_set_error(F_parameter);
+
+        kt_remove_print_error_parameter_missing_value_requires_yesno(&main->program.error, f_console_symbol_long_normal_s, kt_remove_long_remember_s);
+
+        return;
+      }
+    }
+
     if (main->program.parameters.array[kt_remove_parameter_utc_e].result & f_console_result_found_e) {
       main->setting.flag |= kt_remove_main_flag_utc_d;
 
@@ -497,7 +534,6 @@ extern "C" {
         return;
       }
 
-      // @todo this needs to detect duplicate paths and also make not of shared paths on recursive removal to avoid trying to double+ remove.
       for (i = 0; i < main->program.parameters.remaining.used; ++i, ++main->setting.files.used) {
 
         index = main->program.parameters.remaining.array[i];
index 538b57710870085c4d4bb2425f277e4d89f005c3..2e02941c3a73023414c980bcb61eef3a816e3acd 100644 (file)
@@ -150,6 +150,7 @@ extern "C" {
  *   - follow:          Follow the symbolic link.
  *   - link:            The file being operated on is a link or is a followed link.
  *   - parent:          This is a parent of a file for some other file operation process.
+ *   - processed:       This path is already processed.
  *   - recurse:         Perform recursively (only on directories).
  *   - remove:          Perform remove.
  *   - remove_fail:     Cannot perform remove due to failure.
@@ -164,11 +165,12 @@ extern "C" {
   #define kt_remove_flag_file_operate_follow_d          0x8
   #define kt_remove_flag_file_operate_link_d            0x10
   #define kt_remove_flag_file_operate_parent_d          0x20
-  #define kt_remove_flag_file_operate_recurse_d         0x40
-  #define kt_remove_flag_file_operate_remove_d          0x80
-  #define kt_remove_flag_file_operate_remove_fail_d     0x100
-  #define kt_remove_flag_file_operate_remove_not_d      0x200
-  #define kt_remove_flag_file_operate_remove_not_fail_d 0x400
+  #define kt_remove_flag_file_operate_processed_d       0x40
+  #define kt_remove_flag_file_operate_recurse_d         0x80
+  #define kt_remove_flag_file_operate_remove_d          0x100
+  #define kt_remove_flag_file_operate_remove_fail_d     0x200
+  #define kt_remove_flag_file_operate_remove_not_d      0x400
+  #define kt_remove_flag_file_operate_remove_not_fail_d 0x800
 #endif // _di_kt_remove_flag_file_operate_d_
 
 /**
@@ -231,6 +233,7 @@ extern "C" {
  *   - prompt_once:            Operate in interactive mode: prompting if removing 3 or more files.
  *   - recurse:                Recurse directories.
  *   - regular:                Remove by file type: regular.
+ *   - remember:               Enable remembering paths already processed.
  *   - same:                   Remove by same user as caller.
  *   - simulate:               Do not actually perform deletes, instead print messages (when silent, should still return 0 or 1).
  *   - socket:                 Remove by file type: socket.
@@ -270,15 +273,16 @@ extern "C" {
   #define kt_remove_main_flag_prompt_once_d            0x400000
   #define kt_remove_main_flag_recurse_d                0x800000
   #define kt_remove_main_flag_regular_d                0x1000000
-  #define kt_remove_main_flag_same_d                   0x2000000
-  #define kt_remove_main_flag_simulate_d               0x4000000
-  #define kt_remove_main_flag_socket_d                 0x8000000
-  #define kt_remove_main_flag_tree_d                   0x10000000
-  #define kt_remove_main_flag_updated_d                0x20000000
-  #define kt_remove_main_flag_user_d                   0x40000000
-  #define kt_remove_main_flag_utc_d                    0x80000000
-  #define kt_remove_main_flag_version_d                0x100000000
-  #define kt_remove_main_flag_version_copyright_help_d 0x100008008
+  #define kt_remove_main_flag_remember_d               0x2000000
+  #define kt_remove_main_flag_same_d                   0x4000000
+  #define kt_remove_main_flag_simulate_d               0x8000000
+  #define kt_remove_main_flag_socket_d                 0x10000000
+  #define kt_remove_main_flag_tree_d                   0x20000000
+  #define kt_remove_main_flag_updated_d                0x40000000
+  #define kt_remove_main_flag_user_d                   0x80000000
+  #define kt_remove_main_flag_utc_d                    0x100000000
+  #define kt_remove_main_flag_version_d                0x200000000
+  #define kt_remove_main_flag_version_copyright_help_d 0x200008008
 #endif // _di_kt_remove_main_flag_e_
 
 /**
index 54d630a3f411fdfb33b1eef203017737219257b6..6b75896aed36a33bf5796f019dc4d4144a534d11 100644 (file)
@@ -50,6 +50,7 @@ extern "C" {
     kt_remove_parameter_prompt_e,
     kt_remove_parameter_recurse_e,
     kt_remove_parameter_regular_e,
+    kt_remove_parameter_remember_e,
     kt_remove_parameter_same_e,
     kt_remove_parameter_simulate_e,
     kt_remove_parameter_socket_e,
@@ -81,6 +82,7 @@ extern "C" {
       macro_f_console_parameter_t_initialize_3(kt_remove_short_prompt_s,    kt_remove_long_prompt_s,    1, f_console_flag_normal_e), \
       macro_f_console_parameter_t_initialize_3(kt_remove_short_recurse_s,   kt_remove_long_recurse_s,   0, f_console_flag_normal_e), \
       macro_f_console_parameter_t_initialize_3(kt_remove_short_regular_s,   kt_remove_long_regular_s,   0, f_console_flag_normal_e), \
+      macro_f_console_parameter_t_initialize_5(                             kt_remove_long_remember_s,  1, f_console_flag_normal_e), \
       macro_f_console_parameter_t_initialize_3(kt_remove_short_same_s,      kt_remove_long_same_s,      0, f_console_flag_normal_e), \
       macro_f_console_parameter_t_initialize_3(kt_remove_short_simulate_s,  kt_remove_long_simulate_s,  0, f_console_flag_normal_e), \
       macro_f_console_parameter_t_initialize_3(kt_remove_short_socket_s,    kt_remove_long_socket_s,    0, f_console_flag_normal_e), \
@@ -91,7 +93,7 @@ extern "C" {
       macro_f_console_parameter_t_initialize_5(                             kt_remove_long_utc_s,       0, f_console_flag_normal_e), \
     }
 
-  #define kt_remove_total_parameters_d (f_console_parameter_state_type_total_d + 25)
+  #define kt_remove_total_parameters_d (f_console_parameter_state_type_total_d + 26)
 #endif // _di_kt_remove_parameter_e_
 
 #ifdef __cplusplus
index c369be810130bcbfd6d09c6ba9c55d4e5ec0ef06..7d23da09698cfada5eefb7aabc680f3791efba3f 100644 (file)
@@ -30,6 +30,7 @@ extern "C" {
   const f_string_static_t kt_remove_recurse_s = macro_f_string_static_t_initialize_1(KT_REMOVE_recurse_s, 0, KT_REMOVE_recurse_s_length);
   const f_string_static_t kt_remove_remove_s = macro_f_string_static_t_initialize_1(KT_REMOVE_remove_s, 0, KT_REMOVE_remove_s_length);
   const f_string_static_t kt_remove_root_s = macro_f_string_static_t_initialize_1(KT_REMOVE_root_s, 0, KT_REMOVE_root_s_length);
+  const f_string_static_t kt_remove_skip_s = macro_f_string_static_t_initialize_1(KT_REMOVE_skip_s, 0, KT_REMOVE_skip_s_length);
   const f_string_static_t kt_remove_today_s = macro_f_string_static_t_initialize_1(KT_REMOVE_today_s, 0, KT_REMOVE_today_s_length);
   const f_string_static_t kt_remove_tomorrow_s = macro_f_string_static_t_initialize_1(KT_REMOVE_tomorrow_s, 0, KT_REMOVE_tomorrow_s_length);
   const f_string_static_t kt_remove_tree_s = macro_f_string_static_t_initialize_1(KT_REMOVE_tree_s, 0, KT_REMOVE_tree_s_length);
@@ -139,6 +140,7 @@ extern "C" {
   const f_string_static_t kt_remove_long_prompt_s = macro_f_string_static_t_initialize_1(KT_REMOVE_long_prompt_s, 0, KT_REMOVE_long_prompt_s_length);
   const f_string_static_t kt_remove_long_recurse_s = macro_f_string_static_t_initialize_1(KT_REMOVE_long_recurse_s, 0, KT_REMOVE_long_recurse_s_length);
   const f_string_static_t kt_remove_long_regular_s = macro_f_string_static_t_initialize_1(KT_REMOVE_long_regular_s, 0, KT_REMOVE_long_regular_s_length);
+  const f_string_static_t kt_remove_long_remember_s = macro_f_string_static_t_initialize_1(KT_REMOVE_long_remember_s, 0, KT_REMOVE_long_remember_s_length);
   const f_string_static_t kt_remove_long_same_s = macro_f_string_static_t_initialize_1(KT_REMOVE_long_same_s, 0, KT_REMOVE_long_same_s_length);
   const f_string_static_t kt_remove_long_simulate_s = macro_f_string_static_t_initialize_1(KT_REMOVE_long_simulate_s, 0, KT_REMOVE_long_simulate_s_length);
   const f_string_static_t kt_remove_long_socket_s = macro_f_string_static_t_initialize_1(KT_REMOVE_long_socket_s, 0, KT_REMOVE_long_socket_s_length);
index a7e068cfa35b6aa7c135f2b7ddc37e2036c92b07..45ee648dd4544c3b3ac4425d271c380397bf55b2 100644 (file)
@@ -86,6 +86,7 @@ extern "C" {
   #define KT_REMOVE_recurse_s   "recurse"
   #define KT_REMOVE_remove_s    "remove"
   #define KT_REMOVE_root_s      "root"
+  #define KT_REMOVE_skip_s      "skip"
   #define KT_REMOVE_today_s     "today"
   #define KT_REMOVE_tomorrow_s  "tomorrow"
   #define KT_REMOVE_tree_s      "tree"
@@ -109,6 +110,7 @@ extern "C" {
   #define KT_REMOVE_recurse_s_length   7
   #define KT_REMOVE_remove_s_length    6
   #define KT_REMOVE_root_s_length      4
+  #define KT_REMOVE_skip_s_length      4
   #define KT_REMOVE_today_s_length     5
   #define KT_REMOVE_tomorrow_s_length  8
   #define KT_REMOVE_tree_s_length      4
@@ -132,6 +134,7 @@ extern "C" {
   extern const f_string_static_t kt_remove_recurse_s;
   extern const f_string_static_t kt_remove_remove_s;
   extern const f_string_static_t kt_remove_root_s;
+  extern const f_string_static_t kt_remove_skip_s;
   extern const f_string_static_t kt_remove_today_s;
   extern const f_string_static_t kt_remove_tomorrow_s;
   extern const f_string_static_t kt_remove_tree_s;
@@ -407,6 +410,7 @@ extern "C" {
   #define KT_REMOVE_long_prompt_s    "prompt"
   #define KT_REMOVE_long_recurse_s   "recurse"
   #define KT_REMOVE_long_regular_s   "regular"
+  #define KT_REMOVE_long_remember_s  "remember"
   #define KT_REMOVE_long_same_s      "same"
   #define KT_REMOVE_long_simulate_s  "simulate"
   #define KT_REMOVE_long_socket_s    "socket"
@@ -432,6 +436,7 @@ extern "C" {
   #define KT_REMOVE_short_prompt_s_length    1
   #define KT_REMOVE_short_recurse_s_length   1
   #define KT_REMOVE_short_regular_s_length   1
+  #define KT_REMOVE_short_remember_s_length  1
   #define KT_REMOVE_short_same_s_length      1
   #define KT_REMOVE_short_simulate_s_length  1
   #define KT_REMOVE_short_socket_s_length    1
@@ -457,6 +462,7 @@ extern "C" {
   #define KT_REMOVE_long_prompt_s_length    6
   #define KT_REMOVE_long_recurse_s_length   7
   #define KT_REMOVE_long_regular_s_length   7
+  #define KT_REMOVE_long_remember_s_length  8
   #define KT_REMOVE_long_same_s_length      4
   #define KT_REMOVE_long_simulate_s_length  8
   #define KT_REMOVE_long_socket_s_length    6
@@ -507,6 +513,7 @@ extern "C" {
   extern const f_string_static_t kt_remove_long_prompt_s;
   extern const f_string_static_t kt_remove_long_recurse_s;
   extern const f_string_static_t kt_remove_long_regular_s;
+  extern const f_string_static_t kt_remove_long_remember_s;
   extern const f_string_static_t kt_remove_long_same_s;
   extern const f_string_static_t kt_remove_long_simulate_s;
   extern const f_string_static_t kt_remove_long_socket_s;
index 050040b051760cbdc59656ee82e869f720c8c524..4452849cbd723b5af315adb92dd6b8e0e267e8c0 100644 (file)
@@ -13,6 +13,7 @@ extern "C" {
     f_memory_array_resize(0, sizeof(f_char_t), (void **) &cache->buffer.string, &cache->buffer.used, &cache->buffer.size);
 
     f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &cache->files.array, &cache->files.used, &cache->files.size, &f_string_dynamics_delete_callback);
+    f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &cache->memory.array, &cache->memory.used, &cache->memory.size, &f_string_dynamics_delete_callback);
     f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &cache->tree.array, &cache->tree.used, &cache->tree.size, &f_string_dynamics_delete_callback);
   }
 #endif // _di_kt_remove_cache_delete_
index 82cc2a098656427e26084f51125a54cb6447540d..5096df6548b256fbd7e32ea371f1431bb9b43982 100644 (file)
@@ -142,12 +142,14 @@ extern "C" {
  *
  * buffer: The generic buffer.
  * files:  A collection of files, often used during path recursion like those associated with the tree parameter.
+ * memory: A list of paths or partial paths representing files already processed.
  * tree:   A collection of files to process as a result of the --tree command.
  */
 #ifndef _di_kt_remove_cache_t_
   typedef struct {
     f_string_dynamic_t buffer;
     f_string_dynamics_t files;
+    f_string_dynamics_t memory;
     f_string_dynamics_t tree;
   } kt_remove_cache_t;
 
@@ -156,6 +158,7 @@ extern "C" {
       f_string_dynamic_t_initialize, \
       f_string_dynamics_t_initialize, \
       f_string_dynamics_t_initialize, \
+      f_string_dynamics_t_initialize, \
     }
 #endif // _di_kt_remove_cache_t_
 
index 1e41ea7a0c1eaab052ffeffec320c15a683cd5e0..2775b83830cfea65e1a525bdc1798c356ea39bcf 100644 (file)
@@ -38,19 +38,15 @@ extern "C" {
  *     F_okay on success.
  *     F_data_not on success, but buffer is empty and there is no data to process.
  *
- *     F_buffer (with error bit) if the buffer is invalid.
- *     F_parameter (with error bit) if a parameter is invalid.
- *     F_prohibited (with error bit) if the system does not permit accessing the system clock.
- *     F_failure (with error bit) for any other failure.
- *
- *     @todo review codes below.
- *     F_number_too_large (with error bit) if the given ID is too large.
- *     F_number_too_small (with error bit) if the given ID is too small.
  *     F_known_not (with error bit) if the given string is not of a known format
  *
  *     Errors (with error bit) from: f_rip_dynamic_nulless().
+ *     Errors (with error bit) from: f_time_clock_get().
+ *     Errors (with error bit) from: f_utf_is_digit().
+ *     Errors (with error bit) from: f_utf_is_whitespace().
  *     Errors (with error bit) from: fl_conversion_dynamic_partial_to_unsigned_detect().
  *
+ *     Errors (with error bit) from: kt_remove_convert_timezone().
  *     Errors (with error bit) from: kt_remove_get_date_relative().
  * @param buffer
  *   A string containing group name or ID.
@@ -60,8 +56,12 @@ extern "C" {
  *   Must not be NULL.
  *
  * @see f_rip_dynamic_nulless()
+ * @see f_time_clock_get()
+ * @see f_utf_is_digit()
+ * @see f_utf_is_whitespace()
  * @see fl_conversion_dynamic_partial_to_unsigned_detect()
  *
+ * @see kt_remove_convert_timezone()
  * @see kt_remove_get_date_relative()
  */
 #ifndef _di_kt_remove_convert_date_
index 2c86afc74d635ee2a84e7526bf330704501102fd..30c3d2dc927238ce0a9060ac8417494103fb5991 100644 (file)
@@ -19,10 +19,14 @@ extern "C" {
 
     const uint16_t flag_operate = kt_remove_preprocess_file(main, path, 0);
 
-    if (F_status_is_error_not(main->setting.state.status) && !(main->setting.flag & kt_remove_main_flag_simulate_d)) {
+    if (F_status_is_error_not(main->setting.state.status) && !(main->setting.flag & (kt_remove_main_flag_simulate_d)) && !(flag_operate & kt_remove_flag_file_operate_processed_d)) {
       main->setting.state.status = flag_operate & kt_remove_flag_file_operate_directory_d
         ? kt_remove_operate_file_recurse(main, path, flag_operate)
         : kt_remove_operate_file_remove(main, path, flag_operate);
+
+      if (F_status_is_error_not(main->setting.state.status)) {
+        kt_remove_operate_memory_save(main, path, flag_operate);
+      }
     }
 
     if (F_status_is_error_not(main->setting.state.status)) {
@@ -135,6 +139,49 @@ extern "C" {
   }
 #endif // _di_kt_remove_operate_file_remove_normal_
 
+#ifndef _di_kt_remove_operate_memory_check_
+  void kt_remove_operate_memory_check(kt_remove_main_t * const main, const f_string_static_t path, uint16_t * const flag_operate) {
+
+    if (!main) return;
+
+    if (!path.used) {
+      main->setting.state.status = F_data_not;
+
+      return;
+    }
+
+    *flag_operate &= ~kt_remove_flag_file_operate_processed_d;
+
+    main->setting.state.status = F_okay;
+
+    if (!main->cache.memory.used) return;
+
+    // @todo check list and then set F_remove_not as appropriate.
+    // *flag_operate |= kt_remove_flag_file_operate_processed_d
+  }
+#endif // _di_kt_remove_operate_memory_check_
+
+#ifndef _di_kt_remove_operate_memory_save_
+  void kt_remove_operate_memory_save(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate) {
+
+    if (!main) return;
+
+    if (!path.used) {
+      main->setting.state.status = F_data_not;
+
+      return;
+    }
+
+    if (!(main->setting.flag & kt_remove_main_flag_remember_d)) {
+      main->setting.state.status = F_okay;
+
+      return;
+    }
+
+    // @todo
+  }
+#endif // _di_kt_remove_operate_memory_save_
+
 #ifndef _di_kt_remove_operate_shall_remove_
   f_status_t kt_remove_operate_shall_remove(const uint16_t flag) {
 
index a3c6036c365549aad95f68eae288f817e55382c0..fd5712d46315fa7a14102710787f19480f1090db 100644 (file)
@@ -158,6 +158,60 @@ extern "C" {
 #endif // _di_kt_remove_operate_file_remove_normal_
 
 /**
+ * Check if a file should be skipped based on the memory.
+ *
+ * If memory is disabled, then this should always return F_okay.
+ *
+ * @param main
+ *   The main program and settings data.
+ *
+ *   Must not be NULL.
+ *
+ *   This alters main.setting.state.status:
+ *     F_okay on success.
+ *     F_data_not on success but path is an empty string.
+ * @param path
+ *   The path to the file to operate on.
+ * @param flag_operate
+ *   The operate file specific flags from kt_remove_flag_file_operate_*_e.
+ *
+ *   The kt_remove_flag_file_operate_processed_d is set if the path is found in the memory cache.
+ *
+ *   Must not be NULL.
+ *
+ * @see f_string_dynamic_append()
+ */
+#ifndef _di_kt_remove_operate_memory_check_
+  extern void kt_remove_operate_memory_check(kt_remove_main_t * const main, const f_string_static_t path, uint16_t * const flag_operate);
+#endif // _di_kt_remove_operate_memory_check_
+
+/**
+ * Add the path to the memory cache.
+ *
+ * The memory cache is only added when the remember flag (kt_remove_main_flag_remember_d) is set.
+ *
+ * @param main
+ *   The main program and settings data.
+ *
+ *   Must not be NULL.
+ *
+ *   This alters main.setting.state.status:
+ *     F_okay on success and the path is to be processed.
+ *     F_data_not on success but path is an empty string.
+ *
+ *     Errors (with error bit) from: f_string_dynamic_append().
+ * @param path
+ *   The path to the file to operate on.
+ * @param flag_operate
+ *   The operate file specific flags from kt_remove_flag_file_operate_*_e.
+ *
+ * @see f_string_dynamic_append()
+ */
+#ifndef _di_kt_remove_operate_memory_save_
+  extern void kt_remove_operate_memory_save(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate);
+#endif // _di_kt_remove_operate_memory_save_
+
+/**
  * Determine whether or not a file shall be removed based on the given flag.
  *
  * @param flag
index ed2f7e8d119bae918d829570589bbaf17a315077..50bb0c40b7863186a503accf0189850a45d62f6f 100644 (file)
@@ -230,6 +230,9 @@ extern "C" {
       }
     }
 
+    kt_remove_operate_memory_check(main, path, &flag_out);
+    if (F_status_is_error(main->setting.state.status)) return flag_out;
+
     if (main->setting.flag & kt_remove_main_flag_force_d) {
       kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_force_s, F_true);
 
@@ -254,6 +257,10 @@ extern "C" {
 
     kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_remove_s, kt_remove_operate_shall_remove(flag_out));
 
+    if (main->setting.flag & kt_remove_main_flag_remember_d) {
+      kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_skip_s, flag_out & kt_remove_flag_file_operate_processed_d);
+    }
+
     if (main->call.process_operate_file_simulate) {
       main->setting.state.status = F_okay;
 
index 1fdc8b4dcee216991d44a70903a47788884a9435..d61395f25a4a59ceacc325b7f9d452a4fe213032 100644 (file)
@@ -80,6 +80,28 @@ extern "C" {
   }
 #endif // _di_kt_remove_print_error_parameter_missing_value_requires_amount_
 
+#ifndef _di_kt_remove_print_error_parameter_missing_value_requires_yesno_
+  f_status_t kt_remove_print_error_parameter_missing_value_requires_yesno(fl_print_t * const print, const f_string_static_t symbol, const f_string_static_t parameter) {
+
+    if (!print) return F_status_set_error(F_output_not);
+    if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
+
+    f_file_stream_lock(print->to);
+
+    fl_print_format("%[%QThe parameter%] ", print->to, print->set->error, print->prefix, print->set->error);
+    fl_print_format("%[%Q%Q%]", print->to, print->set->notable, symbol, parameter, print->set->notable);
+    fl_print_format(" %[is specified, but neither the%] ", print->to, print->set->error, print->set->error);
+    fl_print_format("%[%r%]", print->to, print->set->notable, kt_remove_yes_s, print->set->notable);
+    fl_print_format(" %[nor the%] ", print->to, print->set->error, print->set->error);
+    fl_print_format("%[%r%]", print->to, print->set->notable, kt_remove_no_s, print->set->notable);
+    fl_print_format(" %[value is given.%]%r", print->to, print->set->error, print->set->error, f_string_eol_s);
+
+    f_file_stream_unlock(print->to);
+
+    return F_okay;
+  }
+#endif // _di_kt_remove_print_error_parameter_missing_value_requires_yesno_
+
 #ifndef _di_kt_remove_print_error_parameter_no_files_
   f_status_t kt_remove_print_error_parameter_no_files(fl_print_t * const print) {
 
index 5ca8216c839d90c6eb62d0553f8c65c6751a45cb..b5fd25251d3c04147f0667c2590b2b76b09697fe 100644 (file)
@@ -182,6 +182,45 @@ extern "C" {
 #endif // _di_kt_remove_print_error_parameter_missing_value_requires_amount_
 
 /**
+ * Print message about parameter not have the required yes/no of values associated with this parameter.
+ *
+ * This is only printed when verbosity is not set to quiet.
+ *
+ * This uses the following:
+ *   - print.set.error: For the error context.
+ *   - print.set.strong: For the highlighting context
+ *   - print.prefix: For the prefixing a string to the message (such as "ERROR:").
+ *
+ * @param print
+ *   The output structure to print to.
+ *
+ *   Must not be NULL.
+ *
+ *   This locks, uses, and unlocks the file stream.
+ *
+ *   This does not alter print.custom.setting.state.status.
+ * @param symbol
+ *   The symbol string prepended to the parameter.
+ *   This locks, uses, and unlocks the file stream.
+ *   This is usually f_console_symbol_long_normal_s.
+ * @param parameter
+ *   The parameter name.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see f_file_stream_lock()
+ * @see f_file_stream_unlock()
+ * @see fl_print_format()
+ */
+#ifndef _di_kt_remove_print_error_parameter_missing_value_requires_yesno_
+  extern f_status_t kt_remove_print_error_parameter_missing_value_requires_yesno(fl_print_t * const print, const f_string_static_t symbol, const f_string_static_t parameter);
+#endif // _di_kt_remove_print_error_parameter_missing_value_requires_yesno_
+
+/**
  * Print message about no files being specified.
  *
  * This is only printed when verbosity is not set to quiet.
index 7f9b2dfce3d9ff07dab90b851869793ad2d79d96..a4c55fe99c7c2314dc785dec53ff93dc4079525d 100644 (file)
@@ -51,8 +51,9 @@ extern "C" {
 
     f_print_dynamic_raw(f_string_eol_s, print->to);
 
-    fll_program_print_help_option_long(print, kt_remove_long_local_s, f_console_symbol_long_normal_s, "Designate dates are in local time, unless time zone is specified.");
-    fll_program_print_help_option_long(print, kt_remove_long_utc_s, f_console_symbol_long_normal_s, "  Designate dates are in UTC, unless time zone is specified.");
+    fll_program_print_help_option_long(print, kt_remove_long_local_s, f_console_symbol_long_normal_s, "   Designate dates are in local time, unless time zone is specified.");
+    fll_program_print_help_option_long(print, kt_remove_long_remember_s, f_console_symbol_long_normal_s, "Remember paths of files already deleted so as to not potentially error out on already removed path.");
+    fll_program_print_help_option_long(print, kt_remove_long_utc_s, f_console_symbol_long_normal_s, "     Designate dates are in UTC, unless time zone is specified.");
 
     f_print_dynamic_raw(f_string_eol_s, print->to);
 
@@ -157,7 +158,11 @@ extern "C" {
     fl_print_format("  - '%[%r%]':             A date like '%[%r%]'.%r", print->to, context.set.notable, kt_remove_date_format_11_s, context.set.notable, context.set.notable, kt_remove_date_format_example_11_s, context.set.notable, f_string_eol_s);
     fl_print_format("  - '%[%r%]':                A date like '%[%r%]'.%r", print->to, context.set.notable, kt_remove_date_format_12_s, context.set.notable, context.set.notable, kt_remove_date_format_example_12_s, context.set.notable, f_string_eol_s);
     fl_print_format("  - '%[%r%]':                   A date like '%[%r%]'.%r", print->to, context.set.notable, kt_remove_date_format_13_s, context.set.notable, context.set.notable, kt_remove_date_format_example_13_s, context.set.notable, f_string_eol_s);
-    fl_print_format("  - '%[%r%]':                     A date like '%[%r%]'.%r", print->to, context.set.notable, kt_remove_date_format_14_s, context.set.notable, context.set.notable, kt_remove_date_format_example_14_s, context.set.notable, f_string_eol_s);
+    fl_print_format("  - '%[%r%]':                     A date like '%[%r%]'.%r%r", print->to, context.set.notable, kt_remove_date_format_14_s, context.set.notable, context.set.notable, kt_remove_date_format_example_14_s, context.set.notable, f_string_eol_s, f_string_eol_s);
+
+    fl_print_format("  The '%[%r%r%]' parameter accepts either ", print->to, context.set.notable, f_console_symbol_long_normal_s, kt_remove_long_remember_s, context.set.notable, f_string_eol_s);
+    fl_print_format("%[%r%]", print->to, context.set.notable, kt_remove_yes_s, context.set.notable);
+    fl_print_format(" or %[%r%] to designate whether or not to remember already pocessed paths.%r", print->to, context.set.notable, kt_remove_no_s, context.set.notable, f_string_eol_s);
 
     f_file_stream_flush(print->to);
     f_file_stream_unlock(print->to);