From f2937ca2323ded8d53601b38d461681d483eb554 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Mon, 19 Jun 2023 15:15:12 -0500 Subject: [PATCH] Progress: Begin setting up directory recursion handling. I started drafting out the directory recursion for the remove. In the middle of this I decided I should really instead focus on this years goal, networking. I am going to follow up with network based projects and so I am putting this on the back burner. --- data/build/remove/dependencies | 2 + data/build/remove/settings | 2 +- sources/c/remove/main/common.c | 2 + sources/c/remove/main/common/define.h | 35 ++++-- sources/c/remove/main/common/type.h | 3 + sources/c/remove/main/main.c | 11 ++ sources/c/remove/main/operate.c | 227 +++++++++++++++++++++++++++++----- sources/c/remove/main/operate.h | 89 +++++++++++++ sources/c/remove/main/print/error.c | 20 +++ sources/c/remove/main/print/error.h | 31 +++++ sources/c/remove/main/remove.c | 7 +- sources/c/remove/main/remove.h | 7 +- 12 files changed, 386 insertions(+), 50 deletions(-) diff --git a/data/build/remove/dependencies b/data/build/remove/dependencies index f6570ba..23fa875 100644 --- a/data/build/remove/dependencies +++ b/data/build/remove/dependencies @@ -11,6 +11,7 @@ f_color f_compare f_console f_conversion +f-directory f_file f_print f_rip @@ -18,6 +19,7 @@ f_signal f_thread fl_conversion +fl_directory fl_string fl_print diff --git a/data/build/remove/settings b/data/build/remove/settings index 8906954..83fd3d2 100644 --- a/data/build/remove/settings +++ b/data/build/remove/settings @@ -32,7 +32,7 @@ build_indexer_arguments rcs build_language c build_libraries -lc -build_libraries-individual -lfll_error -lfll_print -lfll_program -lfl_conversion -lfl_print -lf_account -lf_color -lf_compare -lf_console -lf_conversion -lf_file -lf_memory -lf_pipe -lf_print -lf_rip -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf +build_libraries-individual -lfll_error -lfll_print -lfll_program -lfl_conversion -fl_directory -lfl_print -lf_account -lf_color -lf_compare -lf_console -lf_conversion -lf_directory -lf_file -lf_memory -lf_pipe -lf_print -lf_rip -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf build_libraries-level -lfll_2 -lfll_1 -lfll_0 build_libraries-monolithic -lfll diff --git a/sources/c/remove/main/common.c b/sources/c/remove/main/common.c index 6d94a55..ff21ee8 100644 --- a/sources/c/remove/main/common.c +++ b/sources/c/remove/main/common.c @@ -60,6 +60,8 @@ extern "C" { f_uint32s_resize(0, &setting->groups); f_uint32s_resize(0, &setting->users); + f_directory_recurse_do_delete(&setting->recurse); + return F_none; } #endif // _di_kt_remove_setting_delete_ diff --git a/sources/c/remove/main/common/define.h b/sources/c/remove/main/common/define.h index cfa4b46..ca23a9a 100644 --- a/sources/c/remove/main/common/define.h +++ b/sources/c/remove/main/common/define.h @@ -20,16 +20,19 @@ extern "C" { * The program defines. * * Leap Year: - * - If can be evenly divided by 4, then this is a leap year. + * - If can be evenly divided by 4, then this is a leap year. (@fixme relocate or move "Leap Year" comments where appropriate.) * - * kt_remove_signal_*_d: + * kt_remove_allocation_*_d: + * - console: An allocation step used for small buffers specifically for console parameter. + * - large: An allocation step used for buffers that are anticipated to have large buffers. + * - small: An allocation step used for buffers that are anticipated to have small buffers. + * + * kt_remove_depth_*_d: + * - max: The maximum recursion depth to perform when recursing into a directory. * - * kt_remove_*_d: - * - allocation_console: An allocation step used for small buffers specifically for console parameter. - * - allocation_large: An allocation step used for buffers that are anticipated to have large buffers. - * - allocation_small: An allocation step used for buffers that are anticipated to have small buffers. - * - signal_check: When not using threads, this is how often to perform the check (lower numbers incur more kernel I/O). - * - signal_check_failsafe: When using threads, how many consecutive failures to check signal before aborting (as a recursion failsafe). + * kt_remove_signal_*_d: + * - check: When not using threads, this is how often to perform the check (lower numbers incur more kernel I/O). + * - check_failsafe: When using threads, how many consecutive failures to check signal before aborting (as a recursion failsafe). * * kt_remove_time_seconds_in_*_d: * - day: Number of seconds in a day. @@ -47,6 +50,8 @@ extern "C" { #define kt_remove_allocation_large_d 2048 #define kt_remove_allocation_small_d 128 + #define kt_remove_depth_max_d F_directory_max_recurse_depth_d + #define kt_remove_signal_check_d 20000 #define kt_remove_signal_check_failsafe_d 20000 @@ -69,11 +74,21 @@ extern "C" { * kt_remove_main_flag_prompt_*_d: * - all: All prompt flag bits are combined. */ -#ifndef _di_kt_remove_flag_d_ +#ifndef _di_kt_remove_main_flag_d_ #define kt_remove_main_flag_empty_all_d (kt_remove_main_flag_empty_only_e | kt_remove_main_flag_empty_only_fail_e | kt_remove_main_flag_empty_not_e | kt_remove_main_flag_empty_not_fail_e) #define kt_remove_main_flag_prompt_all_d (kt_remove_main_flag_prompt_all_e | kt_remove_main_flag_prompt_follow_e | kt_remove_main_flag_prompt_never_e | kt_remove_main_flag_prompt_once_e) -#endif // _di_kt_remove_flag_d_ +#endif // _di_kt_remove_main_flag_d_ + +/** + * Defines for bitwise directory recurse flag enumeration combinations. + * + * _di_kt_remove_flag_recurse_*_d: + * - directory_not: All non-directory flags combined. + */ +#ifndef _di_kt_remove_flag_recurse_d_ + #define kt_remove_flag_recurse_directory_not_d (f_directory_recurse_do_flag_block_e | f_directory_recurse_do_flag_character_e | f_directory_recurse_do_flag_fifo_e | f_directory_recurse_do_flag_link_e | f_directory_recurse_do_flag_path_e | f_directory_recurse_do_flag_regular_e | f_directory_recurse_do_flag_socket_e | f_directory_recurse_do_flag_unknown_e) +#endif // _di_kt_remove_flag_recurse_d_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/remove/main/common/type.h b/sources/c/remove/main/common/type.h index dfea6e7..b674921 100644 --- a/sources/c/remove/main/common/type.h +++ b/sources/c/remove/main/common/type.h @@ -173,6 +173,8 @@ extern "C" { f_uint32s_t groups; f_uint32s_t users; + f_directory_recurse_do_t recurse; + const f_string_static_t *program_name; const f_string_static_t *program_name_long; @@ -194,6 +196,7 @@ extern "C" { kt_remove_modes_t_initialize, \ f_uint32s_t_initialize, \ f_uint32s_t_initialize, \ + f_directory_recurse_do_t_initialize, \ 0, \ 0, \ 0, \ diff --git a/sources/c/remove/main/main.c b/sources/c/remove/main/main.c index 2fd7680..6c9d8be 100644 --- a/sources/c/remove/main/main.c +++ b/sources/c/remove/main/main.c @@ -1,6 +1,10 @@ #include "remove.h" #include "main.h" +#ifdef __cplusplus +extern "C" { +#endif + int main(const int argc, const f_string_t *argv, const f_string_t *envp) { kt_remove_main_t data = kt_remove_main_t_initialize; @@ -21,6 +25,9 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { data.setting.program_name_long = &kt_remove_program_name_long_s; data.setting.process_help = &kt_remove_process_help; data.setting.process_normal = &kt_remove_process_normal; + data.setting.recurse.action = &kt_remove_operate_file_directory_recurse_action; + data.setting.recurse.handle = &kt_remove_operate_file_directory_recurse_handle; + data.setting.recurse.depth_max = kt_remove_depth_max_d; #ifdef _en_kt_default_to_utc_ data.setting.flag |= kt_remove_flag_utc_e; @@ -82,3 +89,7 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { return (F_status_is_error(data.setting.state.status) || data.setting.state.status == F_false) ? 1 : 0; } + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/remove/main/operate.c b/sources/c/remove/main/operate.c index 3da1421..74dc72c 100644 --- a/sources/c/remove/main/operate.c +++ b/sources/c/remove/main/operate.c @@ -17,6 +17,185 @@ extern "C" { if (main->program.signal_received) return; + const uint8_t flag = kt_remove_operate_file_simulate(main, path); + if (F_status_is_error(main->setting.state.status)) return; + + if (!(main->setting.flag & kt_remove_main_flag_simulate_e)) { + if (flag & kt_remove_flag_file_operate_directory_e) { + kt_remove_operate_file_directory(main, path, flag); + if (F_status_is_error(main->setting.state.status)) return; + } + else { + kt_remove_operate_file_normal(main, path, flag); + if (F_status_is_error(main->setting.state.status)) return; + } + } + + main->setting.state.status = F_none; + } +#endif // _di_kt_remove_operate_file_ + +#ifndef _di_kt_remove_operate_file_directory_ + void kt_remove_operate_file_directory(kt_remove_main_t * const main, const f_string_static_t path, const uint8_t flag) { + + if (!(flag & kt_remove_flag_file_operate_remove_e)) { + main->setting.state.status = F_no; + + return; + } + + main->setting.recurse.state.custom = (void *) main; + main->setting.recurse.state.code = flag; + main->setting.recurse.flag = f_directory_recurse_do_flag_list_e | f_directory_recurse_do_flag_after_e; + + // @todo consider this in recursion and maybe provide a new parameter follow_recurse for this. + /*if (flag & kt_remove_flag_file_operate_follow_e) { + data.setting.recurse.flag |= f_directory_recurse_do_flag_dereference_e; + }*/ + + fl_directory_do(path, &main->setting.recurse); + if (F_status_is_error(main->setting.state.status)) return; + + main->setting.state.status = F_yes; + } +#endif // _di_kt_remove_operate_file_directory_ + +#ifndef _di_kt_remove_operate_file_directory_recurse_action_ + void kt_remove_operate_file_directory_recurse_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->state.custom) return; + + kt_remove_main_t * const main = (kt_remove_main_t *) recurse->state.custom; + + if (main) { + recurse->state.status = F_status_set_error(F_parameter); + + return; + } + + if (flag == f_directory_recurse_do_flag_list_e) { + // @todo check all listing to determine if any directory is to be recursed or not. + if (recurse->listing.block.used || recurse->listing.character.used || recurse->listing.directory.used || recurse->listing.regular.used || recurse->listing.link.used || recurse->listing.fifo.used || recurse->listing.socket.used || recurse->listing.unknown.used) { + if (!(main->setting.recurse.state.code & kt_remove_flag_file_operate_recurse_e)) { + // @todo error out on trying to remove non-empty directory without recursion. + recurse->state.status = F_status_set_error(F_recurse_not); + } + } + else { + if (main->setting.recurse.state.code & kt_remove_flag_file_operate_remove_e) { + recurse->state.status = f_directory_remove(name, 0, F_false); + + if (F_status_is_error_not(recurse->state.status)) { + recurse->state.status = F_done; + } + } + else { + recurse->state.status = F_done; + } + } + + return; + } + + if (flag & f_directory_recurse_do_flag_after_e) { + kt_remove_operate_file(main, name); + recurse->state.status = main->setting.state.status; + + const uint8_t flag = kt_remove_operate_file_simulate(main, name); + if (F_status_is_error(main->setting.state.status)) return; + + // @todo needs empty check to see if directory contents are fully removed (because of removal conditions). + + if (!(main->setting.flag & kt_remove_main_flag_simulate_e)) { + if (flag & kt_remove_flag_file_operate_directory_e) { + kt_remove_operate_file_directory(main, name, flag); + if (F_status_is_error(main->setting.state.status)) return; + } + else { + kt_remove_operate_file_normal(main, name, flag); + if (F_status_is_error(main->setting.state.status)) return; + } + } + + return; + } + } +#endif // _di_kt_remove_operate_file_directory_recurse_action_ + +#ifndef _di_kt_remove_operate_file_directory_recurse_handle_ + void kt_remove_operate_file_directory_recurse_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->state.custom) return; + + kt_remove_main_t * const main = (kt_remove_main_t *) recurse->state.custom; + + if (!main) return; + + // Arguments to fl_recurse_do() are invalid (parameter checking). + if (flag == f_directory_recurse_do_flag_top_e) { + // @todo print error message. + + return; + } + + // The top-level path is an empty string or an error occurred while processing the top-level path. + if (flag == (f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e)) { + // @todo print error message. + // @todo note that F_directory_not (with error bit) is returned if the top-level path is not a directory. + + return; + } + + // The top-level path is an empty string or an error occurred while processing the top-level path. + if (flag == (f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e | f_directory_recurse_do_flag_before_e)) { + // @todo print error message. + // @todo note that F_directory_not (with error bit) is returned if the top-level path does not exist. + + return; + } + + // An error happened during directory list loading. + if (flag == (f_directory_recurse_do_flag_list_e | f_directory_recurse_do_flag_path_e)) { + // @todo print error message. + + return; + } + + + main->setting.state.status = recurse->state.status; + + //kt_remove_print_error_recursion_max(&main->program.error); + + // recurse->state.code is the top-level operate flag. + + //kt_remove_print_error_operate_file_directory_recurse(&main->program.error, macro_fake_f(fl_directory_do), flag_operate, *recurse->path_top, recurse->path_cache, f_file_operation_delete_s, F_true); + } +#endif // _di_kt_remove_operate_file_directory_recurse_handle_ + +#ifndef _di_kt_remove_operate_file_simulate_ + uint8_t kt_remove_operate_file_simulate(kt_remove_main_t * const main, const f_string_static_t path) { + + if (!main) return 0; + + if (!path.used) { + main->setting.state.status = F_data_not; + + return 0; + } + + if (main->program.signal_received) return 0; + kt_remove_print_simulate_operate_file(&main->program.output, path); main->setting.state.status = f_file_exists(path, main->setting.flag & kt_remove_main_flag_follow_e); @@ -28,7 +207,7 @@ extern "C" { remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_not_found_s); } - return; + return 0; } if (F_status_is_error(main->setting.state.status)) { @@ -36,16 +215,16 @@ extern "C" { remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_no_access_s); } - return; + return 0; } if (main->setting.state.status == F_false) { kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_remove_s, F_false); - return; + return 0; } - if (main->program.signal_received) return; + if (main->program.signal_received) return 0; f_number_unsigned_t i = 0; uint8_t flag = (main->setting.flag & kt_remove_main_flag_option_used_e) ? 0 : kt_remove_flag_file_operate_remove_e; @@ -67,7 +246,7 @@ extern "C" { remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_stat_fail_s); } - return; + return flag; } if (main->setting.flag & kt_remove_main_flag_block_e) { @@ -118,7 +297,7 @@ extern "C" { if (main->setting.flag & kt_remove_main_flag_user_e) { for (i = 0; i < main->setting.users.used; ++i) { - if (main->program.signal_received) return; + if (main->program.signal_received) return flag; if (statistics.st_uid == (uid_t) main->setting.users.array[i]) break; } // for @@ -142,7 +321,7 @@ extern "C" { if (main->setting.flag & kt_remove_main_flag_group_e) { for (i = 0; i < main->setting.groups.used; ++i) { - if (main->program.signal_received) return; + if (main->program.signal_received) return flag; if (statistics.st_gid == (gid_t) main->setting.groups.array[i]) break; } // for @@ -156,7 +335,7 @@ extern "C" { for (i = 0; i < main->setting.modes.used; ++i) { - if (main->program.signal_received) return; + if (main->program.signal_received) return flag; if (main->setting.modes.array[i].type == kt_remove_flag_mode_different_e) { if (main->setting.modes.array[i].mode & ~mode) break; @@ -189,12 +368,12 @@ extern "C" { main->setting.state.status = F_none; main->setting.process_operate_file((void *) main, path, statistics, &flag); - if (F_status_is_error(main->setting.state.status)) return; + if (F_status_is_error(main->setting.state.status)) return flag; if (main->setting.state.status == F_done) { main->setting.state.status = F_none; - return; + return flag; } } @@ -222,6 +401,8 @@ extern "C" { else if (main->setting.flag & kt_remove_main_flag_tree_e) { // @todo handle simulate for this. } + + // @todo call a similate fl_directory_do() or move this into the kt_remove_operate_file_directory() process. } if (main->setting.flag & kt_remove_main_flag_prompt_all_d) { @@ -230,33 +411,11 @@ extern "C" { kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_remove_s, flag & kt_remove_flag_file_operate_remove_e); - if (!(main->setting.flag & kt_remove_main_flag_simulate_e)) { - if (flag & kt_remove_flag_file_operate_directory_e) { - kt_remove_operate_file_directory(main, path, flag); - if (F_status_is_error(main->setting.state.status)) return; - } - else { - kt_remove_operate_file_normal(main, path, flag); - if (F_status_is_error(main->setting.state.status)) return; - } - } - main->setting.state.status = F_none; - } -#endif // _di_kt_remove_operate_file_ - -#ifndef _di_kt_remove_operate_file_directory_ - void kt_remove_operate_file_directory(kt_remove_main_t * const main, const f_string_static_t path, const uint8_t flag) { - if (!(flag & kt_remove_flag_file_operate_remove_e)) { - main->setting.state.status = F_no; - - return; - } - - main->setting.state.status = F_yes; + return flag; } -#endif // _di_kt_remove_operate_file_directory_ +#endif // _di_kt_remove_operate_file_simulate_ #ifndef _di_kt_remove_operate_file_normal_ void kt_remove_operate_file_normal(kt_remove_main_t * const main, const f_string_static_t path, const uint8_t flag) { diff --git a/sources/c/remove/main/operate.h b/sources/c/remove/main/operate.h index 1253df3..963b523 100644 --- a/sources/c/remove/main/operate.h +++ b/sources/c/remove/main/operate.h @@ -21,8 +21,24 @@ extern "C" { * This alters main.setting.state.status: * F_none on success. * F_data_not on success but file is an empty string. + * + * Errors (with error bit) from: f_string_dynamic_append(). + * + * Errors (with error bit) from: kt_remove_operate_file_directory(). + * Errors (with error bit) from: kt_remove_operate_file_normal(). + * Errors (with error bit) from: kt_remove_operate_file_simulate(). * @param path * The path to the file to operate on. + * + * This should always be TRUE when calling from the top level. + * This should always be FALSE if calling from within a fl_directory_do() callback. + * This is because fl_directory_do() handles directory traversal and processing. + * + * @see f_string_dynamic_append() + * + * @see kt_remove_operate_file_directory() + * @see kt_remove_operate_file_normal() + * @see kt_remove_operate_file_simulate() */ #ifndef _di_kt_remove_operate_file_ extern void kt_remove_operate_file(kt_remove_main_t * const main, const f_string_static_t path); @@ -38,17 +54,60 @@ extern "C" { * F_no on success but file is not to be removed. * F_yes on success and file is removed. * + * F_recurse (with error bit) on max recursion depth reached. + * * Errors (with error bit) from: f_file_remove(). * @param path * The path to the file to operate on. * @param flag * The operate file specific flags from kt_remove_flag_file_operate_*_e. + * + * @see f_file_remove() */ #ifndef _di_kt_remove_operate_file_directory_ extern void kt_remove_operate_file_directory(kt_remove_main_t * const main, const f_string_static_t path, const uint8_t flag); #endif // _di_kt_remove_operate_file_directory_ /** + * Perform directory recurse file operation action. + * + * @param recurse + * Must not be NULL. + * Must be of type f_directory_recurse_do_t. + * @param 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. + * @param flag + * A flag representing the particular action being performed. + * + * @see f_directory_remove() + * @see fl_directory_do() + */ +#ifndef _di_kt_remove_operate_file_directory_recurse_action_ + extern void kt_remove_operate_file_directory_recurse_action(void * const recurse, const f_string_static_t name, const uint16_t flag); +#endif // _di_kt_remove_operate_file_directory_recurse_action_ + +/** + * Handle errors while performing directory recurse file operation action. + * + * @param recurse + * Must not be NULL. + * Must be of type f_directory_recurse_do_t. + * @param 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. + * @param flag + * A flag representing the particular action being performed. + * + * @see fl_directory_do() + */ +#ifndef _di_kt_remove_operate_file_directory_recurse_handle_ + extern void kt_remove_operate_file_directory_recurse_handle(void * const recurse, const f_string_static_t name, const uint16_t flag); +#endif // _di_kt_remove_operate_file_directory_recurse_handle_ + +/** * Perform actual file removal for non-directory files. * * @param main @@ -58,18 +117,48 @@ extern "C" { * F_no on success but file is not to be removed. * F_yes on success and file is removed. * + * Errors (with error bit) from: f_file_link_read(). * Errors (with error bit) from: f_file_remove(). * @param path * The path to the file to operate on. * @param flag * The operate file specific flags from kt_remove_flag_file_operate_*_e. * + * @see f_file_link_read() * @see f_file_remove() */ #ifndef _di_kt_remove_operate_file_normal_ extern void kt_remove_operate_file_normal(kt_remove_main_t * const main, const f_string_static_t path, const uint8_t flag); #endif // _di_kt_remove_operate_file_normal_ +/** + * Perform simulation of the file operation. + * + * The simulation process is also intended to be used to determine what to do with the actual file. + * A flag is populated based on the results of the simulation analysis. + * + * @param main + * The main program and settings data. + * + * This alters main.setting.state.status: + * F_none on success. + * F_data_not on success but file is an empty string. + * + * Errors (with error bit) from: f_file_link_read(). + * Errors (with error bit) from: f_file_remove(). + * @param path + * The path to the file to operate on. + * + * @return + * The flags determined by the simulation. + * + * @see f_file_link_read() + * @see f_file_remove() + */ +#ifndef _di_kt_remove_operate_file_simulate_ + extern uint8_t kt_remove_operate_file_simulate(kt_remove_main_t * const main, const f_string_static_t path); +#endif // _di_kt_remove_operate_file_simulate_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/remove/main/print/error.c b/sources/c/remove/main/print/error.c index ebcdbc9..ef8fbff 100644 --- a/sources/c/remove/main/print/error.c +++ b/sources/c/remove/main/print/error.c @@ -60,6 +60,26 @@ extern "C" { } #endif // _di_kt_remove_print_error_parameter_no_files_ +#ifndef _di_kt_remove_print_error_recursion_max_ + f_status_t kt_remove_print_error_recursion_max(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_error_e) return F_output_not; + + kt_remove_main_t *main = (kt_remove_main_t *) print->custom; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QMax recursion of", print->to, print->set->error, print->prefix, print->set->error, f_string_eol_s); + fl_print_format("%[%ul%]", print->to, print->set->notable, main->setting.recurse.depth_max, print->set->notable); + fl_print_format(" at '%[%Q%]'.%]%r", print->to, print->set->notable, path, print->set->notable, f_string_eol_s); + + f_file_stream_unlock(print->to); + + return F_none; + } +#endif // _di_kt_remove_print_error_recursion_max_ + #ifndef _di_kt_remove_print_error_parameter_unknown_value_ f_status_t kt_remove_print_error_parameter_unknown_value(fl_print_t * const print, const f_string_static_t symbol, const f_string_static_t parameter, const f_string_static_t value) { diff --git a/sources/c/remove/main/print/error.h b/sources/c/remove/main/print/error.h index 81591fa..cc7c1eb 100644 --- a/sources/c/remove/main/print/error.h +++ b/sources/c/remove/main/print/error.h @@ -134,6 +134,37 @@ extern "C" { #endif // _di_kt_remove_print_error_parameter_no_files_ /** + * Print message about max recursion being reached. + * + * 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. + * + * This locks, uses, and unlocks the file stream. + * + * This does not alter print.custom.setting.state.status. + * @param path + * The path in which the recursion max is reached. + * + * @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 fll_print_format() + */ +#ifndef _di_kt_remove_print_error_recursion_max_ + extern f_status_t kt_remove_print_error_recursion_max(fl_print_t * const print, const f_string_static_t path); +#endif // _di_kt_remove_print_error_recursion_max_ + +/** * Print message about parameter having an unknown value. * * This is only printed when verbosity is not set to quiet. diff --git a/sources/c/remove/main/remove.c b/sources/c/remove/main/remove.c index 071b5ab..3d4f757 100644 --- a/sources/c/remove/main/remove.c +++ b/sources/c/remove/main/remove.c @@ -49,7 +49,7 @@ extern "C" { } if (main->program.signal_received) { - main->setting.state.status = F_interrupt; + main->setting.state.status = F_status_set_error(F_interrupt); } if (main->setting.state.status == F_status_set_error(F_interrupt)) { @@ -105,13 +105,12 @@ extern "C" { for (f_number_unsigned_t i = 0; i < main->setting.files.used; ++i) { kt_remove_operate_file(main, main->setting.files.array[i]); - if (F_status_is_error(main->setting.state.status)) break; - if ((main->setting.flag & kt_remove_main_flag_simulate_e) && i + 1 < main->setting.files.used) { + if ((main->setting.flag & kt_remove_main_flag_simulate_e) && i + 1 < main->setting.files.used && (F_status_is_error_not(main->setting.state.status) || F_status_set_fine(main->setting.state.status) == F_interrupt)) { f_print_dynamic(f_string_eol_s, main->program.output.to); } - if (main->setting.state.status == F_interrupt) break; + if (F_status_is_error(main->setting.state.status)) break; } // for } #endif // _di_kt_remove_process_normal_operate_ diff --git a/sources/c/remove/main/remove.h b/sources/c/remove/main/remove.h index bb03653..77091e5 100644 --- a/sources/c/remove/main/remove.h +++ b/sources/c/remove/main/remove.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ // FLL-1 includes. #include +#include #include // FLL-2 includes. @@ -84,7 +86,10 @@ extern "C" { * F_none on success. * F_true on success when performing verification and verify passed. * F_false on success when performing verification and verify failed. - * F_interrupt on (exit) signal received. + * + * F_interrupt (with error bit) on (exit) signal received. + * + * Errors (with error bit) from: main.callback.process_normal(). */ #ifndef _di_kt_remove_main_ extern void kt_remove_main(kt_remove_main_t * const main); -- 1.8.3.1