From c06221052011f76fcbeec325bb2f4f5b6a6429b2 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Wed, 15 Jul 2020 22:32:29 -0500 Subject: [PATCH] Progress: featureless make. Remove the custom color toggler based on verbosity because I changed my mind. Allow assigning define as a fakefile operation. Begin stubbing out the operations. Implement the operations that can easily be implemented. Documentation updates. --- level_3/fake/c/fake.c | 10 - level_3/fake/c/fake.h | 5 - level_3/fake/c/private-build.c | 16 +- level_3/fake/c/private-clean.c | 4 +- level_3/fake/c/private-make.c | 384 +++++++++++++++++++++++++++---- level_3/fake/c/private-make.h | 105 ++++++--- level_3/fake/c/private-print.c | 31 ++- level_3/fake/c/private-print.h | 18 ++ level_3/fake/c/private-skeleton.c | 2 +- level_3/fake/data/build/fakefile | 60 ++--- level_3/fake/documents/fakefile.txt | 36 ++- level_3/fake/specifications/fakefile.txt | 22 +- 12 files changed, 533 insertions(+), 160 deletions(-) diff --git a/level_3/fake/c/fake.c b/level_3/fake/c/fake.c index 2cc468b..dc4687a 100644 --- a/level_3/fake/c/fake.c +++ b/level_3/fake/c/fake.c @@ -127,9 +127,6 @@ extern "C" { } else if (choice == fake_parameter_verbose) { data->verbosity = fake_verbosity_verbose; - - data->color_section_set = data->context.important; - data->color_section_reset = data->context.reset; } else if (choice == fake_parameter_debug) { data->verbosity = fake_verbosity_debug; @@ -308,13 +305,6 @@ extern "C" { if (F_status_is_not_error(status)) { status = fake_make_operate(*data); } - - /*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 operation '"); - fl_color_print(f_type_error, data->context.notable, data->context.reset, "%s", fake_other_operation_make); - fl_color_print_line(f_type_error, data->context.error, data->context.reset, "' is not yet implemented."); - }*/ } else if (operations[i] == fake_operation_skeleton) { status = fake_skeleton_operate(*data); diff --git a/level_3/fake/c/fake.h b/level_3/fake/c/fake.h index aa89cee..99f12d6 100644 --- a/level_3/fake/c/fake.h +++ b/level_3/fake/c/fake.h @@ -375,9 +375,6 @@ extern "C" { uint8_t operation; uint8_t verbosity; - f_string_static color_section_set; - f_string_static color_section_reset; - f_string_dynamics define; f_string_dynamics mode; f_string_dynamic process; @@ -441,8 +438,6 @@ extern "C" { 0, \ 0, \ fake_verbosity_normal, \ - f_string_static_initialize, \ - f_string_static_initialize, \ f_string_dynamics_initialize, \ f_string_dynamics_initialize, \ f_string_dynamic_initialize, \ diff --git a/level_3/fake/c/private-build.c b/level_3/fake/c/private-build.c index 566e357..5f653de 100644 --- a/level_3/fake/c/private-build.c +++ b/level_3/fake/c/private-build.c @@ -199,7 +199,7 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Copying %s.", label); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Copying %s.", label); } f_macro_string_dynamic_new(*status, path_source, source.used); @@ -386,7 +386,7 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Creating base build directories."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Creating base build directories."); } for (uint8_t i = 0; i < 15; i++) { @@ -670,7 +670,7 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Compiling shared library."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Compiling shared library."); } f_string_dynamics arguments = f_string_dynamics_initialize; @@ -957,7 +957,7 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Compiling static library."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Compiling static library."); } f_string_dynamic file_name = f_string_dynamic_initialize; @@ -2113,7 +2113,7 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Compiling static objects."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Compiling static objects."); } f_string_dynamic file_name = f_string_dynamic_initialize; @@ -2283,7 +2283,7 @@ extern "C" { f_return_status fake_build_operate(const fake_data data) { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Building project."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Building project."); } f_status status = F_none; @@ -2396,7 +2396,7 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Compiling shared program."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Compiling shared program."); } f_string_dynamics arguments = f_string_dynamics_initialize; @@ -2488,7 +2488,7 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Compiling static program."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Compiling static program."); } f_string_dynamics arguments = f_string_dynamics_initialize; diff --git a/level_3/fake/c/private-clean.c b/level_3/fake/c/private-clean.c index a369658..de14814 100644 --- a/level_3/fake/c/private-clean.c +++ b/level_3/fake/c/private-clean.c @@ -13,9 +13,9 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print(f_type_output, data.color_section_set, data.color_section_reset, "Deleting all files within build directory '"); + fl_color_print(f_type_output, data.context.important, data.context.reset, "Deleting all files within build directory '"); fl_color_print(f_type_output, data.context.notable, data.context.reset, "%s", data.path_build.string); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "'."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "'."); } if (data.verbosity == fake_verbosity_verbose) { diff --git a/level_3/fake/c/private-make.c b/level_3/fake/c/private-make.c index c86b2da..1dc47cc 100644 --- a/level_3/fake/c/private-make.c +++ b/level_3/fake/c/private-make.c @@ -138,38 +138,106 @@ extern "C" { return; } - data_make->setting_make.load_build = F_true; + // always have the parameter variable "return" map at index 0 and pre-initialized. + { + f_string function_name = "f_macro_string_map_multis_new"; - if (settings.objects.used) { - // look for load_build to determine if settings from the build settings file should be loaded. - const f_string_range range_load_build = f_macro_string_range_initialize(fake_make_setting_load_build_length); + f_macro_string_map_multis_new(*status, data_make->setting_make.parameter, f_memory_default_allocation_step); + + if (F_status_is_fine(*status)) { + data_make->setting_make.parameter.used = 1; + + function_name = "fl_string_append"; + *status = fl_string_append(fake_make_setting_return, fake_make_setting_return_length, &data_make->setting_make.parameter.array[0].name); + } - const f_string_range range_yes = f_macro_string_range_initialize(fake_common_setting_bool_yes_length); - const f_string_range range_no = f_macro_string_range_initialize(fake_common_setting_bool_no_length); + if (F_status_is_fine(*status)) { + function_name = "fl_string_dynamic_terminate_after"; + *status = fl_string_dynamic_terminate_after(&data_make->setting_make.parameter.array[0].name); + } + + if (F_status_is_fine(*status)) { + function_name = "f_macro_string_dynamics_new"; + f_macro_string_dynamics_new(*status, data_make->setting_make.parameter.array[0].value, 1); + } - const f_string_static name_settings_load_build = f_macro_string_static_initialize(fake_make_setting_load_build, fake_make_setting_load_build_length); - const f_string_static value_settings_load_build_yes = f_macro_string_static_initialize(fake_common_setting_bool_yes, fake_common_setting_bool_yes_length); - const f_string_static value_settings_load_build_no = f_macro_string_static_initialize(fake_common_setting_bool_no, fake_common_setting_bool_no_length); + if (F_status_is_fine(*status)) { + function_name = "fl_string_dynamic_terminate_after"; + *status = fl_string_dynamic_terminate_after(&data_make->setting_make.parameter.array[0].value.array[0]); + } + + if (F_status_is_error(*status)) { + fake_print_error(data.context, data.verbosity, *status, function_name, F_true); + + f_macro_fss_set_delete_simple(settings); + return; + } + } + + data_make->setting_make.parameter.array[0].value.used = 1; + data_make->setting_make.load_build = F_true; + + if (settings.objects.used) { + bool unmatched_load = F_true; for (f_array_length i = 0; i < settings.objects.used; i++) { - if (fl_string_dynamic_partial_compare(name_settings_load_build, data_make->buffer, range_load_build, settings.objects.array[i]) == F_equal_to) { - if (settings.contents.array[i].used) { - if (fl_string_dynamic_partial_compare(value_settings_load_build_yes, data_make->buffer, range_yes, settings.contents.array[i].array[0]) == F_equal_to) { - data_make->setting_make.load_build = F_true; - } - else if (fl_string_dynamic_partial_compare(value_settings_load_build_no, data_make->buffer, range_no, settings.contents.array[i].array[0]) == F_equal_to) { - data_make->setting_make.load_build = F_false; + if (fl_string_dynamic_partial_compare_string(fake_make_setting_load_build, data_make->buffer, fake_make_setting_load_build_length, settings.objects.array[i]) == F_equal_to) { + if (unmatched_load) { + if (settings.contents.array[i].used) { + if (fl_string_dynamic_partial_compare_string(fake_common_setting_bool_yes, data_make->buffer, fake_common_setting_bool_yes_length, settings.contents.array[i].array[0]) == F_equal_to) { + data_make->setting_make.load_build = F_true; + } + else if (fl_string_dynamic_partial_compare_string(fake_common_setting_bool_no, data_make->buffer, fake_common_setting_bool_no_length, settings.contents.array[i].array[0]) == F_equal_to) { + data_make->setting_make.load_build = F_false; + } + else { + fake_print_error_fakefile_settings_content_invalid(data.context, data.verbosity, data.file_data_build_fakefile.string, data_make->buffer, settings.objects.array[i], settings.contents.array[i].array[0], fake_make_section_settings); + } + + unmatched_load = F_false; } - else { - fake_print_error_fakefile_settings_content_invalid(data.context, data.verbosity, data.file_data_build_fakefile.string, data_make->buffer, settings.objects.array[i], settings.contents.array[i].array[0], fake_make_section_settings); + + if (settings.contents.array[i].used > 1) { + fake_print_warning_settings_content_multiple(data.context, data.verbosity, data.file_data_build_fakefile.string, fake_make_setting_load_build); } } - - if (settings.contents.array[i].used > 1) { + else { fake_print_warning_settings_content_multiple(data.context, data.verbosity, data.file_data_build_fakefile.string, fake_make_setting_load_build); } + } + else if (fl_string_dynamic_partial_compare_string(fake_make_setting_parameter, data_make->buffer, fake_make_setting_parameter_length, settings.objects.array[i]) == F_equal_to) { + if (settings.contents.array[i].used) { + if (fl_string_dynamic_partial_compare_string(fake_make_setting_return, data_make->buffer, fake_make_setting_return_length, settings.contents.array[i].array[0]) == F_equal_to) { + if (settings.contents.array[i].used > 1) { + f_string function_name = 0; - break; + // each define replaces the previous define. + data_make->setting_make.parameter.array[0].value.array[0].used = 0; + + for (f_array_length j = 1; j < settings.contents.array[i].used; j++) { + function_name = "fl_string_dynamic_partial_append_nulless"; + *status = fl_string_dynamic_partial_append_nulless(data_make->buffer, settings.contents.array[i].array[j], &data_make->setting_make.parameter.array[0].value.array[0]); + + if (F_status_is_fine(*status)) { + function_name = "fl_string_dynamic_terminate_after"; + *status = fl_string_dynamic_terminate_after(&data_make->setting_make.parameter.array[0].value.array[0]); + } + + if (F_status_is_fine(*status) && j + 1 < settings.contents.array[i].used) { + function_name = "fl_string_append_assure"; + *status = fl_string_append_assure(" ", 1, &data_make->setting_make.parameter.array[0].value.array[0]); + } + + if (F_status_is_error(*status)) { + fake_print_error(data.context, data.verbosity, *status, function_name, F_true); + + f_macro_fss_set_delete_simple(settings); + return; + } + } // for + } + } + } } } // for } @@ -205,6 +273,29 @@ extern "C" { } } + if (data_make->setting_make.define.used) { + f_status status_validate = F_none; + + for (f_array_length i = 0; i < data_make->setting_make.define.used; i++) { + status_validate = fake_make_operate_validate_define_name(data_make->setting_make.define.array[i].name); + + if (status_validate == F_false) { + 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: invalid characters in the define setting name '"); + + fl_color_print_code(f_type_error, data.context.notable); + f_print_string_dynamic(f_type_error, data_make->setting_make.define.array[i].name); + fl_color_print_code(f_type_error, data.context.reset); + + fl_color_print_line(f_type_error, data.context.error, data.context.reset, "', only alpha-numeric ASCII characters and underscore (without a leading digit) is allowed."); + } + + *status = F_status_set_error(F_failure); + } + } // for + } + f_macro_fss_set_delete_simple(settings); } } @@ -214,7 +305,7 @@ extern "C" { f_return_status fake_make_operate(const fake_data data) { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Making project."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Making project."); } f_status status = F_none; @@ -243,16 +334,6 @@ extern "C" { if (F_status_is_error(*status)) return; if (content.used == 0) return; - if (data.verbosity == fake_verbosity_verbose) { - fl_color_print(f_type_output, data.context.standout, data.context.reset, "Expanding content values for section operation '"); - - fl_color_print_code(f_type_output, data.context.notable); - f_print_string_dynamic(f_type_output, operation_name); - fl_color_print_code(f_type_output, data.context.reset); - - fl_color_print_line(f_type_output, data.context.standout, data.context.reset, "'."); - } - // pre-allocate the known arguments size. if (arguments->used + content.used > arguments->size) { if (arguments->used + content.used > F_buffer_too_large) { @@ -507,13 +588,13 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print(f_type_output, data.color_section_set, data.color_section_reset, "Processing Section '"); + fl_color_print(f_type_output, data.context.important, data.context.reset, "Processing Section '"); fl_color_print_code(f_type_output, data.context.notable); f_print_string_dynamic_partial(f_type_output, data_make->buffer, section->name); fl_color_print_code(f_type_output, data.context.reset); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "'."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "'."); } if (!section->objects.used) { @@ -526,6 +607,7 @@ extern "C" { 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_else, fake_make_operation_else_length), f_macro_string_static_initialize(fake_make_operation_fail, fake_make_operation_fail_length), @@ -551,6 +633,7 @@ extern "C" { 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_else_length), f_macro_string_range_initialize(fake_make_operation_fail_length), @@ -576,6 +659,7 @@ extern "C" { 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_else, fake_make_operation_type_fail, @@ -614,7 +698,6 @@ extern "C" { do { // pre-process the list to identify invalid commands so that nothing is processed if any operation can be detected as invalid by the pre-process validation. - // then process the list process = !process; for (i = 0; i < section->objects.used; i++) { @@ -686,12 +769,16 @@ extern "C" { *status = F_none; continue; } - } // for - if (error_none) { - // @todo: perform the operation. - //fake_make_operate_perform(); - } + if (error_none && process) { + fake_make_operate_perform(data, section->name, operation, *operation_name, arguments[i], operation_if, data_make, status); + + if (F_status_is_error(*status)) { + fake_print_error_fakefile_section_operation_failed(data.context, data.verbosity, data_make->buffer, section->name, section->objects.array[i]); + break; + } + } + } // for } while (error_none && !process); if (!error_none && F_status_is_fine(*status)) { @@ -704,6 +791,193 @@ extern "C" { } #endif // _di_fake_make_operate_section_ +#ifndef _di_fake_make_operate_perform_ + void fake_make_operate_perform(const fake_data data, const f_string_range section_name, const f_array_length operation, const f_string_static operation_name, const f_string_dynamics arguments, const uint8_t operation_if, fake_make_data *data_make, f_status *status) { + if (F_status_is_error(*status)) return; + + if (operation == fake_make_operation_type_archive) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + + return; + } + + if (operation == fake_make_operation_type_build) { + *status = fake_build_operate(data); + + fake_make_operate_perform_process_return(data, 0, data_make, status); + return; + } + + if (operation == fake_make_operation_type_clean) { + *status = fake_clean_operate(data); + + fake_make_operate_perform_process_return(data, 0, data_make, status); + return; + } + + if (operation == fake_make_operation_type_compile) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + return; + } + + if (operation == fake_make_operation_type_create) { + // *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_build_execute(data, data_build, 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) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + return; + } + + if (operation == fake_make_operation_type_else) { + // @todo: need to manage the condition result for the if condition to decide if the else was or was not triggered. + return; + } + + if (operation == fake_make_operation_type_fail) { + return; + } + + if (operation == fake_make_operation_type_group) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + return; + } + + if (operation == fake_make_operation_type_if) { + // @todo: walk through each condition and save success/failure state. + return; + } + + if (operation == fake_make_operation_type_link) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + return; + } + + if (operation == fake_make_operation_type_mode) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + return; + } + + if (operation == fake_make_operation_type_operate) { + // @todo: call other list, adding it to the stack. + return; + } + + if (operation == fake_make_operation_type_owner) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + return; + } + + if (operation == fake_make_operation_type_pop) { + // @todo: change directory. + return; + } + + if (operation == fake_make_operation_type_print) { + for (f_array_length i = 0; i < arguments.used; i++) { + f_print_string_dynamic(f_type_output, arguments.array[i]); + + if (i + 1 < arguments.used) { + printf(" "); + } + } // for + + printf("%c", f_string_eol[0]); + return; + } + + if (operation == fake_make_operation_type_run) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + return; + } + + if (operation == fake_make_operation_type_shell) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + return; + } + + if (operation == fake_make_operation_type_skeleton) { + *status = fake_skeleton_operate(data); + + fake_make_operate_perform_process_return(data, 0, data_make, status); + return; + } + + if (operation == fake_make_operation_type_to) { + // @todo: change directory. + return; + } + + if (operation == fake_make_operation_type_top) { + // @todo: change directory. + return; + } + + if (operation == fake_make_operation_type_touch) { + // *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_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status); + return; + } + } +#endif // _di_fake_make_operate_perform_ + +#ifndef _di_fake_make_operate_perform_process_return_ + void fake_make_operate_perform_process_return(const fake_data data, const f_number_signed return_code, fake_make_data *data_make, f_status *status) { + f_status status2 = F_none; + + // @todo: assiging the return status should be moved to a function. + data_make->setting_make.parameter.array[0].value.array[0].used = 0; + + if (F_status_is_error(*status)) { + // @todo: convert F_status_set_fine(*status) to a string and assign that instead of 1. (need a convert function from llu to string.) + status2 = fl_string_append("1", 1, &data_make->setting_make.parameter.array[0].value.array[0]); + } + else { + // @todo: convert return_code to a string and assign that instead of 0. (need a convert function from llu to string.) + status2 = fl_string_append("0", 1, &data_make->setting_make.parameter.array[0].value.array[0]); + if (F_status_is_error(status2)) { + *status = status2; + // @todo print error. + } + } + + if (F_status_is_fine(status2)) { + status2 = fl_string_dynamic_terminate_after(&data_make->setting_make.parameter.array[0].value.array[0]); + if (F_status_is_error(status2)) { + *status = status2; + // @todo print error. + } + } + } +#endif // _di_fake_make_operate_perform_process_return_ + #ifndef _di_fake_make_operate_validate_ void fake_make_operate_validate(const fake_data data, const f_string_range section_name, const f_array_length operation, const f_string_static operation_name, const fake_make_data data_make, const f_string_dynamics arguments, const uint8_t operation_if, const bool process, f_status *status) { if (F_status_is_error(*status)) return; @@ -782,6 +1056,18 @@ extern "C" { *status = F_status_set_error(F_failure); } } + else if (operation == fake_make_operation_type_define) { + if (arguments.used) { + if (process) { + // @todo: validate that first argument is a valid define name. + // @todo: if arguments.used is 1, then value is assigned to null. + } + } + else { + fake_print_error_section_operation(data, data_make.buffer,section_name, operation_name, "requires arguments"); + *status = F_status_set_error(F_failure); + } + } else if (operation == fake_make_operation_type_else) { if (operation_if == fake_make_operation_if_type_else) { fake_print_error_section_operation(data, data_make.buffer,section_name, operation_name, "must not be used after another else condition"); @@ -941,6 +1227,24 @@ extern "C" { } #endif // _di_fake_make_operate_validate_ +#ifndef _di_fake_make_operate_validate_define_name_ + f_return_status fake_make_operate_validate_define_name(const f_string_static name) { + if (!name.used) return F_none; + + if (!(isascii(name.string[0]) || name.string[0] == '_')) { + return F_false; + } + + for (f_string_length i = 0; i < name.used; i++) { + if (!(isalnum(name.string[i]) || name.string[i] == '_')) { + return F_false; + } + } // for + + return F_true; + } +#endif // _di_fake_make_operate_validate_define_name_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/fake/c/private-make.h b/level_3/fake/c/private-make.h index 47c3697..6c0575c 100644 --- a/level_3/fake/c/private-make.h +++ b/level_3/fake/c/private-make.h @@ -41,47 +41,51 @@ extern "C" { f_macro_string_map_multis_delete_simple(setting.define) \ f_macro_string_map_multis_delete_simple(setting.parameter) - #define fake_make_setting_define "define" // @todo 'define' means define this as an environment variable on run, only a single argument is supported. (consider a second parameter such as 'if_missing' or 'if_exists' to define this only if it is not already defined.) - #define fake_make_setting_load_build "load_build" // @todo ("yes"/"no") as in use the build settings file, write code to import that first and match all settings from that into this. - #define fake_make_setting_parameter "parameter" // @todo see parameters below, first content is parameter name, second content is parameter values. + #define fake_make_setting_define "define" + #define fake_make_setting_load_build "load_build" + #define fake_make_setting_parameter "parameter" + #define fake_make_setting_return "return" #define fake_make_setting_define_length 6 #define fake_make_setting_load_build_length 10 #define fake_make_setting_parameter_length 9 + #define fake_make_setting_return_length 6 #define fake_make_setting_total 3 #endif // _di_fake_make_setting_ // @todo "operate" should use a call stack, but do not allow recursive calls (check to see if named operation is already on the call stack). #ifndef _di_fake_make_operation_ - #define fake_make_operation_archive "archive" // run the ar linker (all arguments are passed as arguments, except for reserved parameter words, with $ in front, such as $build_1). - #define fake_make_operation_build "build" // run the fake build operation ($1 = path to settings file, if missing use default, auto-passes verbosity and other Fake parameters.). - #define fake_make_operation_clean "clean" // run the fake clean operation (auto-passes verbosity and other Fake parameters.). - #define fake_make_operation_compile "compile" // run the gcc compiler (all arguments are passed as arguments, except for reserved parameter words, with $ in front, such as $build_1). - #define fake_make_operation_create "create" // create a file or directory ($1 = 'file' or 'directory') ($2 = path to file or directory) ($3 = 'recursive' (optional) for 'directory' only). - #define fake_make_operation_delete "delete" // delete a file or directory ($1 = 'file' or 'directory') ($2 = path to file or directory) ($3 = 'recursive' (optional) for 'directory' only). - #define fake_make_operation_else "else" // execute next line if immediately previous "if" condition fails (if exists file_name.txt, if defined environment_name, if equals "some string or define" "another string or define", if succeed for previous run/shell command succeeding, if fail for previous run/shell command failing). - #define fake_make_operation_fail "fail" // what to do when a command fails, either 'exit', 'warn' or 'ignore'. - #define fake_make_operation_group "group" // change group on file or directory ($1 = path to file or directory). - #define fake_make_operation_if "if" // execute next line if condition succeeds (if exists file_name.txt, if defined environment_name, if equals "some string or define" "another string or define", if succeed for previous run/shell command succeeding, if fail for previous run/shell command failing). - #define fake_make_operation_link "link" // create a symbolic link ($1 = target) ($2 = point). (@todo also don't allow linking outside project directory). - #define fake_make_operation_mode "mode" // change mode of a file or directory ($1 = path to file or directory). - #define fake_make_operation_operate "operate" // enter into a given named operation except for reserved . - #define fake_make_operation_owner "owner" // change owner on file or directory ($1 = path to file or directory). - #define fake_make_operation_pop "pop" // pop the previous directory off the stack, changing to the popped directory. - #define fake_make_operation_print "print" // print to an output or file ($1 = color, out, error, warning) ($2 = if $1 = color, then out, error, warning; else string to print) ($3 = if $1 = color, then string to print). - #define fake_make_operation_run "run" // execute command via PATH ($1 = program name, all other arguments are passed as arguments, except for reserved parameter words, with $ in front, such as $build_1). - #define fake_make_operation_shell "shell" // execute command at path ($1 = path to program/script, all other arguments are passed as arguments, except for reserved parameter words, with $ in front, such as $build_1). - #define fake_make_operation_skeleton "skeleton" // run the fake skeleton operation (auto-passes verbosity and other Fake parameters.). - #define fake_make_operation_to "to" // change into a given directory, adding it to the directory stack ($1 = directory name). - #define fake_make_operation_top "top" // change to project root, clearing directory stack. - #define fake_make_operation_touch "touch" // perform touch operation on file or directoy ($1 = path to file or directory). + #define fake_make_operation_archive "archive" + #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_else "else" + #define fake_make_operation_fail "fail" + #define fake_make_operation_group "group" + #define fake_make_operation_if "if" + #define fake_make_operation_link "link" + #define fake_make_operation_mode "mode" + #define fake_make_operation_operate "operate" + #define fake_make_operation_owner "owner" + #define fake_make_operation_pop "pop" + #define fake_make_operation_print "print" + #define fake_make_operation_run "run" + #define fake_make_operation_shell "shell" + #define fake_make_operation_skeleton "skeleton" + #define fake_make_operation_to "to" + #define fake_make_operation_top "top" + #define fake_make_operation_touch "touch" #define fake_make_operation_archive_length 7 #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_else_length 4 #define fake_make_operation_fail_length 4 @@ -106,6 +110,7 @@ extern "C" { 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_else, fake_make_operation_type_fail, @@ -125,7 +130,7 @@ extern "C" { fake_make_operation_type_touch, }; - #define fake_make_operation_total 22 + #define fake_make_operation_total 23 #define fake_make_operation_argument_file "file" #define fake_make_operation_argument_directory "directory" @@ -168,6 +173,7 @@ extern "C" { #define fake_make_parameter_variable_no_color "no_color" #define fake_make_parameter_variable_process "process" #define fake_make_parameter_variable_quiet "quiet" + #define fake_make_parameter_variable_return "return" #define fake_make_parameter_variable_settings "settings" #define fake_make_parameter_variable_sources "sources" #define fake_make_parameter_variable_verbose "verbose" @@ -182,6 +188,7 @@ extern "C" { #define fake_make_file_parameter_variable_no_color_length 8 #define fake_make_file_parameter_variable_process_length 7 #define fake_make_file_parameter_variable_quiet_length 5 + #define fake_make_file_parameter_variable_return_length 6 #define fake_make_file_parameter_variable_settings_length 8 #define fake_make_file_parameter_variable_sources_length 7 #define fake_make_file_parameter_variable_verbose_length 7 @@ -245,6 +252,7 @@ extern "C" { f_fss_nameds fakefile; f_string_dynamic buffer; + f_array_length main; uint8_t fail; @@ -363,8 +371,6 @@ extern "C" { /** * Perform a specific make operation within the given section. * - * @todo - * * @param data * The program data. * @param section_name @@ -373,20 +379,38 @@ extern "C" { * The operation being performed. * @param operation_name * The operation name. - * @param data_make - * All make related setting data, including data from the fakefile and optionally build settings file. * @param arguments * The expanded arguments. + * @param operation_if + * The if-condition status for the current operation. + * @param data_make + * All make related setting data, including data from the fakefile and optionally build settings file. * @param status * The return status. * * Status codes (with error bit) are returned on any problem. */ #ifndef _di_fake_make_operate_perform_ - //extern void fake_make_operate_perform(const fake_data data, const f_string_range section_name, const f_array_length operation, const f_string_static operation_name, const fake_make_data data_make, const f_string_dynamics arguments, f_status *status) f_gcc_attribute_visibility_internal; + extern void fake_make_operate_perform(const fake_data data, const f_string_range section_name, const f_array_length operation, const f_string_static operation_name, const f_string_dynamics arguments, const uint8_t operation_if, fake_make_data *data_make, f_status *status) f_gcc_attribute_visibility_internal; #endif // _di_fake_make_operate_perform_ /** + * Handle the return code, converting it to a number. + * + * @param data + * The program data. + * @param data_make + * All make related setting data, including data from the fakefile and optionally build settings file. + * @param status + * The return status. + * + * Status codes (with error bit) are returned on any problem. + */ +#ifndef _di_fake_make_operate_perform_process_return_ + extern void fake_make_operate_perform_process_return(const fake_data data, const f_number_signed return_code, fake_make_data *data_make, f_status *status) f_gcc_attribute_visibility_internal; +#endif // _di_fake_make_operate_perform_process_return_ + +/** * For a given make section operation, validate the given operation. * * This performs pre-operation validations. @@ -418,6 +442,25 @@ extern "C" { extern void fake_make_operate_validate(const fake_data data, const f_string_range section_name, const f_array_length operation, const f_string_static operation_name, const fake_make_data data_make, const f_string_dynamics arguments, const uint8_t operation_if, const bool process, f_status *status) f_gcc_attribute_visibility_internal; #endif // _di_fake_make_operate_validate_ +/** + * Validate that the given define variable name is valid. + * + * A valid define variable name mst begin with an alpha-character or an underscore. + * Every character after that may be alphanumeric or underscore. + * All other characters, including Unicode characters, are invalid. + * + * @param name + * The variable name string to validate. + * + * @return + * F_true on valid. + * F_false on invalid. + * F_none if there is no string to validate (used = 0). + */ +#ifndef _di_fake_make_operate_validate_define_name_ + extern f_return_status fake_make_operate_validate_define_name(const f_string_static name) f_gcc_attribute_visibility_internal; +#endif // _di_fake_make_operate_validate_define_name_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/fake/c/private-print.c b/level_3/fake/c/private-print.c index 7d0538b..466b982 100644 --- a/level_3/fake/c/private-print.c +++ b/level_3/fake/c/private-print.c @@ -100,6 +100,33 @@ extern "C" { } #endif // _di_fake_print_error_fakefile_section_line_ +#ifndef _di_fake_print_error_fakefile_section_operation_failed_ + void fake_print_error_fakefile_section_operation_failed(const fl_color_context context, const uint8_t verbosity, const f_string_static buffer, const f_string_range section_name, const f_string_range operation_name) { + if (verbosity == fake_verbosity_quiet) return; + + f_string_length line = 0; + + f_fss_count_lines(buffer, operation_name.start, &line); + + fprintf(f_type_error, "%c", f_string_eol[0]); + fl_color_print(f_type_error, context.error, context.reset, "ERROR: The section operation '"); + + fl_color_print_code(f_type_error, context.notable); + f_print_string_dynamic_partial(f_type_error, buffer, operation_name); + fl_color_print_code(f_type_error, context.reset); + + fl_color_print(f_type_error, context.error, context.reset, "' from section '"); + + fl_color_print_code(f_type_error, context.notable); + f_print_string_dynamic_partial(f_type_error, buffer, section_name); + fl_color_print_code(f_type_error, context.reset); + + fl_color_print(f_type_error, context.error, context.reset, "' on line "); + fl_color_print(f_type_error, context.notable, context.reset, "%llu", line); + fl_color_print_line(f_type_error, context.error, context.reset, " failed."); + } +#endif // _di_fake_print_error_fakefile_section_operation_failed_ + #ifndef _di_fake_print_error_fakefile_section_operation_stack_max_ void fake_print_error_fakefile_section_operation_stack_max(const fl_color_context context, const uint8_t verbosity, const f_string_static buffer, const f_string_range section_name, const f_string_range operation_name, const f_array_length stack_max) { if (verbosity == fake_verbosity_quiet) return; @@ -693,12 +720,12 @@ extern "C" { fprintf(f_type_error, "%c", f_string_eol[0]); - fl_color_print(f_type_warning, context.warning, context.reset, "WARNING: the setting object '"); + fl_color_print(f_type_warning, context.warning, context.reset, "WARNING: the setting '"); fl_color_print(f_type_warning, context.notable, context.reset, "%s", name_object); fl_color_print(f_type_warning, context.warning, context.reset, "' in the file '"); fl_color_print(f_type_warning, context.notable, context.reset, "%s", path_file); - fl_color_print_line(f_type_warning, context.warning, context.reset, "' may only have a single content, only using the first."); + fl_color_print_line(f_type_warning, context.warning, context.reset, "' may only have a single property, only using the first."); } #endif // _di_fake_print_warning_settings_content_multiple_ diff --git a/level_3/fake/c/private-print.h b/level_3/fake/c/private-print.h index 74b0a59..86d42ef 100644 --- a/level_3/fake/c/private-print.h +++ b/level_3/fake/c/private-print.h @@ -89,6 +89,24 @@ extern "C" { #endif // _di_fake_print_error_fakefile_section_line_ /** + * Print error messages when processing some fakefile section, for a specific line and operation, and that operation failed. + * + * @param context + * The color context. + * @param verbosity + * The verbosity level, which determines if and what should be printed. + * @param buffer + * The buffer containing the fakefile data. + * @param section_name + * The range within the buffer representing the section name. + * @param operation_name + * The range within the buffer representing the operation name within the section. + */ +#ifndef _di_fake_print_error_fakefile_section_operation_failed_ + extern void fake_print_error_fakefile_section_operation_failed(const fl_color_context context, const uint8_t verbosity, const f_string_static buffer, const f_string_range section_name, const f_string_range operation_name) f_gcc_attribute_visibility_internal; +#endif // _di_fake_print_error_fakefile_section_operation_failed_ + +/** * Print error messages when processing some fakefile section, for a specific line and operation, and that the max stack depth is reached. * * @param context diff --git a/level_3/fake/c/private-skeleton.c b/level_3/fake/c/private-skeleton.c index da904da..9408540 100644 --- a/level_3/fake/c/private-skeleton.c +++ b/level_3/fake/c/private-skeleton.c @@ -14,7 +14,7 @@ extern "C" { if (data.verbosity != fake_verbosity_quiet) { printf("%c", f_string_eol[0]); - fl_color_print_line(f_type_output, data.color_section_set, data.color_section_reset, "Generating skeleton structure."); + fl_color_print_line(f_type_output, data.context.important, data.context.reset, "Generating skeleton structure."); } { diff --git a/level_3/fake/data/build/fakefile b/level_3/fake/data/build/fakefile index 82e9769..979692e 100644 --- a/level_3/fake/data/build/fakefile +++ b/level_3/fake/data/build/fakefile @@ -3,47 +3,25 @@ settings: load_build yes - define example value - - # from this, adding 'parameter:"verbose"' in main would be replaced with '+v' if and when the +V/++verbose parameter is passed to fake otherwise it is removed. - # gcc parameter:"verbose" would become gcc +v parameter verbose +v - parameter verbose4 +v and then " some" main: - print This is a line "(define = 'define:"example"')." parameter:"verbose4" - - invalid - - print This works? 'parameter\:"verbose" parameter:"verbose2' parameter:'verbose3' should_-+miss:"abc" - print This is another line. 'parameter\:"verbose" parameter:"verbose2\""' parameter:'verbose3\\' - - another invalid - - archive // run the ar linker (all arguments are passed as arguments, except for reserved parameter words, with $ in front, such as $build_1). - build // run the fake build operation ($1 = path to settings file, if missing use default, auto-passes verbosity and other Fake parameters.). - clean // run the fake clean operation (auto-passes verbosity and other Fake parameters.). - compile // run the gcc compiler (all arguments are passed as arguments, except for reserved parameter words, with $ in front, such as $build_1). - create // create a file or directory ($1 = file or directory) ($2 = path to file or directory) ($3 = recursive (optional) for directory only). - delete // delete a file or directory ($1 = file or directory) ($2 = path to file or directory) ($3 = recursive (optional) for directory only). - else // execute next line if immediately previous if condition fails (if exists file_name.txt, if defined environment_name, if equals some string or define another string or define, if succeed for previous run/shell command succeeding, if fail for previous run/shell command failing). - fail // what to do when a command fails, either exit, warn or ignore. - group // change group on file or directory ($1 = path to file or directory). - if // execute next line if condition succeeds (if exists file_name.txt, if defined environment_name, if equals some string or define another string or define, if succeed for previous run/shell command succeeding, if fail for previous run/shell command failing). - link // create a symbolic link ($1 = target) ($2 = point). (@todo also dont allow linking outside project directory). - mode // change mode of a file or directory ($1 = path to file or directory). - operate // enter into a given named operation except for reserved . - owner // change owner on file or directory ($1 = path to file or directory). - pop // pop the previous directory off the stack, changing to the popped directory. - print // print to an output or file ($1 = color, out, error, warning) ($2 = if $1 = color, then out, error, warning; else string to print) ($3 = if $1 = color, then string to print). - run // execute command via PATH ($1 = program name, all other arguments are passed as arguments, except for reserved parameter words, with $ in front, such as $build_1). - shell // execute command at path ($1 = path to program/script, all other arguments are passed as arguments, except for reserved parameter words, with $ in front, such as $build_1). - skeleton // run the fake skeleton operation (auto-passes verbosity and other Fake parameters.). - to // change into a given directory, adding it to the directory stack ($1 = directory name). - top // change to project root, clearing directory stack. - touch // perform touch operation on file or directoy ($1 = path to file or directory). - - - and - so - forth + print Begin processing the \"main" program. + + print + print First, cleaning any previous work. + clean + + print Result = \'parameter:"result"' + + print + print Second, building the skeleton. + skeleton + + print Result = \'parameter:"result"' + + print + print Third, executing the build process. + build + + print Result = \'parameter:"result"' diff --git a/level_3/fake/documents/fakefile.txt b/level_3/fake/documents/fakefile.txt index 7072fd3..9ec2842 100644 --- a/level_3/fake/documents/fakefile.txt +++ b/level_3/fake/documents/fakefile.txt @@ -15,19 +15,23 @@ Fakefile Documentation: The following settings are available (in addition to the build settings)\: - 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. - @todo: consider changing how/when define is applied and validated. It may be better to expand each operation immediately before execution in order to open the possibility of an environment define variable being changed. + 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. - load_build\: - This represents whether or not to load the load the build settings file. - The first Content value may be "true" to load the build settings and "false" to not load the build settings file. + This represents whether or not to load the load the build settings file. + The first Content value may be "true" to load the build settings and "false" to not load the build settings file. - parameter\: - This defines an IKI variable name to substitute with the value. - The first Content value represents the IKI variable name. - All Content values after the first represent the values the matching IKI variable is replaced with. + This defines an IKI variable name to substitute with the value. + This replaces the value of any existing environment variable with this name. + + The first Content value represents the IKI variable name. + All Content values after the first represent the values the matching IKI variable is replaced with. + + The parameter variable name "return" is used to store the return result of an "run" or "shell" operation. + Setting this here only sets the default "return" parameter variable value. - main\: This is the main entry point when processing the fakefile. @@ -35,7 +39,8 @@ Fakefile Documentation: The following operations are available\: - archive\: - Execute the archive program, such as "ar". + Execute the linker program, such as "ar". + This uses "archive" instead of "link" to avoid confusion between this and generating a symbolic link to some file. All Content are passed as arguments to the respective "ar" program. @@ -67,6 +72,11 @@ Fakefile Documentation: This third Content, if specified, may only be "recursive". When specified, 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. @@ -170,6 +180,9 @@ Fakefile Documentation: The first Content represents the program or script name. All Content after the first are passed to the program or script when running. + After this executes the return result is made available via the "return" parameter variable name. + Any existing value associated with "return" gets replaced. + - shell\: Manually execute a remote program or script using a specific path to the program or script. This does not require the program to exist in PATH, but the path to the program or script must be relative to the project path. @@ -178,6 +191,9 @@ Fakefile Documentation: The first Content represents the program or script name. All Content after the first are passed to the program or script when running. + After this executes the return result is made available via the "return" parameter variable name. + Any existing value associated with "return" gets replaced. + - skeleton\: Run the fake skeleton operation as if "fake skeleton" was run instead of "fake make". Command line arguments are automatically passed to the fake skeleton operation. diff --git a/level_3/fake/specifications/fakefile.txt b/level_3/fake/specifications/fakefile.txt index f4af710..0a466c7 100644 --- a/level_3/fake/specifications/fakefile.txt +++ b/level_3/fake/specifications/fakefile.txt @@ -14,6 +14,7 @@ Fakefile Specification: The Operations are represented by the Extended Object name and the Extended Content represents the Operation Arguments. Each of these Operations support IKI variable substitution within their respective Arguments. The Operation Extended Object does not support IKI variable substitution. + The reserved Settings Section does not support IKI variable substitution. The IKI-0002 vocabulary context is further clarified as follows\: - define\: @@ -43,20 +44,21 @@ 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 or Three Content. First Content is either "file" or "directory" (case-sensitive), Second Content is path to file, and Third Content is "recursive" (case-sensitive) or is not provided. - - delete: Two or Three Content. First Content is either "file" or "directory" (case-sensitive), Second Content is path to file, and Third Content is "recursive" (case-sensitive) or is not provided. + - create: Two or three Content. First Content is either "file" or "directory" (case-sensitive), second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided. + - define: Two or more Content. + - delete: Two or three Content. First Content is either "file" or "directory" (case-sensitive), second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided. - else: Zero Content. - fail: One Content. First Content must be one of "exit", "warn", or "ignore" (case-sensitive). - - group: Two or Three Content. First Content is group name or number, Second Content is path to file, and Third Content is "recursive" (case-sensitive) or is not provided. - - if: One or More Content. First Content is the condition, remaining Content are specific to the condition. - - link: Two Content. First Content is the link target file and Second Content is the pointer file (the link). - - mode: Two or Three Content. First Content is group name or number, Second Content is path to file, and Third Content is "recursive" (case-sensitive) or is not provided. + - group: Two or three Content. First Content is group name or number, second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided. + - if: One or more Content. First Content is the condition, remaining Content are specific to the condition. + - link: Two Content. First Content is the link target file and second Content is the pointer file (the link). + - mode: Two or three Content. First Content is group name or number, second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided. - operate: One Content. First Content is the name of a valid Section Object, except for the reserved Section Objects. - - owner: Two or Three Content. First Content is group name or number, Second Content is path to file, and Third Content is "recursive" (case-sensitive) or is not provided. + - owner: Two or Three Content. First Content is group name or number, second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided. - pop: Zero Content. - - print: Zero or More Content. - - run: One or More Content. First Content is the name of the program (or script) and all remaining Content are passed as arguments to the named program (or script). - - shell: One or More Content. First Content is the file path of the program (or script) and all remaining Content are passed as arguments to the named program (or script). + - print: Zero or more Content. + - run: One or more Content. First Content is the name of the program (or script) and all remaining Content are passed as arguments to the named program (or script). + - shell: One or more Content. First Content is the file path of the program (or script) and all remaining Content are passed as arguments to the named program (or script). - skeleton: Zero Content. - to: One Content. First Content is the directory path. - top: Zero Content. -- 1.8.3.1