From 224dab331a458daeb5b623736b5e12050fa4eeff Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 23 Jul 2022 17:41:30 -0500 Subject: [PATCH] Bugfix: Link operation is incorrect, support new link arguments, and clone and copy operation failure problems. The link operation target path is relative to the point path. The previous code is trying to treat the target path in isolation. Change the behavior to make the target path relative to the point path. Add two new options to make creating symbolic linking easier to use: 1) "force": Used to forcibly overwrite an existing file or directory. 2) "strict": Used to require the target path to exist when creating the symbolic links. The clone and copy operations now have better error return code processing. --- level_3/fake/c/private-common.c | 8 +- level_3/fake/c/private-common.h | 24 ++- level_3/fake/c/private-make-operate_process_type.c | 48 ++++- .../fake/c/private-make-operate_validate_type.c | 228 ++++++++++++++++----- level_3/fake/c/private-print.c | 72 ++++++- level_3/fake/c/private-print.h | 57 ++++++ level_3/fake/documents/fakefile.txt | 8 +- level_3/fake/specifications/fakefile.txt | 2 +- 8 files changed, 365 insertions(+), 82 deletions(-) diff --git a/level_3/fake/c/private-common.c b/level_3/fake/c/private-common.c index 46559a2..74b9df1 100644 --- a/level_3/fake/c/private-common.c +++ b/level_3/fake/c/private-common.c @@ -209,12 +209,13 @@ extern "C" { const f_string_static_t fake_make_operation_touch_s = macro_f_string_static_t_initialize(FAKE_make_operation_touch_s, 0, FAKE_make_operation_touch_s_length); const f_string_static_t fake_make_operation_write_s = macro_f_string_static_t_initialize(FAKE_make_operation_write_s, 0, FAKE_make_operation_write_s_length); - const f_string_static_t fake_make_operation_argument_environment_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_environment_s, 0, FAKE_make_operation_argument_environment_s_length); - const f_string_static_t fake_make_operation_argument_failure_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_failure_s, 0, FAKE_make_operation_argument_failure_s_length); - const f_string_static_t fake_make_operation_argument_file_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_file_s, 0, FAKE_make_operation_argument_file_s_length); const f_string_static_t fake_make_operation_argument_directory_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_directory_s, 0, FAKE_make_operation_argument_directory_s_length); + const f_string_static_t fake_make_operation_argument_environment_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_environment_s, 0, FAKE_make_operation_argument_environment_s_length); const f_string_static_t fake_make_operation_argument_error_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_error_s, 0, FAKE_make_operation_argument_error_s_length); const f_string_static_t fake_make_operation_argument_exit_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_exit_s, 0, FAKE_make_operation_argument_exit_s_length); + const f_string_static_t fake_make_operation_argument_failure_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_failure_s, 0, FAKE_make_operation_argument_failure_s_length); + const f_string_static_t fake_make_operation_argument_file_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_file_s, 0, FAKE_make_operation_argument_file_s_length); + const f_string_static_t fake_make_operation_argument_force_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_force_s, 0, FAKE_make_operation_argument_force_s_length); const f_string_static_t fake_make_operation_argument_has_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_has_s, 0, FAKE_make_operation_argument_has_s_length); const f_string_static_t fake_make_operation_argument_ignore_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_ignore_s, 0, FAKE_make_operation_argument_ignore_s_length); const f_string_static_t fake_make_operation_argument_is_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_is_s, 0, FAKE_make_operation_argument_is_s_length); @@ -222,6 +223,7 @@ extern "C" { const f_string_static_t fake_make_operation_argument_parameter_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_parameter_s, 0, FAKE_make_operation_argument_parameter_s_length); const f_string_static_t fake_make_operation_argument_point_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_point_s, 0, FAKE_make_operation_argument_point_s_length); const f_string_static_t fake_make_operation_argument_recursive_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_recursive_s, 0, FAKE_make_operation_argument_recursive_s_length); + const f_string_static_t fake_make_operation_argument_strict_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_strict_s, 0, FAKE_make_operation_argument_strict_s_length); const f_string_static_t fake_make_operation_argument_success_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_success_s, 0, FAKE_make_operation_argument_success_s_length); const f_string_static_t fake_make_operation_argument_target_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_target_s, 0, FAKE_make_operation_argument_target_s_length); const f_string_static_t fake_make_operation_argument_warn_s = macro_f_string_static_t_initialize(FAKE_make_operation_argument_warn_s, 0, FAKE_make_operation_argument_warn_s_length); diff --git a/level_3/fake/c/private-common.h b/level_3/fake/c/private-common.h index a5299ad..4d372d1 100644 --- a/level_3/fake/c/private-common.h +++ b/level_3/fake/c/private-common.h @@ -1324,12 +1324,13 @@ extern "C" { // Total does not include "fake_make_operation_type_none_e". #define fake_make_operation_total_d 35 - #define FAKE_make_operation_argument_environment_s "environment" - #define FAKE_make_operation_argument_failure_s "failure" - #define FAKE_make_operation_argument_file_s "file" #define FAKE_make_operation_argument_directory_s "directory" + #define FAKE_make_operation_argument_environment_s "environment" #define FAKE_make_operation_argument_error_s "error" #define FAKE_make_operation_argument_exit_s "exit" + #define FAKE_make_operation_argument_failure_s "failure" + #define FAKE_make_operation_argument_file_s "file" + #define FAKE_make_operation_argument_force_s "force" #define FAKE_make_operation_argument_has_s "has" #define FAKE_make_operation_argument_ignore_s "ignore" #define FAKE_make_operation_argument_is_s "is" @@ -1337,16 +1338,18 @@ extern "C" { #define FAKE_make_operation_argument_parameter_s "parameter" #define FAKE_make_operation_argument_point_s "point" #define FAKE_make_operation_argument_recursive_s "recursive" + #define FAKE_make_operation_argument_strict_s "strict" #define FAKE_make_operation_argument_success_s "success" #define FAKE_make_operation_argument_target_s "target" #define FAKE_make_operation_argument_warn_s "warn" - #define FAKE_make_operation_argument_environment_s_length 11 - #define FAKE_make_operation_argument_failure_s_length 7 - #define FAKE_make_operation_argument_file_s_length 4 #define FAKE_make_operation_argument_directory_s_length 9 + #define FAKE_make_operation_argument_environment_s_length 11 #define FAKE_make_operation_argument_error_s_length 5 #define FAKE_make_operation_argument_exit_s_length 4 + #define FAKE_make_operation_argument_failure_s_length 7 + #define FAKE_make_operation_argument_file_s_length 4 + #define FAKE_make_operation_argument_force_s_length 5 #define FAKE_make_operation_argument_has_s_length 3 #define FAKE_make_operation_argument_ignore_s_length 6 #define FAKE_make_operation_argument_is_s_length 2 @@ -1354,16 +1357,18 @@ extern "C" { #define FAKE_make_operation_argument_parameter_s_length 9 #define FAKE_make_operation_argument_point_s_length 5 #define FAKE_make_operation_argument_recursive_s_length 9 + #define FAKE_make_operation_argument_strict_s_length 6 #define FAKE_make_operation_argument_success_s_length 7 #define FAKE_make_operation_argument_target_s_length 6 #define FAKE_make_operation_argument_warn_s_length 4 - extern const f_string_static_t fake_make_operation_argument_environment_s; - extern const f_string_static_t fake_make_operation_argument_failure_s; - extern const f_string_static_t fake_make_operation_argument_file_s; extern const f_string_static_t fake_make_operation_argument_directory_s; + extern const f_string_static_t fake_make_operation_argument_environment_s; extern const f_string_static_t fake_make_operation_argument_error_s; extern const f_string_static_t fake_make_operation_argument_exit_s; + extern const f_string_static_t fake_make_operation_argument_failure_s; + extern const f_string_static_t fake_make_operation_argument_file_s; + extern const f_string_static_t fake_make_operation_argument_force_s; extern const f_string_static_t fake_make_operation_argument_has_s; extern const f_string_static_t fake_make_operation_argument_ignore_s; extern const f_string_static_t fake_make_operation_argument_is_s; @@ -1371,6 +1376,7 @@ extern "C" { extern const f_string_static_t fake_make_operation_argument_parameter_s; extern const f_string_static_t fake_make_operation_argument_point_s; extern const f_string_static_t fake_make_operation_argument_recursive_s; + extern const f_string_static_t fake_make_operation_argument_strict_s; extern const f_string_static_t fake_make_operation_argument_success_s; extern const f_string_static_t fake_make_operation_argument_target_s; extern const f_string_static_t fake_make_operation_argument_warn_s; diff --git a/level_3/fake/c/private-make-operate_process_type.c b/level_3/fake/c/private-make-operate_process_type.c index 375ff31..b36e391 100644 --- a/level_3/fake/c/private-make-operate_process_type.c +++ b/level_3/fake/c/private-make-operate_process_type.c @@ -1312,10 +1312,52 @@ extern "C" { f_status_t status = F_none; - status = f_file_link(data_make->cache_arguments.array[0], data_make->cache_arguments.array[1]); + // 0x1 = force, 0x2 = strict. + uint8_t flag = 0; + + if (data_make->cache_arguments.used > 2) { + if (fl_string_dynamic_compare(fake_make_operation_argument_force_s, data_make->cache_arguments.array[1]) != F_equal_to) { + flag |= 0x1; + } + else if (fl_string_dynamic_compare(fake_make_operation_argument_strict_s, data_make->cache_arguments.array[1]) == F_equal_to) { + flag |= 0x2; + } + + if (data_make->cache_arguments.used > 3) { + if (fl_string_dynamic_compare(fake_make_operation_argument_force_s, data_make->cache_arguments.array[2]) != F_equal_to) { + flag |= 0x1; + } + else if (fl_string_dynamic_compare(fake_make_operation_argument_strict_s, data_make->cache_arguments.array[2]) == F_equal_to) { + flag |= 0x2; + } + } + } + + if ((flag & 0x1) && f_file_exists(data_make->cache_arguments.array[data_make->cache_arguments.used - 1], F_false) == F_true) { + if (f_directory_is(data_make->cache_arguments.array[data_make->cache_arguments.used - 1]) == F_true) { + status = f_directory_remove(data_make->cache_arguments.array[data_make->cache_arguments.used - 1], F_directory_descriptors_max_d, F_false); + + if (F_status_is_error(status)) { + fll_error_file_print(data_make->error, F_status_set_fine(status), "f_directory_remove", F_true, data_make->cache_arguments.array[data_make->cache_arguments.used - 1], f_file_operation_delete_s, fll_error_file_type_directory_e); + + return F_status_set_error(F_failure); + } + } + else { + status = f_file_remove(data_make->cache_arguments.array[data_make->cache_arguments.used - 1]); + + if (F_status_is_error(status)) { + fll_error_file_print(data_make->error, F_status_set_fine(status), "f_file_remove", F_true, data_make->cache_arguments.array[data_make->cache_arguments.used - 1], f_file_operation_delete_s, fll_error_file_type_file_e); + + return F_status_set_error(F_failure); + } + } + } + + status = f_file_link(data_make->cache_arguments.array[0], data_make->cache_arguments.array[data_make->cache_arguments.used - 1]); if (F_status_is_error(status)) { - fll_error_file_print(data_make->error, F_status_set_fine(status), "f_file_link", F_true, data_make->cache_arguments.array[1], f_file_operation_link_s, fll_error_file_type_file_e); + fll_error_file_print(data_make->error, F_status_set_fine(status), "f_file_link", F_true, data_make->cache_arguments.array[data_make->cache_arguments.used - 1], f_file_operation_link_s, fll_error_file_type_file_e); return F_status_set_error(F_failure); } @@ -1323,7 +1365,7 @@ extern "C" { if (data_make->main->error.verbosity >= f_console_verbosity_verbose_e) { flockfile(data_make->main->output.to.stream); - fl_print_format("Created symbolic link from '%[%Q%]", data_make->main->output.to.stream, data_make->main->context.set.notable, data_make->cache_arguments.array[1], data_make->main->context.set.notable); + fl_print_format("Created symbolic link from '%[%Q%]", data_make->main->output.to.stream, data_make->main->context.set.notable, data_make->cache_arguments.array[data_make->cache_arguments.used - 1], data_make->main->context.set.notable); fl_print_format("' to %[%Q%].%r", data_make->main->output.to.stream, data_make->main->context.set.notable, data_make->cache_arguments.array[0], data_make->main->context.set.notable, f_string_eol_s); funlockfile(data_make->main->output.to.stream); diff --git a/level_3/fake/c/private-make-operate_validate_type.c b/level_3/fake/c/private-make-operate_validate_type.c index 7d96ed3..c40b377 100644 --- a/level_3/fake/c/private-make-operate_validate_type.c +++ b/level_3/fake/c/private-make-operate_validate_type.c @@ -123,15 +123,16 @@ extern "C" { if (data_make->cache_arguments.used > 1) { f_status_t status = F_none; + f_status_t status_file = F_none; for (f_array_length_t i = 0; i < data_make->cache_arguments.used; ++i) { - status = fake_make_assure_inside_project(data_make, data_make->cache_arguments.array[i]); + status_file = fake_make_assure_inside_project(data_make, data_make->cache_arguments.array[i]); - if (F_status_is_error(status)) { - fake_print_message_section_operation_path_outside(data_make->data, data_make->error, F_status_set_fine(status), "fake_make_assure_inside_project", data_make->cache_path.used ? data_make->cache_path : data_make->cache_arguments.array[i]); + if (F_status_is_error(status_file)) { + fake_print_message_section_operation_path_outside(data_make->data, data_make->error, F_status_set_fine(status_file), "fake_make_assure_inside_project", data_make->cache_path.used ? data_make->cache_path : data_make->cache_arguments.array[i]); - if (F_status_set_fine(status) == F_false) return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } } // for @@ -148,16 +149,16 @@ extern "C" { funlockfile(data_make->error.to.stream); } - return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } } // for if (data_make->cache_arguments.used > 2) { // The last file must be a directory. - status = f_directory_is(data_make->cache_arguments.array[data_make->cache_arguments.used - 1]); + status_file = f_directory_is(data_make->cache_arguments.array[data_make->cache_arguments.used - 1]); - if (status == F_false || status == F_file_found_not) { + if (status_file == F_false || status_file == F_file_found_not) { if (data_make->error.verbosity != f_console_verbosity_quiet_e && data_make->error.to.stream) { flockfile(data_make->error.to.stream); @@ -168,24 +169,24 @@ extern "C" { funlockfile(data_make->error.to.stream); } - return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } - if (F_status_is_error(status)) { - fll_error_file_print(data_make->error, F_status_set_fine(status), "f_directory_is", F_true, data_make->cache_arguments.array[data_make->cache_arguments.used - 1], f_file_operation_find_s, fll_error_file_type_directory_e); + if (F_status_is_error(status_file)) { + fll_error_file_print(data_make->error, F_status_set_fine(status_file), "f_directory_is", F_true, data_make->cache_arguments.array[data_make->cache_arguments.used - 1], f_file_operation_find_s, fll_error_file_type_directory_e); - return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } } else { // When the first file is a directory, then the second, if it exists, must also be a directory. - status = f_directory_is(data_make->cache_arguments.array[0]); + status_file = f_directory_is(data_make->cache_arguments.array[0]); - if (status == F_true) { - status = f_directory_is(data_make->cache_arguments.array[1]); + if (status_file == F_true) { + status_file = f_directory_is(data_make->cache_arguments.array[1]); - if (status == F_false) { + if (status_file == F_false) { if (data_make->error.verbosity != f_console_verbosity_quiet_e && data_make->error.to.stream) { flockfile(data_make->error.to.stream); @@ -196,12 +197,12 @@ extern "C" { funlockfile(data_make->error.to.stream); } - return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } } } - return F_none; + return status; } fake_print_error_requires_more_arguments(data_make); @@ -716,23 +717,18 @@ extern "C" { if (data_make->cache_arguments.used > 1) { f_status_t status = F_none; + f_status_t status_file = F_none; - { - f_status_t status_file = F_none; - - for (f_array_length_t i = 0; i < data_make->cache_arguments.used; ++i) { - - status_file = fake_make_assure_inside_project(data_make, data_make->cache_arguments.array[i]); + for (f_array_length_t i = 0; i < data_make->cache_arguments.used; ++i) { - if (F_status_is_error(status_file)) { - fake_print_message_section_operation_path_outside(data_make->data, data_make->error, F_status_set_fine(status_file), "fake_make_assure_inside_project", data_make->cache_path.used ? data_make->cache_path : data_make->cache_arguments.array[i]); + status_file = fake_make_assure_inside_project(data_make, data_make->cache_arguments.array[i]); - status = F_status_set_error(F_failure); - } - } // for - } + if (F_status_is_error(status_file)) { + fake_print_message_section_operation_path_outside(data_make->data, data_make->error, F_status_set_fine(status_file), "fake_make_assure_inside_project", data_make->cache_path.used ? data_make->cache_path : data_make->cache_arguments.array[i]); - if (F_status_is_error(status)) return status; + status = F_status_set_error(F_failure); + } + } // for for (f_array_length_t i = 0; i < data_make->cache_arguments.used - 1; ++i) { @@ -747,16 +743,16 @@ extern "C" { funlockfile(data_make->error.to.stream); } - return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } } // for if (data_make->cache_arguments.used > 2) { // The last file must be a directory. - status = f_directory_is(data_make->cache_arguments.array[data_make->cache_arguments.used - 1]); + status_file = f_directory_is(data_make->cache_arguments.array[data_make->cache_arguments.used - 1]); - if (status == F_false || status == F_file_found_not) { + if (status_file == F_false || status_file == F_file_found_not) { if (data_make->error.verbosity != f_console_verbosity_quiet_e && data_make->error.to.stream) { flockfile(data_make->error.to.stream); @@ -767,24 +763,24 @@ extern "C" { funlockfile(data_make->error.to.stream); } - return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } - if (F_status_is_error(status)) { - fll_error_file_print(data_make->error, F_status_set_fine(status), "f_directory_is", F_true, data_make->cache_arguments.array[data_make->cache_arguments.used - 1], f_file_operation_identify_s, fll_error_file_type_directory_e); + if (F_status_is_error(status_file)) { + fll_error_file_print(data_make->error, F_status_set_fine(status_file), "f_directory_is", F_true, data_make->cache_arguments.array[data_make->cache_arguments.used - 1], f_file_operation_identify_s, fll_error_file_type_directory_e); - return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } } else { // When the first file is a directory, then the second, if it exists, must also be a directory. - status = f_directory_is(data_make->cache_arguments.array[0]); + status_file = f_directory_is(data_make->cache_arguments.array[0]); - if (status == F_true) { - status = f_directory_is(data_make->cache_arguments.array[1]); + if (status_file == F_true) { + status_file = f_directory_is(data_make->cache_arguments.array[1]); - if (status == F_false) { + if (status_file == F_false) { if (data_make->error.verbosity != f_console_verbosity_quiet_e && data_make->error.to.stream) { flockfile(data_make->error.to.stream); @@ -795,12 +791,12 @@ extern "C" { funlockfile(data_make->error.to.stream); } - return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } } } - return F_none; + return status; } fake_print_error_requires_more_arguments(data_make); @@ -1024,30 +1020,154 @@ extern "C" { #ifndef _di_fake_make_operate_validate_type_link_ f_status_t fake_make_operate_validate_type_link(fake_make_data_t * const data_make) { - if (data_make->cache_arguments.used > 2) { + if (data_make->cache_arguments.used > 4) { fake_print_error_too_many_arguments(data_make); return F_status_set_error(F_failure); } - if (data_make->cache_arguments.used == 2) { - f_status_t status = fake_make_assure_inside_project(data_make, data_make->cache_arguments.array[0]); + if (data_make->cache_arguments.used > 1) { + f_status_t status = F_none; + f_status_t status_file = F_none; - if (F_status_is_error(status)) { - fake_print_message_section_operation_path_outside(data_make->data, data_make->error, F_status_set_fine(status), "fake_make_assure_inside_project", data_make->cache_path.used ? data_make->cache_path : data_make->cache_arguments.array[0]); + // 0x1 = force, 0x2 = strict. + uint8_t flag = 0; + + if (data_make->cache_arguments.used > 2) { + if (fl_string_dynamic_compare(fake_make_operation_argument_force_s, data_make->cache_arguments.array[0]) == F_equal_to) { + flag |= 0x1; + } + else if (fl_string_dynamic_compare(fake_make_operation_argument_strict_s, data_make->cache_arguments.array[0]) == F_equal_to) { + flag |= 0x2; + } + else { + fake_print_message_section_operation_link_argument_unknown(data_make->data, data_make->error, data_make->cache_arguments.array[0]); - if (F_status_set_fine(status) == F_false) return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); + } + + if (data_make->cache_arguments.used > 3) { + if (fl_string_dynamic_compare(fake_make_operation_argument_force_s, data_make->cache_arguments.array[1]) == F_equal_to) { + flag |= 0x1; + } + else if (fl_string_dynamic_compare(fake_make_operation_argument_strict_s, data_make->cache_arguments.array[1]) == F_equal_to) { + flag |= 0x2; + } + else { + fake_print_message_section_operation_link_argument_unknown(data_make->data, data_make->error, data_make->cache_arguments.array[1]); + + status = F_status_set_error(F_failure); + } + } } - status = fake_make_assure_inside_project(data_make, data_make->cache_arguments.array[1]); + status_file = fake_make_assure_inside_project(data_make, data_make->cache_arguments.array[data_make->cache_arguments.used - 1]); - if (F_status_is_error(status)) { - fake_print_message_section_operation_path_outside(data_make->data, data_make->error, F_status_set_fine(status), "fake_make_assure_inside_project", data_make->cache_path.used ? data_make->cache_path : data_make->cache_arguments.array[1]); + if (F_status_is_error(status_file)) { + fake_print_message_section_operation_path_outside(data_make->data, data_make->error, F_status_set_fine(status_file), "fake_make_assure_inside_project", data_make->cache_path.used ? data_make->cache_path : data_make->cache_arguments.array[data_make->cache_arguments.used - 1]); - if (F_status_set_fine(status) == F_false) return F_status_set_error(F_failure); + status = F_status_set_error(F_failure); } + else { + if (!(flag & 0x1)) { + if (!data_make->cache_path.used || f_file_exists(data_make->cache_path, F_false) == F_true) { + fake_print_message_section_operation_link_point_exists(data_make->data, data_make->error, data_make->cache_arguments.array[data_make->cache_arguments.used - 1]); - return F_none; + status = F_status_set_error(F_failure); + } + } + + if (f_path_is_absolute(data_make->cache_arguments.array[data_make->cache_arguments.used - 2]) == F_true) { + status_file = fake_make_assure_inside_project(data_make, data_make->cache_arguments.array[data_make->cache_arguments.used - 2]); + + if (F_status_is_error(status_file)) { + fake_print_message_section_operation_path_outside(data_make->data, data_make->error, F_status_set_fine(status_file), "fake_make_assure_inside_project", data_make->cache_arguments.array[data_make->cache_arguments.used - 2]); + + status = F_status_set_error(F_failure); + } + + if ((flag & 0x2) && F_status_is_error_not(status_file)) { + if (f_file_exists(data_make->cache_arguments.array[data_make->cache_arguments.used - 2], F_false) != F_true) { + fake_print_message_section_operation_link_target_exists_not(data_make->data, data_make->error, data_make->cache_arguments.array[data_make->cache_arguments.used - 2]); + + status = F_status_set_error(F_failure); + } + } + } + + // The target path is relative to the point path so construct the path for performing checks. + else if (data_make->cache_arguments.array[data_make->cache_arguments.used - 2].used) { + + // The cache_path contains the full path to the point file, save this so that the cache_path can be re-used. + f_char_t full_string[data_make->cache_path.used + 1]; + f_string_static_t full = macro_f_string_static_t_initialize(full_string, 0, data_make->cache_path.used); + + memcpy(full_string, data_make->cache_path.string, sizeof(f_char_t) * data_make->cache_path.used); + full_string[data_make->cache_path.used] = 0; + + data_make->cache_path.used = 0; + + status_file = f_file_name_directory(full, &data_make->cache_path); + + if (F_status_is_error(status_file)) { + fll_error_file_print(data_make->error, F_status_set_fine(status_file), "f_file_name_directory", F_true, full, f_file_operation_analyze_s, fll_error_file_type_path_e); + + status = F_status_set_error(F_failure); + } + + if (F_status_is_error_not(status_file)) { + status_file = f_string_dynamic_append_assure(f_path_separator_s, &data_make->cache_path); + + if (F_status_is_error(status_file)) { + fll_error_print(data_make->error, F_status_set_fine(status_file), "f_string_dynamic_append_assure", F_true); + + status = F_status_set_error(F_failure); + } + else { + status_file = f_string_dynamic_append(data_make->cache_arguments.array[data_make->cache_arguments.used - 2], &data_make->cache_path); + + if (F_status_is_error(status_file)) { + fll_error_print(data_make->error, F_status_set_fine(status_file), "f_string_dynamic_append", F_true); + + status = F_status_set_error(F_failure); + } + } + + if (F_status_is_error_not(status_file)) { + + // The cache_path is used by fake_make_assure_inside_project(), so copy the contents into another buffer. + f_char_t target_string[data_make->cache_path.used + 1]; + f_string_static_t target = macro_f_string_static_t_initialize(target_string, 0, data_make->cache_path.used); + + memcpy(target_string, data_make->cache_path.string, sizeof(f_char_t) * data_make->cache_path.used); + target_string[data_make->cache_path.used] = 0; + + status_file = fake_make_assure_inside_project(data_make, target); + + if (F_status_is_error(status_file)) { + fake_print_message_section_operation_path_outside(data_make->data, data_make->error, F_status_set_fine(status_file), "fake_make_assure_inside_project", target); + + status = F_status_set_error(F_failure); + } + + if ((flag & 0x2) && F_status_is_error_not(status_file)) { + if (f_file_exists(target, F_false) != F_true) { + fake_print_message_section_operation_link_target_exists_not(data_make->data, data_make->error, target); + + status = F_status_set_error(F_failure); + } + } + } + } + } + else { + if (data_make->error.verbosity != f_console_verbosity_quiet_e && data_make->error.to.stream) { + fll_print_format("%r%[%QTarget filename argument must not be an empty string.%]%r", data_make->error.to.stream, f_string_eol_s, data_make->error.context, data_make->error.prefix, data_make->error.context, f_string_eol_s); + } + } + } + + return status; } fake_print_error_requires_more_arguments(data_make); diff --git a/level_3/fake/c/private-print.c b/level_3/fake/c/private-print.c index f682a57..57916b4 100644 --- a/level_3/fake/c/private-print.c +++ b/level_3/fake/c/private-print.c @@ -367,27 +367,79 @@ extern "C" { #ifndef _di_fake_print_message_section_operation_failed_ void fake_print_message_section_operation_failed(fake_data_t * const data, const fl_print_t print, const f_string_static_t buffer, const f_string_range_t section_name, const f_string_range_t operation_name) { - if (data->main->error.verbosity == f_console_verbosity_quiet_e || !print.to.stream) return; + if (print.verbosity == f_console_verbosity_quiet_e || !print.to.stream) return; f_array_length_t line = 1; f_state_t state = f_state_t_initialize; f_fss_count_lines(state, buffer, operation_name.start, &line); - flockfile(data->main->error.to.stream); + flockfile(print.to.stream); - fl_print_format("%r%[%QThe section operation '%]", data->main->error.to.stream, f_string_eol_s, data->main->error.context, data->main->error.prefix, data->main->error.context); - fl_print_format("%[%/Q%]", data->main->error.to.stream, data->main->error.notable, buffer, operation_name, data->main->error.notable); - fl_print_format("%[' from section '%]", data->main->error.to.stream, data->main->error.context, data->main->error.context); - fl_print_format("%[%/Q%]", data->main->error.to.stream, data->main->error.notable, buffer, section_name, data->main->error.notable); - fl_print_format("%[' on line%] ", data->main->error.to.stream, data->main->error.context, data->main->error.context); - fl_print_format("%[%un%]", data->main->error.to.stream, data->main->error.notable, line, data->main->error.notable); - fl_print_format(" %[failed.%]%r", data->main->error.to.stream, data->main->error.context, data->main->error.context, f_string_eol_s); + fl_print_format("%r%[%QThe section operation '%]", print.to.stream, f_string_eol_s, print.context, print.prefix, print.context); + fl_print_format("%[%/Q%]", print.to.stream, print.notable, buffer, operation_name, print.notable); + fl_print_format("%[' from section '%]", print.to.stream, print.context, print.context); + fl_print_format("%[%/Q%]", print.to.stream, print.notable, buffer, section_name, print.notable); + fl_print_format("%[' on line%] ", print.to.stream, print.context, print.context); + fl_print_format("%[%un%]", print.to.stream, print.notable, line, print.notable); + fl_print_format(" %[failed.%]%r", print.to.stream, print.context, print.context, f_string_eol_s); - funlockfile(data->main->error.to.stream); + funlockfile(print.to.stream); } #endif // _di_fake_print_message_section_operation_failed_ +#ifndef _di_fake_print_message_section_operation_link_argument_unknown_ + void fake_print_message_section_operation_link_argument_unknown(fake_data_t * const data, const fl_print_t print, const f_string_static_t argument) { + + if (print.verbosity == f_console_verbosity_quiet_e || !print.to.stream) return; + + flockfile(print.to.stream); + + fl_print_format("%r%[%QThe argument '%]", print.to.stream, f_string_eol_s, print.context, print.prefix, print.context); + fl_print_format("%[%Q%]", print.to.stream, print.notable, argument, print.notable); + fl_print_format("%[' is not not valid and may only be one of either '%]", print.to.stream, print.context, print.context); + fl_print_format("%[%r%]", print.to.stream, print.notable, fake_make_operation_argument_force_s, print.notable); + fl_print_format("%[' or '%]", print.to.stream, print.context, print.context); + fl_print_format("%[%r%]", print.to.stream, print.notable, fake_make_operation_argument_strict_s, print.notable); + fl_print_format("%['.%]%r", print.to.stream, print.context, print.context, f_string_eol_s); + + funlockfile(print.to.stream); + + } +#endif // _di_fake_print_message_section_operation_link_argument_unknown_ + +#ifndef _di_fake_print_message_section_operation_link_point_exists_ + void fake_print_message_section_operation_link_point_exists(fake_data_t * const data, const fl_print_t print, const f_string_static_t argument) { + + if (print.verbosity == f_console_verbosity_quiet_e || !print.to.stream) return; + + flockfile(print.to.stream); + + fl_print_format("%r%[%QThe point file '%]", print.to.stream, f_string_eol_s, print.context, print.prefix, print.context); + fl_print_format("%[%Q%]", print.to.stream, print.notable, argument, print.notable); + fl_print_format("%[' already exists.%]%r", print.to.stream, print.context, print.context, f_string_eol_s); + + funlockfile(print.to.stream); + + } +#endif // _di_fake_print_message_section_operation_link_point_exists_ + +#ifndef _di_fake_print_message_section_operation_link_target_exists_not_ + void fake_print_message_section_operation_link_target_exists_not(fake_data_t * const data, const fl_print_t print, const f_string_static_t argument) { + + if (print.verbosity == f_console_verbosity_quiet_e || !print.to.stream) return; + + flockfile(print.to.stream); + + fl_print_format("%r%[%QThe target file '%]", print.to.stream, f_string_eol_s, print.context, print.prefix, print.context); + fl_print_format("%[%Q%]", print.to.stream, print.notable, argument, print.notable); + fl_print_format("%[' does not exist.%]%r", print.to.stream, print.context, print.context, f_string_eol_s); + + funlockfile(print.to.stream); + + } +#endif // _di_fake_print_message_section_operation_link_target_exists_not_ + #ifndef _di_fake_print_message_section_operation_path_outside_ void fake_print_message_section_operation_path_outside(fake_data_t * const data, const fl_print_t print, const f_status_t status, const char *function, const f_string_static_t path) { diff --git a/level_3/fake/c/private-print.h b/level_3/fake/c/private-print.h index 931d9be..3f84b44 100644 --- a/level_3/fake/c/private-print.h +++ b/level_3/fake/c/private-print.h @@ -198,6 +198,63 @@ extern "C" { #endif // _di_fake_print_message_section_operation_failed_ /** + * Print error messages when a given link argument is unknown. + * + * @param data + * The program data. + * @param print + * Designates how the section error/warning should be printed. + * @param argument + * The argument that is unknown by the link operation. + * + * @see flockfile() + * @see funlockfile() + * + * @see fl_print_format() + */ +#ifndef _di_fake_print_message_section_operation_link_argument_unknown_ + extern void fake_print_message_section_operation_link_argument_unknown(fake_data_t * const data, const fl_print_t print, const f_string_static_t argument) F_attribute_visibility_internal_d; +#endif // _di_fake_print_message_section_operation_link_argument_unknown_ + +/** + * Print error messages when a given link point file already exists. + * + * @param data + * The program data. + * @param print + * Designates how the section error/warning should be printed. + * @param argument + * The argument representing the point file. + * + * @see flockfile() + * @see funlockfile() + * + * @see fl_print_format() + */ +#ifndef _di_fake_print_message_section_operation_link_point_exists_ + extern void fake_print_message_section_operation_link_point_exists(fake_data_t * const data, const fl_print_t print, const f_string_static_t argument) F_attribute_visibility_internal_d; +#endif // _di_fake_print_message_section_operation_link_point_exists_ + +/** + * Print error messages when a given link target file does not already exist. + * + * @param data + * The program data. + * @param print + * Designates how the section error/warning should be printed. + * @param argument + * The argument representing the point file. + * + * @see flockfile() + * @see funlockfile() + * + * @see fl_print_format() + */ +#ifndef _di_fake_print_message_section_operation_link_target_exists_not_ + extern void fake_print_message_section_operation_link_target_exists_not(fake_data_t * const data, const fl_print_t print, const f_string_static_t argument) F_attribute_visibility_internal_d; +#endif // _di_fake_print_message_section_operation_link_target_exists_not_ + +/** * Print error messages when processing some fakefile section, for a specific line and operation, and that operation has a path outside of the project root. * * @param data diff --git a/level_3/fake/documents/fakefile.txt b/level_3/fake/documents/fakefile.txt index 53e0b76..eb220fb 100644 --- a/level_3/fake/documents/fakefile.txt +++ b/level_3/fake/documents/fakefile.txt @@ -337,8 +337,12 @@ Fakefile Documentation: - link\: Create a symbolic link from some point to some target. - The first Content represents the target file. - The second Content represents the point file. + The first Content, when there are more than 2 arguments, may be either "force" or "strict". + The second to last Content represents the target file. + The last Content represents the point file. + + The "force" Content designates that the point file will be overwritten if the file already exists. + The "strict" Content requires that the target file already exists. - mode\: Change the mode permissions for a given file. diff --git a/level_3/fake/specifications/fakefile.txt b/level_3/fake/specifications/fakefile.txt index 5f2bd88..eb2d3e5 100644 --- a/level_3/fake/specifications/fakefile.txt +++ b/level_3/fake/specifications/fakefile.txt @@ -59,7 +59,7 @@ Fakefile Specification: - groups: Two or more Content. First Content is group name, number, or "no_dereference" (when "no_dereference", then the second Content is the group name or number, etc..), remaining Content are paths to files. - if: One or more Content. First Content is the condition or is "no_dereference" (when "no_dereference", then the Second Content is the condition, etc..), remaining Content are specific to the condition. - index: One or more Content. - - link: Two Content. First Content is the link target file and second Content is the pointer file (the link). + - link: Two to Four Content. The first and second Content may be either "force" or "strict", the second to last Content is the link target file, and the last Content is the pointer file (the link). - mode: Two or more Content. First Content is the mode, remaining Content are paths to files. - modes: Two or more Content. First Content is the mode, remaining Content are paths to files. - move: Two or more Content representing paths to files. -- 1.8.3.1