From 63223ea28152b4b70cb0319c09e338f0b4d935d8 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Wed, 19 Aug 2020 21:59:55 -0500 Subject: [PATCH] Progress: featureless make. Remove the 'create' section operation, it is effectively redundant with the 'touch' section operation. There is still potential for having both because 'touch' section operation has additional actions that could be undesired. For keeping it simple, I have decided to not support both 'create' and 'touch' at the same time. Implement 'delete' section operatin and update validation. Implement 'link' section operation and update validation. Add 'deletes' section operation that performs a "recursive" delete which allows for deleting non-empty directories. --- level_3/fake/c/private-make.c | 259 +++++++++++++++---------------- level_3/fake/c/private-make.h | 7 +- level_3/fake/c/private-print.c | 11 ++ level_3/fake/documents/fakefile.txt | 26 +--- level_3/fake/specifications/fakefile.txt | 4 +- 5 files changed, 148 insertions(+), 159 deletions(-) diff --git a/level_3/fake/c/private-make.c b/level_3/fake/c/private-make.c index a1f78d1..4c2c5f1 100644 --- a/level_3/fake/c/private-make.c +++ b/level_3/fake/c/private-make.c @@ -1305,9 +1305,9 @@ extern "C" { f_macro_string_static_initialize(fake_make_operation_build, fake_make_operation_build_length), f_macro_string_static_initialize(fake_make_operation_clean, fake_make_operation_clean_length), f_macro_string_static_initialize(fake_make_operation_compile, fake_make_operation_compile_length), - f_macro_string_static_initialize(fake_make_operation_create, fake_make_operation_create_length), f_macro_string_static_initialize(fake_make_operation_define, fake_make_operation_define_length), f_macro_string_static_initialize(fake_make_operation_delete, fake_make_operation_delete_length), + f_macro_string_static_initialize(fake_make_operation_deletes, fake_make_operation_deletes_length), f_macro_string_static_initialize(fake_make_operation_else, fake_make_operation_else_length), f_macro_string_static_initialize(fake_make_operation_fail, fake_make_operation_fail_length), f_macro_string_static_initialize(fake_make_operation_group, fake_make_operation_group_length), @@ -1334,9 +1334,9 @@ extern "C" { f_macro_string_range_initialize(fake_make_operation_build_length), f_macro_string_range_initialize(fake_make_operation_clean_length), f_macro_string_range_initialize(fake_make_operation_compile_length), - f_macro_string_range_initialize(fake_make_operation_create_length), f_macro_string_range_initialize(fake_make_operation_define_length), f_macro_string_range_initialize(fake_make_operation_delete_length), + f_macro_string_range_initialize(fake_make_operation_deletes_length), f_macro_string_range_initialize(fake_make_operation_else_length), f_macro_string_range_initialize(fake_make_operation_fail_length), f_macro_string_range_initialize(fake_make_operation_group_length), @@ -1363,9 +1363,9 @@ extern "C" { fake_make_operation_type_build, fake_make_operation_type_clean, fake_make_operation_type_compile, - fake_make_operation_type_create, fake_make_operation_type_define, fake_make_operation_type_delete, + fake_make_operation_type_deletes, fake_make_operation_type_else, fake_make_operation_type_fail, fake_make_operation_type_group, @@ -1535,24 +1535,73 @@ extern "C" { return; } - if (operation == fake_make_operation_type_create) { - // fake_make_assure_inside_project - // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments); - //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status); - //fake_execute(data, data_make->environment, data_build.setting.build_compiler, arguments, status); - return; - } - if (operation == fake_make_operation_type_define) { // @todo: walk through each existing define to see if it already exists and replace it, otherwise create a new one. return; } - if (operation == fake_make_operation_type_delete) { - // fake_make_assure_inside_project - // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments); - //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status); - //fake_execute(data, data_make->environment, data_build.setting.build_compiler, arguments, status); + if (operation == fake_make_operation_type_delete || operation == fake_make_operation_type_deletes) { + const int recursion_max = operation == fake_make_operation_type_delete ? 0 : f_directory_descriptors_max; + struct stat file_stat; + + for (f_array_length i = 0; i < arguments.used; i++) { + memset(&file_stat, 0, sizeof(struct stat)); + + *status = f_file_stat(arguments.array[i].string, F_false, &file_stat); + + if (F_status_is_error(*status)) { + if (F_status_set_fine(*status) == F_file_found_not) { + if (data.verbosity == fake_verbosity_verbose) { + fprintf(f_type_warning, "%c", f_string_eol[0]); + fl_color_print(f_type_warning, data.context.warning, data.context.reset, "WARNING: the file '"); + fl_color_print(f_type_warning, data.context.notable, data.context.reset, "%s", arguments.array[i].string); + fl_color_print_line(f_type_warning, data.context.warning, data.context.reset, "' was not found."); + } + + *status = F_none; + } + else { + fake_print_error_file(data, F_status_set_fine(*status), "f_file_stat", arguments.array[i].string, "delete", F_true, F_true); + return; + } + } + else if (f_macro_file_type_is_directory(file_stat.st_mode)) { + if (data.verbosity == fake_verbosity_verbose) { + *status = f_directory_remove_custom(arguments.array[i].string, recursion_max, F_false, fake_clean_remove_recursively_verbosely); + } + else { + *status = f_directory_remove(arguments.array[i].string, recursion_max, F_false); + } + + if (F_status_set_fine(*status) == F_file_found_not) { + if (data.verbosity == fake_verbosity_verbose) { + printf("The directory '%s' does not exist.%c", arguments.array[i].string, f_string_eol[0]); + } + + *status = F_none; + } + + if (F_status_is_error(*status)) { + fake_print_error_file(data, F_status_set_fine(*status), "f_directory_remove", arguments.array[i].string, "delete", F_false, F_true); + return; + } + else { + printf("Removed '%s'.\n", arguments.array[i].string); + } + } + else { + *status = f_file_remove(arguments.array[i].string); + + if (F_status_is_error(*status)) { + fake_print_error_file(data, F_status_set_fine(*status), "f_file_remove", arguments.array[i].string, "delete", F_true, F_true); + return; + } + else { + printf("Removed '%s'.\n", arguments.array[i].string); + } + } + } // for + return; } @@ -1573,6 +1622,7 @@ extern "C" { for (f_array_length i = 1; i < arguments.used; i++) { *status = f_file_role_change(arguments.array[i].string, -1, id, F_false); + if (F_status_is_error(*status)) { fake_print_error_file(data, *status, "f_file_role_change", arguments.array[i].string, "change group of", F_true, F_true); } @@ -1590,6 +1640,7 @@ extern "C" { for (f_array_length i = 1; i < arguments.used; i++) { // @todo: recursive. *status = f_file_role_change(arguments.array[i].string, -1, id, F_false); + if (F_status_is_error(*status)) { fake_print_error_file(data, *status, "f_file_role_change", arguments.array[i].string, "change group of", F_true, F_true); } @@ -1604,8 +1655,12 @@ extern "C" { } if (operation == fake_make_operation_type_link) { - // fake_make_assure_inside_project - // @todo: create symlink. + *status = f_file_link(arguments.array[0].string, arguments.array[1].string); + + if (F_status_is_error(*status)) { + fake_print_error_file(data, *status, "f_file_link", arguments.array[1].string, "create link", F_true, F_true); + } + return; } @@ -1881,40 +1936,42 @@ extern "C" { f_macro_mode_set_default_umask(mode, data.umask); - if (data.verbosity == fake_verbosity_verbose) { - printf("Touching %s '", arguments.array[0].string); - fl_color_print(f_type_output, data.context.notable, data.context.reset, "%s", arguments.array[1].string); - printf("'.%c", f_string_eol[0]); - } + for (f_array_length i = 1; i < arguments.used; i++) { + if (data.verbosity == fake_verbosity_verbose) { + printf("Touching %s '", arguments.array[0].string); + fl_color_print(f_type_output, data.context.notable, data.context.reset, "%s", arguments.array[i].string); + printf("'.%c", f_string_eol[0]); + } - if (fl_string_dynamic_compare_string(fake_make_operation_argument_file, arguments.array[0], fake_make_operation_argument_file_length) == F_equal_to) { - *status = f_file_touch(arguments.array[1].string, mode.regular, F_false); + if (fl_string_dynamic_compare_string(fake_make_operation_argument_file, arguments.array[0], fake_make_operation_argument_file_length) == F_equal_to) { + *status = f_file_touch(arguments.array[i].string, mode.regular, F_false); - if (F_status_is_error(*status)) { - if (F_status_is_fine(fll_path_canonical(arguments.array[1].string, &data_make->path_cache))) { - fake_print_error_file(data, F_status_set_fine(*status), "f_file_touch", data_make->path_cache.string, "touch", F_true, F_true); - } - else { - fake_print_error_file(data, F_status_set_fine(*status), "f_file_touch", arguments.array[1].string, "touch", F_true, F_true); - } + if (F_status_is_error(*status)) { + if (F_status_is_fine(fll_path_canonical(arguments.array[i].string, &data_make->path_cache))) { + fake_print_error_file(data, F_status_set_fine(*status), "f_file_touch", data_make->path_cache.string, "touch", F_true, F_true); + } + else { + fake_print_error_file(data, F_status_set_fine(*status), "f_file_touch", arguments.array[i].string, "touch", F_true, F_true); + } - return; + return; + } } - } - else if (fl_string_dynamic_compare_string(fake_make_operation_argument_directory, arguments.array[0], fake_make_operation_argument_directory_length) == F_equal_to) { - *status = f_directory_touch(arguments.array[1].string, mode.directory); + else if (fl_string_dynamic_compare_string(fake_make_operation_argument_directory, arguments.array[0], fake_make_operation_argument_directory_length) == F_equal_to) { + *status = f_directory_touch(arguments.array[i].string, mode.directory); - if (F_status_is_error(*status)) { - if (F_status_is_fine(fll_path_canonical(arguments.array[1].string, &data_make->path_cache))) { - fake_print_error_file(data, F_status_set_fine(*status), "f_directory_touch", data_make->path_cache.string, "touch", F_false, F_true); - } - else { - fake_print_error_file(data, F_status_set_fine(*status), "f_directory_touch", arguments.array[1].string, "touch", F_false, F_true); - } + if (F_status_is_error(*status)) { + if (F_status_is_fine(fll_path_canonical(arguments.array[i].string, &data_make->path_cache))) { + fake_print_error_file(data, F_status_set_fine(*status), "f_directory_touch", data_make->path_cache.string, "touch", F_false, F_true); + } + else { + fake_print_error_file(data, F_status_set_fine(*status), "f_directory_touch", arguments.array[i].string, "touch", F_false, F_true); + } - return; + return; + } } - } + } // for return; } @@ -2166,42 +2223,19 @@ extern "C" { *status = F_status_set_error(F_failure); } } - else if (operation == fake_make_operation_type_create || operation == fake_make_operation_type_delete) { + else if (operation == fake_make_operation_type_delete || operation == fake_make_operation_type_deletes) { if (arguments.used) { - if (fl_string_dynamic_compare_string(fake_make_operation_argument_file, arguments.array[0], fake_make_operation_argument_file_length) == F_equal_to) { - if (arguments.used > 2) { - printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_error, data.context.error, data.context.reset, "ERROR: Has too many arguments."); - - *status = F_status_set_error(F_failure); - } - } - else if (fl_string_dynamic_compare_string(fake_make_operation_argument_directory, arguments.array[0], fake_make_operation_argument_directory_length) == F_equal_to) { - if (arguments.used > 3) { - printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_error, data.context.error, data.context.reset, "ERROR: Has too many arguments."); + for (f_array_length i = 0; i < arguments.used; i++) { + *status = fake_make_assure_inside_project(data, arguments.array[i], data_make); - *status = F_status_set_error(F_failure); - } - else if (arguments.used == 3) { - if (fl_string_dynamic_compare_string(fake_make_operation_argument_recursive, arguments.array[0], fake_make_operation_argument_recursive_length) == F_equal_to_not) { - printf("%c", f_string_eol[0]); - fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Third argument must be either '"); - fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", fake_make_operation_argument_recursive); - fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' or not provided at all."); + if (F_status_is_error(*status)) { + fake_print_error_fakefile_section_operation_path_outside(data, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string); + if (F_status_set_fine(*status) == F_false) { *status = F_status_set_error(F_failure); } } - } - else { - printf("%c", f_string_eol[0]); - fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Unsupported file type '"); - fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", arguments.array[0].string); - fl_color_print_line(f_type_error, data.context.error, data.context.reset, "'."); - - *status = F_status_set_error(F_failure); - } + } // for } else { printf("%c", f_string_eol[0]); @@ -2295,7 +2329,6 @@ extern "C" { } } else if (operation == fake_make_operation_type_link) { - // @todo validate link is outside that the link is or is not outside the project directory. if (arguments.used > 2) { printf("%c", f_string_eol[0]); fl_color_print_line(f_type_error, data.context.error, data.context.reset, "ERROR: Has too many arguments."); @@ -2303,55 +2336,23 @@ extern "C" { *status = F_status_set_error(F_failure); } else if (arguments.used == 2) { - f_status status_file = F_none; - - if (arguments.array[0].used) { - status_file = f_file_exists(arguments.array[0].string); - - if (F_status_is_error(status_file) || !status_file) { - printf("%c", f_string_eol[0]); - fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Failed to find file '"); - fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", arguments.array[0].string); - fl_color_print_line(f_type_error, data.context.error, data.context.reset, "'."); + *status = fake_make_assure_inside_project(data, arguments.array[0], data_make); + if (F_status_is_error(*status)) { + fake_print_error_fakefile_section_operation_path_outside(data, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[0].string); - if (status_file == F_false) { - *status = F_status_set_error(F_failure); - } - else { - *status = status_file; - } + if (F_status_set_fine(*status) == F_false) { + *status = F_status_set_error(F_failure); } } - else { - printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_error, data.context.error, data.context.reset, "ERROR: The %s filename argument must not be an empty string.", fake_make_operation_argument_target); - *status = F_status_set_error(F_failure); - } - - if (arguments.array[1].used) { - status_file = f_file_exists(arguments.array[1].string); - - if (F_status_is_error(status_file) || !status_file) { - printf("%c", f_string_eol[0]); - fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Failed to find file '"); - fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", arguments.array[1].string); - fl_color_print_line(f_type_error, data.context.error, data.context.reset, "'."); + *status = fake_make_assure_inside_project(data, arguments.array[1], data_make); + if (F_status_is_error(*status)) { + fake_print_error_fakefile_section_operation_path_outside(data, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[1].string); - if (status_file == F_false) { - *status = F_status_set_error(F_failure); - } - else { - *status = status_file; - } + if (F_status_set_fine(*status) == F_false) { + *status = F_status_set_error(F_failure); } } - else { - printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_error, data.context.error, data.context.reset, "ERROR: Filename argument must not be an empty string.", fake_make_operation_argument_point); - - *status = F_status_set_error(F_failure); - } } else { printf("%c", f_string_eol[0]); @@ -2410,13 +2411,7 @@ extern "C" { } } else if (operation == fake_make_operation_type_touch) { - if (arguments.used > 2) { - printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_error, data.context.error, data.context.reset, "ERROR: Has too many arguments."); - - *status = F_status_set_error(F_failure); - } - else if (arguments.used == 2) { + if (arguments.used > 1) { if (fl_string_dynamic_compare_string(fake_make_operation_argument_file, arguments.array[0], fake_make_operation_argument_file_length) == F_equal_to_not) { if (fl_string_dynamic_compare_string(fake_make_operation_argument_directory, arguments.array[0], fake_make_operation_argument_directory_length) == F_equal_to_not) { printf("%c", f_string_eol[0]); @@ -2428,14 +2423,16 @@ extern "C" { } } - *status = fake_make_assure_inside_project(data, arguments.array[1], data_make); - if (F_status_is_error(*status)) { - fake_print_error_fakefile_section_operation_path_outside(data, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[1].string); + for (f_array_length i = 1; i < arguments.used; i++) { + *status = fake_make_assure_inside_project(data, arguments.array[i], data_make); + if (F_status_is_error(*status)) { + fake_print_error_fakefile_section_operation_path_outside(data, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string); - if (F_status_set_fine(*status) == F_false) { - *status = F_status_set_error(F_failure); + if (F_status_set_fine(*status) == F_false) { + *status = F_status_set_error(F_failure); + } } - } + } // for } else { printf("%c", f_string_eol[0]); diff --git a/level_3/fake/c/private-make.h b/level_3/fake/c/private-make.h index 495f734..a56ecdf 100644 --- a/level_3/fake/c/private-make.h +++ b/level_3/fake/c/private-make.h @@ -22,7 +22,6 @@ extern "C" { #define fake_make_section_stack_max 8192 // maximum stack call depth. #endif // _di_fake_make_section_ -// @todo safety checks that ensures operations on files only happen inside the project directory, represented by "top". #ifndef _di_fake_make_setting_ typedef struct { bool load_build; @@ -64,9 +63,9 @@ extern "C" { #define fake_make_operation_build "build" #define fake_make_operation_clean "clean" #define fake_make_operation_compile "compile" - #define fake_make_operation_create "create" #define fake_make_operation_define "define" #define fake_make_operation_delete "delete" + #define fake_make_operation_deletes "deletes" #define fake_make_operation_else "else" #define fake_make_operation_fail "fail" #define fake_make_operation_group "group" @@ -91,9 +90,9 @@ extern "C" { #define fake_make_operation_build_length 5 #define fake_make_operation_clean_length 5 #define fake_make_operation_compile_length 7 - #define fake_make_operation_create_length 6 #define fake_make_operation_define_length 6 #define fake_make_operation_delete_length 6 + #define fake_make_operation_deletes_length 7 #define fake_make_operation_else_length 4 #define fake_make_operation_fail_length 4 #define fake_make_operation_group_length 5 @@ -119,9 +118,9 @@ extern "C" { fake_make_operation_type_build, fake_make_operation_type_clean, fake_make_operation_type_compile, - fake_make_operation_type_create, fake_make_operation_type_define, fake_make_operation_type_delete, + fake_make_operation_type_deletes, fake_make_operation_type_else, fake_make_operation_type_fail, fake_make_operation_type_group, diff --git a/level_3/fake/c/private-print.c b/level_3/fake/c/private-print.c index 0a420fa..8cca889 100644 --- a/level_3/fake/c/private-print.c +++ b/level_3/fake/c/private-print.c @@ -463,6 +463,17 @@ extern "C" { return F_false; } + if (status == F_directory_empty_not) { + if (data.verbosity != fake_verbosity_quiet) { + fprintf(f_type_error, "%c", f_string_eol[0]); + fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: The %s '", file_or_directory); + fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", name); + fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' is not empty."); + } + + return F_false; + } + if (status == F_parameter) { if (data.verbosity != fake_verbosity_quiet) { fprintf(f_type_error, "%c", f_string_eol[0]); diff --git a/level_3/fake/documents/fakefile.txt b/level_3/fake/documents/fakefile.txt index 3ba3dd5..2837b4d 100644 --- a/level_3/fake/documents/fakefile.txt +++ b/level_3/fake/documents/fakefile.txt @@ -75,36 +75,20 @@ Fakefile Documentation: All Content are passed as arguments to the respective "gcc" program. - - create\: - Create a file or directory. - - The first Content must be either "file" or "directory". - Use "file" to designate that this is a regular file being created. - Use "directory" to designate that this is a directory file being created. - - The second Content must be the file to be created (be it a regular "file" or a "directory" file). - - - creates\: - Identical to "create", except that this will create all directories specified in the given directory file path. - - define\: This represents an environment variable to define on run. The environment variable name is case-sensitive. This replaces the value of any existing environment variable with this name. - delete\: - Delete a file or directory. - - The first Content must be either "file" or "directory". - Use "file" to designate that this is a regular file being deleted. - The "directory" to designate that this is a directory file being deleted. + Delete one or more files or directories. - The second Content must be the file to be deleted. + All Content must be the file or directory to be deleted. - When the first content is "directory" and that directory is not empty, then this will not delete the directory. + If the path is a directory and is not empty, then this will not delete the directory. - deletes\: - Identical to "delete", except that when the first content is "directory" and that directory is not empty, then this will delete the directory. + Identical to "delete", except that when the path is a directory and is not empty, then this will delete the directory. - else\: Performs a programmatic "else" condition. @@ -226,4 +210,4 @@ Fakefile Documentation: Manually create a new file or a directory within the project root or update its last changed timestamp if the file already exists. The first Content must be either "file" or "directory". - The second Content must be the file name. + The remaining Content must be a path to the file. diff --git a/level_3/fake/specifications/fakefile.txt b/level_3/fake/specifications/fakefile.txt index 328306f..7221d47 100644 --- a/level_3/fake/specifications/fakefile.txt +++ b/level_3/fake/specifications/fakefile.txt @@ -47,8 +47,6 @@ Fakefile Specification: - build: Zero or One Content. First Content represents path to the settings file, relative to the project root. - clean: Zero Content. - compile: One or more Content as parameters to compiler. - - create: Two Content. First Content is either "file" or "directory" (case-sensitive), second Content is path to file. - - creates: Two Content. First Content is either "file" or "directory" (case-sensitive), second Content is path to file. - define: Two or more Content. - delete: One or more Content representing paths to files. - deletes: One or more Content representing paths to files. @@ -70,4 +68,4 @@ Fakefile Specification: - skeleton: Zero Content. - to: One Content. First Content is the directory path. - top: Zero Content. - - touch: One Content. First Content is the file path. + - touch: Two or more Content. First content is one of "file" or "directory", remaining Content are paths to files. -- 1.8.3.1