From: Kevin Day Date: Tue, 4 Jun 2024 05:35:02 +0000 (-0500) Subject: Progress: Continue migrating the project. X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=769f3f92b276f5cdc455c19f2f299803edac7041;p=controller Progress: Continue migrating the project. --- diff --git a/data/build/settings b/data/build/settings index 256af71..5c17d3d 100644 --- a/data/build/settings +++ b/data/build/settings @@ -44,9 +44,11 @@ build_sources_library main/common.c main/common/define.c main/common/enumeration build_sources_library main/common/type/cache.c main/common/type/control.c main/common/type/entry.c main/common/type/execute.c main/common/type/instance.c main/common/type/interrupt.c main/common/type/lock.c main/common/type/process.c main/common/type/rule.c main/common/type/thread.c build_sources_library main/common/string/general.c main/common/string/rule.c build_sources_library main/convert.c main/instance.c main/instance/prepare.c main/instance/wait.c +build_sources_library main/entry.c main/entry/action.c main/entry/preprocess.c main/entry/process.c main/entry/setting.c build_sources_library main/file.c main/lock.c main/path.c main/process.c build_sources_library main/rule.c main/rule/action.c main/rule/execute.c main/rule/expand.c main/rule/instance.c main/rule/is.c main/rule/item.c main/rule/parameter.c main/rule/read.c main/rule/setting.c main/rule/validate.c main/rule/wait.c -build_sources_library main/print/action.c main/print/data.c main/print/debug.c main/print/error.c main/print/lock.c main/print/message.c main/print/rule.c main/print/verbose.c main/print/warning.c +build_sources_library main/perform.c +build_sources_library main/print/action.c main/print/data.c main/print/debug.c main/print/entry.c main/print/error.c main/print/lock.c main/print/message.c main/print/rule.c main/print/verbose.c main/print/warning.c build_sources_library main/print/rule/action.c main/print/rule/item.c main/print/rule/setting.c build_sources_library main/signal.c main/time.c build_sources_library main/thread.c main/thread/cleanup.c main/thread/control.c main/thread/entry.c main/thread/instance.c main/thread/is.c main/thread/rule.c main/thread/signal.c @@ -58,9 +60,11 @@ build_sources_headers main/common/enumeration/control.h main/common/enumeration/ build_sources_headers main/common/string/general.h main/common/string/rule.h build_sources_headers main/common/type/cache.h main/common/type/control.h main/common/type/defs.h main/common/type/entry.h main/common/type/execute.h main/common/type/instance.h main/common/type/interrupt.h main/common/type/lock.h main/common/type/process.h main/common/type/rule.h main/common/type/thread.h build_sources_headers main/convert.h main/instance.h main/instance/prepare.h main/instance/wait.h +build_sources_headers main/entry.h main/entry/action.h main/entry/preprocess.h main/entry/process.h main/entry/setting.h build_sources_headers main/file.h main/lock.h main/path.h main/process.h build_sources_headers main/rule.h main/rule/action.h main/rule/execute.h main/rule/expand.h main/rule/instance.h main/rule/is.h main/rule/item.h main/rule/parameter.h main/rule/read.h main/rule/setting.h main/rule/validate.h main/rule/wait.h -build_sources_headers main/print/action.h main/print/data.h main/print/debug.h main/print/error.h main/print/lock.h main/print/message.h main/print/rule.h main/print/verbose.h main/print/warning.h +build_sources_headers main/perform.h +build_sources_headers main/print/action.h main/print/data.h main/print/debug.h main/print/entry.h main/print/error.h main/print/lock.h main/print/message.h main/print/rule.h main/print/verbose.h main/print/warning.h build_sources_headers main/print/rule/action.h main/print/rule/item.h main/print/rule/setting.h build_sources_headers main/signal.h main/time.h build_sources_headers main/thread.h main/thread/cleanup.h main/thread/control.h main/thread/entry.h main/thread/instance.h main/thread/is.h main/thread/rule.h main/thread/signal.h diff --git a/sources/c/main/common/print.c b/sources/c/main/common/print.c index 999d311..a489503 100644 --- a/sources/c/main/common/print.c +++ b/sources/c/main/common/print.c @@ -6,6 +6,8 @@ extern "C" { #ifndef _di_controller_f_a_ const f_string_t controller_f_a[] = { + "controller_convert_group_id", + "controller_convert_user_id", "controller_lock_create", "controller_rule_copy", "controller_path_canonical_relative", @@ -41,6 +43,7 @@ extern "C" { "fl_fss_extended_object_read", "fl_iki_read", "fll_control_group_prepare", + "fll_execute_into", "fll_execute_program", "fll_fss_basic_list_read", "fll_fss_extended_read", diff --git a/sources/c/main/common/print.h b/sources/c/main/common/print.h index a8b6feb..7bf2381 100644 --- a/sources/c/main/common/print.h +++ b/sources/c/main/common/print.h @@ -39,6 +39,8 @@ extern "C" { */ #ifndef _di_controller_f_e_ enum { + controller_f_controller_convert_group_id_e, + controller_f_controller_convert_user_id_e, controller_f_controller_lock_create_e, controller_f_controller_rule_copy_e, controller_f_controller_path_canonical_relative_e, @@ -74,6 +76,7 @@ extern "C" { controller_f_fl_fss_extended_object_read_e, controller_f_fl_iki_read_e, controller_f_fll_control_group_prepare_e, + controller_f_fll_execute_into_e, controller_f_fll_execute_program_e, controller_f_fll_fss_basic_list_read_e, controller_f_fll_fss_extended_read_e, diff --git a/sources/c/main/controller.h b/sources/c/main/controller.h index b1a0047..d767d84 100644 --- a/sources/c/main/controller.h +++ b/sources/c/main/controller.h @@ -104,6 +104,7 @@ #include #include #include +#include #include #include #include diff --git a/sources/c/main/convert.c b/sources/c/main/convert.c index b58200d..59c59cb 100644 --- a/sources/c/main/convert.c +++ b/sources/c/main/convert.c @@ -5,7 +5,7 @@ extern "C" { #endif #ifndef _di_controller_convert_user_id_ - f_status_t controller_convert_user_id(const f_string_static_t buffer, const f_range_t range, controller_cache_t * const cache, uid_t * const id) { + f_status_t controller_convert_user_id(controller_cache_t * const cache, const f_string_static_t buffer, const f_range_t range, uid_t * const id) { f_number_unsigned_t number = 0; @@ -32,7 +32,7 @@ extern "C" { #endif // _di_controller_convert_user_id_ #ifndef _di_controller_convert_group_id_ - f_status_t controller_convert_group_id(const f_string_static_t buffer, const f_range_t range, controller_cache_t * const cache, gid_t * const id) { + f_status_t controller_convert_group_id(controller_cache_t * const cache, const f_string_static_t buffer, const f_range_t range, gid_t * const id) { f_number_unsigned_t number = 0; @@ -145,6 +145,30 @@ extern "C" { } #endif // _di_controller_convert_rule_action_type_string_ +#ifndef _di_controller_convert_rule_item_type_string_ + f_string_static_t controller_convert_rule_item_type_string(const uint8_t type) { + + switch (type) { + case controller_rule_item_type_command_e: + return controller_command_s; + + case controller_rule_item_type_script_e: + return controller_script_s; + + case controller_rule_item_type_service_e: + return controller_service_s; + + case controller_rule_item_type_settings_e: + return controller_settings_s; + + case controller_rule_item_type_utility_e: + return controller_utility_s; + } + + return f_string_empty_s; + } +#endif // _di_controller_convert_rule_item_type_string_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/main/convert.h b/sources/c/main/convert.h index 07850ff..d07096a 100644 --- a/sources/c/main/convert.h +++ b/sources/c/main/convert.h @@ -43,7 +43,7 @@ extern "C" { * @see f_rip_dynamic_partial_nulless() */ #ifndef _di_controller_convert_user_id_ - f_status_t controller_convert_user_id(const f_string_static_t buffer, const f_range_t range, controller_cache_t * const cache, uid_t * const id); + f_status_t controller_convert_user_id(controller_cache_t * const cache, const f_string_static_t buffer, const f_range_t range, uid_t * const id); #endif // _di_controller_convert_user_id_ /** @@ -73,7 +73,7 @@ extern "C" { * @see f_rip_dynamic_partial_nulless() */ #ifndef _di_controller_convert_group_id_ - f_status_t controller_convert_group_id(const f_string_static_t buffer, const f_range_t range, controller_cache_t * const cache, gid_t * const id); + f_status_t controller_convert_group_id(controller_cache_t * const cache, const f_string_static_t buffer, const f_range_t range, gid_t * const id); #endif // _di_controller_convert_group_id_ /** @@ -104,6 +104,20 @@ extern "C" { extern f_string_static_t controller_convert_rule_action_type_string(const uint8_t type); #endif // _di_controller_convert_rule_action_type_string_ +/** + * Convert the rule item type code to the string representation. + * + * @param type + * The rule item type code. + * + * @return + * The string with used > 0 on success. + * The string with used == 0 if no match was found. + */ +#ifndef _di_controller_convert_rule_item_type_string_ + extern f_string_static_t controller_convert_rule_item_type_string(const uint8_t type); +#endif // _di_controller_convert_rule_item_type_string_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/main/entry.c b/sources/c/main/entry.c new file mode 100644 index 0000000..ea4d9a2 --- /dev/null +++ b/sources/c/main/entry.c @@ -0,0 +1,355 @@ +#include "controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_entry_read_ + f_status_t controller_entry_read(controller_t * const main, controller_cache_t * const cache, const uint8_t is_entry) { + + f_status_t status = F_okay; + + controller_entry_t * const entry = is_entry ? &main->process.entry : &main->process.exit; + + entry->status = F_known_not; + entry->items.used = 0; + entry->session = (main->setting.flag & controller_main_flag_init_e) ? controller_entry_session_new_e : controller_entry_session_same_e; + + cache->action.line_action = 0; + cache->action.line_item = 0; + + cache->timestamp.seconds = 0; + cache->timestamp.seconds_nano = 0; + + cache->comments.used = 0; + cache->delimits.used = 0; + + cache->content_action.used = 0; + + { + f_number_unsigned_t i = 0; + + for (; i < cache->content_actions.used; ++i) { + cache->content_actions.array[i].used = 0; + } // for + + for (i = 0; i < cache->content_items.used; ++i) { + cache->content_items.array[i].used = 0; + } // for + } + + cache->content_actions.used = 0; + cache->content_items.used = 0; + + cache->object_actions.used = 0; + cache->object_items.used = 0; + + cache->buffer_file.used = 0; + cache->buffer_path.used = 0; + + cache->action.name_file.used = 0; + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; + + if (is_entry) { + status = controller_file_load(main, cache, F_true, controller_entries_s, main->setting.name_entry, controller_entry_s); + } + else { + status = controller_file_load(main, cache, F_false, controller_exits_s, main->setting.name_entry, controller_exit_s); + if (status == F_file_found_not) return F_file_found_not; + } + + if (F_status_is_error_not(status)) { + if (cache->buffer_file.used) { + controller_interrupt_t custom = macro_controller_interrupt_t_initialize_1(is_entry, main); + f_state_t state = macro_f_state_t_initialize_1(controller_common_allocation_large_d, controller_common_allocation_small_d, F_okay, 0, 0, 0, &controller_thread_signal_state_fss, 0, (void *) &custom, 0); + f_range_t range = macro_f_range_t_initialize_2(cache->buffer_file.used); + + fll_fss_basic_list_read(cache->buffer_file, &range, &cache->object_items, &cache->content_items, &cache->delimits, 0, &cache->comments, &state); + + if (F_status_is_error(status)) { + controller_print_error_status(&main->program.error, macro_controller_f(fll_fss_basic_list_read), F_status_set_fine(status)); + } + else { + f_fss_apply_delimit(cache->delimits, &cache->buffer_file, &state); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), "f_fss_apply_delimit", F_true, &main->thread); + controller_print_error_status(&main->program.error, macro_controller_f(fll_fss_basic_list_read), F_status_set_fine(status)); + } + } + } + else { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fll_print_format("%r%[%QThe %r file is empty.%]%r", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, is_entry ? controller_entry_s : is_entry ? controller_entry_s : controller_exit_s, main->program.error.context, f_string_eol_s); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + status = F_status_set_error(F_data_not); + } + } + + if (F_status_is_error_not(status) && cache->object_items.used) { + status = f_memory_array_increase_by(cache->object_items.used, &entry->items.array, &entry->items.used, &entry->items.size); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), "f_memory_array_increase_by", F_true, &main->thread); + controller_print_error_status(&main->program.error, macro_controller_f(f_string_dynamic_append), F_status_set_fine(status)); + } + else { + + // 0x1 = main found, 0x2 = found existing. + uint8_t code = 0; + + f_range_t *range = 0; + + f_number_unsigned_t at = 0; + f_number_unsigned_t i = 0; + f_number_unsigned_t j = 0; + + f_state_t state = f_state_t_initialize; + + for (; i < cache->object_items.used && controller_thread_is_enabled(is_entry, &main->thread); ++i) { + + if (code & 0x2) { + code -= 0x2; + } + + at = 0; + range = 0; + + cache->action.line_action = 0; + cache->action.line_item = 0; + + cache->comments.used = 0; + cache->delimits.used = 0; + + cache->content_action.used = 0; + cache->content_actions.used = 0; + + cache->object_actions.used = 0; + + cache->buffer_path.used = 0; + + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; + + status = controller_entry_items_increase_by(controller_common_allocation_small_d, &entry->items); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), "controller_entry_items_increase_by", F_true, &main->thread); + + break; + } + + status = f_string_dynamic_partial_append(cache->buffer_file, cache->object_items.array[i], &cache->action.name_item); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), "f_string_dynamic_partial_append", F_true, &main->thread); + + break; + } + + f_fss_count_lines(cache->buffer_file, cache->object_items.array[i].start, &cache->action.line_item, &main->setting.state); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), "f_fss_count_lines", F_true, &main->thread); + + break; + } + + ++cache->action.line_item; + + for (j = (code & 0x1) ? 1 : 0; j < entry->items.used; ++j) { + + if (f_compare_dynamic(entry->items.array[j].name, cache->action.name_item) == F_equal_to) { + if (main->program.warning.verbosity == f_console_verbosity_debug_e) { + controller_lock_print(main->program.warning.to, &main->thread); + + fl_print_format("%r%[%QIgnoring duplicate %r item '%]", main->program.warning.to, f_string_eol_s, main->program.warning.context, main->program.warning.prefix, is_entry ? controller_entry_s : controller_exit_s, main->program.warning.context); + fl_print_format(f_string_format_Q_single_s.string, main->program.warning.to, main->program.warning.notable, cache->action.name_file, main->program.warning.notable); + fl_print_format(f_string_format_sentence_end_quote_s.string, main->program.warning.to, main->program.warning.context, main->program.warning.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.warning, cache->action); + + controller_unlock_print_flush(main->program.warning.to, &main->thread); + } + + code |= 0x2; + + break; + } + } // for + + if (code & 0x2) continue; + + range = &cache->content_items.array[i].array[0]; + + if (f_compare_dynamic(controller_main_s, cache->action.name_item) == F_equal_to) { + code |= 0x1; + + at = 0; + + if (!entry->items.used) { + entry->items.used = 1; + } + } + else if (f_compare_dynamic(controller_settings_s, cache->action.name_item) == F_equal_to) { + status = controller_entry_setting_read(main, cache, is_entry, *range); + + continue; + } + else if (entry->items.used) { + at = entry->items.used++; + } + else { + + // skip position 0, which is reserved for "main". + entry->items.array[0].name.used = 0; + + at = 1; + entry->items.used = 2; + } + + entry->items.array[at].line = cache->action.line_item; + + status = f_string_dynamic_append_nulless(cache->action.name_item, &entry->items.array[at].name); + + if (F_status_is_error(status)) { + controller_print_error(main->thread, &main->program.error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true); + + break; + } + + status = controller_entry_actions_read(main, cache, is_entry, *range, &entry->items.array[at].actions); + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) != F_interrupt) { + controller_lock_print(main->program.error.to, &main->thread); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + if (F_status_set_fine(status) == F_memory_not) break; + } + } // for + + if (is_entry && F_status_set_fine(status) == F_interrupt) return status; + + if (F_status_is_error_not(status)) { + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; + + if (!(code & 0x1)) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fl_print_format("%r%[%QThe required %r item '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, is_entry ? controller_entry_s : controller_exit_s, main->program.error.context); + fl_print_format(f_string_format_r_single_s.string, main->program.error.to, main->program.error.notable, controller_main_s, main->program.error.notable); + fl_print_format("%[' is not found.%]%r", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + status = F_status_set_error(F_found_not); + } + + if (F_status_is_error_not(status)) { + controller_entry_action_t *action = 0; + + f_number_unsigned_t k = 0; + + // 0x1 = missing or not, 0x2 = one or more missing. + uint8_t missing = 0; + + for (i = 0; i < entry->items.used; ++i) { + + for (j = 0; j < entry->items.array[i].actions.used; ++j) { + + if (!controller_thread_is_enabled(is_entry, &main->thread)) { + return F_status_set_error(F_interrupt); + } + + action = &entry->items.array[i].actions.array[j]; + + // Only process actions that don't already have an error. + if (F_status_is_error(action->status)) continue; + + if (action->type == controller_entry_action_type_failsafe_e || action->type == controller_entry_action_type_item_e) { + missing |= 0x1; + + for (k = 0; k < entry->items.used; ++k) { + + if (f_compare_dynamic(action->parameters.array[0], entry->items.array[k].name) == F_equal_to) { + missing &= ~0x1; + + break; + } + } // for + + if (missing & 0x1) { + missing |= 0x2; + + cache->action.line_action = action->line; + cache->action.line_item = entry->items.array[i].line; + + status = f_string_dynamic_append_nulless(entry->items.array[i].name, &cache->action.name_item); + + if (F_status_is_error(status)) { + controller_print_error(main->thread, &main->program.error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true); + + break; + } + + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fl_print_format("%r%[%QThe required %r item '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, is_entry ? controller_entry_s : controller_exit_s, main->program.error.context); + fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, action->parameters.array[0], main->program.error.notable); + fl_print_format("%[' does not exist.%]%r", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + action->number = 0; + action->status = controller_status_simplify_error(F_found_not); + + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; + } + else { + action->number = k; + } + } + } // for + } // for + } + } + } + } + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) != F_interrupt) { + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + } + + entry->status = controller_status_simplify_error(F_status_set_fine(status)); + } + else { + entry->status = F_okay; + } + + return entry->status; + } +#endif // _di_controller_entry_read_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/entry.h b/sources/c/main/entry.h new file mode 100644 index 0000000..a9d340d --- /dev/null +++ b/sources/c/main/entry.h @@ -0,0 +1,75 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides entry functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_entry_h +#define _controller_entry_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Read the entry, extracting all lists. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param cache + * The cache for the specific thread. + * This should be the cache global.thread->asynchronouss.array[global.id].cache. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * + * @return + * F_okay on success. + * F_file_found_not on file not found for a an exit file (is_entry is FALSE). + * + * Errors (with error bit) from: controller_entry_actions_read(). + * Errors (with error bit) from: controller_entry_items_increase_by(). + * Errors (with error bit) from: controller_file_load(). + * Errors (with error bit) from: controller_status_simplify_error(). + * + * Errors (with error bit) from: f_fss_count_lines(). + * Errors (with error bit) from: f_string_dynamic_append(). + * Errors (with error bit) from: f_string_dynamic_append_nulless(). + * Errors (with error bit) from: f_string_dynamic_partial_append(). + * Errors (with error bit) from: f_string_dynamic_partial_append_nulless(). + * Errors (with error bit) from: f_string_dynamic_terminate(). + * Errors (with error bit) from: f_fss_apply_delimit(). + * Errors (with error bit) from: fll_fss_basic_list_read(). + * + * @see controller_entry_actions_read() + * @see controller_entry_items_increase_by() + * @see controller_file_load() + * @see controller_status_simplify_error() + * + * @see f_fss_count_lines() + * @see f_string_dynamic_append() + * @see f_string_dynamic_append_nulless() + * @see f_string_dynamic_partial_append() + * @see f_string_dynamic_partial_append_nulless() + * @see f_string_dynamic_terminate() + * @see f_fss_apply_delimit() + * @see fll_fss_basic_list_read() + */ +#ifndef _di_controller_entry_read_ + extern f_status_t controller_entry_read(controller_t * const main, controller_cache_t * const cache, const uint8_t is_entry); +#endif // _di_controller_entry_read_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_entry_h diff --git a/sources/c/main/entry/action.c b/sources/c/main/entry/action.c new file mode 100644 index 0000000..e69de29 diff --git a/sources/c/main/entry/action.h b/sources/c/main/entry/action.h new file mode 100644 index 0000000..e69de29 diff --git a/sources/c/main/entry/preprocess.c b/sources/c/main/entry/preprocess.c new file mode 100644 index 0000000..dc6e3ea --- /dev/null +++ b/sources/c/main/entry/preprocess.c @@ -0,0 +1,242 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_entry_preprocess_ + f_status_t controller_entry_preprocess(controller_t * const main, const uint8_t is_entry) { + + f_status_t status = F_okay; + f_status_t status2 = F_okay; + + f_number_unsigned_t i = 0; + f_number_unsigned_t j = 0; + + f_number_unsigned_t at_i = 0; + f_number_unsigned_t at_j = 1; + + controller_entry_t * const entry = is_entry ? &main->process.entry : &main->process.exit; + controller_cache_t * const cache = &main->thread.cache; + controller_entry_actions_t *actions = 0; + + uint8_t error_has = F_false; + + // This effectively sets the read for an entry and resets the ready for an exit. + main->setting.ready = controller_setting_ready_no_e; + + cache->ats.used = 0; + + cache->action.line_action = 0; + cache->action.line_item = 0; + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; + + status = f_memory_array_increase(controller_common_allocation_small_d, sizeof(f_number_unsigned_t), (void **) &cache->ats.array, &cache->ats.used, &cache->ats.size); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(f_memory_array_increase), F_true); + + return status; + } + + // Utilize the ats cache as an item execution stack (at_i is for item index, and at_j (at_i + 1) is for action index). + cache->ats.array[0] = 0; + cache->ats.array[1] = 0; + cache->ats.used = 2; + + cache->action.line_item = entry->items.array[0].line; + cache->action.name_item.used = 0; + + status = f_string_dynamic_append_nulless(entry->items.array[0].name, &cache->action.name_item); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(f_string_dynamic_append_nulless), F_true); + + return status; + } + + while (controller_thread_is_enabled(is_entry, &main->thread)) { + + actions = &entry->items.array[cache->ats.array[at_i]].actions; + + for (; cache->ats.array[at_j] < actions->used && controller_thread_is_enabled(is_entry, &main->thread); ++cache->ats.array[at_j]) { + + cache->action.line_action = actions->array[cache->ats.array[at_j]].line; + cache->action.name_action.used = 0; + + status2 = f_string_dynamic_append_nulless(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->action.name_action); + + if (F_status_is_error(status2)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status2), macro_controller_f(f_string_dynamic_append_nulless), F_true); + + return status2; + } + + if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_ready_e) { + + if (main->setting.ready == controller_setting_ready_wait_e) { + if (main->program.warning.verbosity == f_console_verbosity_debug_e) { + controller_lock_print(main->program.warning.to, &main->thread); + + fl_print_format("%r%[%QMultiple '%]", main->program.warning.to, f_string_eol_s, main->program.warning.context, main->program.warning.prefix, main->program.warning.context); + fl_print_format(f_string_format_r_single_s.string, main->program.warning.to, main->program.warning.notable, controller_ready_s, main->program.warning.notable); + fl_print_format("%[' %r item actions detected; only the first will be used.%]%r", main->program.warning.to, main->program.warning.context, is_entry ? controller_entry_s : controller_exit_s, main->program.warning.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.warning, cache->action); + + controller_unlock_print_flush(main->program.warning.to, &main->thread); + } + } + else { + main->setting.ready = controller_setting_ready_wait_e; + } + } + else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item_e) { + error_has = F_false; + + // "main" is not allowed to be used for an "item" and "setting" is not an executable "item". + if (f_compare_dynamic(controller_main_s, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) { + continue; + } + else if (f_compare_dynamic(controller_settings_s, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) { + continue; + } + + // Walk though each items and check to see if the item actually exists. + for (i = 1; i < entry->items.used && controller_thread_is_enabled(is_entry, &main->thread); ++i) { + + if (f_compare_dynamic(entry->items.array[i].name, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) { + + // Check to see if "i" is already in the stack (to prevent recursion) (skipping main). + for (j = 2; j < cache->ats.used; j += 2) { + + if (cache->ats.array[j] == i) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fl_print_format("%r%[%QThe %r item named '%]", main->program.error.to, f_string_eol_s, main->program.error.context, is_entry ? controller_entry_s : controller_exit_s, main->program.error.prefix, main->program.error.context); + fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, entry->items.array[i].name, main->program.error.notable); + fl_print_format("%[' cannot be executed because recursion is not allowed.%]%r", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + if (F_status_is_error_not(status)) { + status = F_status_set_error(F_recurse); + } + + error_has = F_true; + + break; + } + } // for + + if (error_has) break; + + status2 = f_memory_array_increase(controller_common_allocation_small_d, sizeof(f_number_unsigned_t), (void **) &cache->ats.array, &cache->ats.used, &cache->ats.size); + + if (F_status_is_error(status2)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status2), macro_controller_f(f_memory_array_increase), F_true); + + return status2; + } + + // Save the value so to avoid string comparison during normal operation. + actions->array[cache->ats.array[at_j]].number = i; + + // Continue into the requested item. + at_i = cache->ats.used; + at_j = cache->ats.used + 1; + + cache->ats.array[at_i] = i; + cache->ats.array[at_j] = 0; + cache->ats.used += 2; + + cache->action.name_action.used = 0; + cache->action.line_action = 0; + + cache->action.name_item.used = 0; + cache->action.line_item = entry->items.array[i].line; + + status2 = f_string_dynamic_append_nulless(entry->items.array[i].name, &cache->action.name_item); + + if (F_status_is_error(status2)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status2), macro_controller_f(f_string_dynamic_append_nulless), F_true); + + return status2; + } + + break; + } + } // for + + if (error_has || i >= entry->items.used) { + if (i >= entry->items.used) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fl_print_format("%r%[%QThe %r item named '%]", main->program.error.to, f_string_eol_s, main->program.error.context, is_entry ? controller_entry_s : controller_exit_s, main->program.error.prefix, main->program.error.context); + fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, actions->array[cache->ats.array[at_j]].parameters.array[0], main->program.error.notable); + fl_print_format("%[' does not exist.%]%r", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + if (F_status_is_error_not(status)) { + status = F_status_set_error(F_valid_not); + } + } + } + else { + break; + } + } + } // for + + cache->action.line_action = 0; + cache->action.name_action.used = 0; + + // End of actions found, so drop to previous loop in stack. + if (cache->ats.array[at_j] == actions->used) { + + // All actions for "main" are processed so there is nothing left to do. + if (at_i == 0) break; + + at_i -= 2; + at_j -= 2; + + cache->ats.used -= 2; + ++cache->ats.array[at_j]; + + cache->action.line_item = entry->items.array[cache->ats.array[at_i]].line; + cache->action.name_item.used = 0; + + status2 = f_string_dynamic_append_nulless(entry->items.array[cache->ats.array[at_i]].name, &cache->action.name_item); + + if (F_status_is_error(status2)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status2), macro_controller_f(f_string_dynamic_append_nulless), F_true); + + return status2; + } + } + } // while + + if (!controller_thread_is_enabled(is_entry, &main->thread)) return F_status_set_error(F_interrupt); + + // If ready was never found in the entry, then default to always ready. + if (main->setting.ready == controller_setting_ready_no_e) { + main->setting.ready = controller_setting_ready_yes_e; + } + + return status; + } +#endif // _di_controller_entry_preprocess_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/entry/preprocess.h b/sources/c/main/entry/preprocess.h new file mode 100644 index 0000000..d3f02f5 --- /dev/null +++ b/sources/c/main/entry/preprocess.h @@ -0,0 +1,52 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the entry pre-process functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_entry_preprocess_h +#define _controller_main_entry_preprocess_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Pre-process all items for the loaded entry. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this operate as an entry. + * If FALSE, then this operate as an exit. + * + * @return + * F_okay on success. + * F_recurse (with error bit) on a recursion error. + * F_valid_not (with error bit) on invalid entry item, entry item action, or entry item action value. + * + * Errors (with error bit) from: macro_f_number_unsigneds_t_increase_by(). + * Errors (with error bit) from: f_string_dynamic_append(). + * + * This will detect and report all errors, but only the first error is returned. + * Memory related errors return immediately. + + * @see macro_f_number_unsigneds_t_increase_by() + * @see f_string_dynamic_append() + */ +#ifndef _di_controller_entry_preprocess_ + extern f_status_t controller_entry_preprocess(controller_t * const main, const uint8_t is_entry); +#endif // _di_controller_entry_preprocess_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_entry_preprocess_h diff --git a/sources/c/main/entry/process.c b/sources/c/main/entry/process.c new file mode 100644 index 0000000..164a36f --- /dev/null +++ b/sources/c/main/entry/process.c @@ -0,0 +1,686 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_entry_process_ + f_status_t controller_entry_process(controller_t * const main, const bool failsafe, const uint8_t is_entry) { + + f_status_t status = F_okay; + f_status_t status_lock = F_okay; + + f_number_unsigned_t at_i = 0; + f_number_unsigned_t at_j = 1; + + uint8_t options_force = 0; + uint8_t options_process = 0; + + controller_entry_t * const entry = is_entry ? &main->process.entry : &main->process.exit; + controller_cache_t * const cache = &main->thread.cache; + controller_entry_action_t *entry_action = 0; + controller_entry_actions_t *entry_actions = 0; + + // An empty stack is used here because each rule here is the first rule run in the rule's scope. + const f_number_unsigneds_t stack = f_number_unsigneds_t_initialize; + + cache->ats.used = 0; + cache->stack.used = 0; + + cache->action.line_action = 0; + cache->action.line_item = 0; + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; + + status = f_memory_array_increase(controller_common_allocation_small_d, sizeof(f_number_unsigned_t), (void **) &cache->ats.array, &cache->ats.used, &cache->ats.size); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), macro_controller_f(f_memory_array_increase), F_true, &main->thread); + + return status; + } + + // utilize the ats cache as an item execution stack (at_i is for item index, and at_j (at_i + 1) is for action index). + cache->ats.array[0] = failsafe ? main->setting.failsafe_item_id : 0; + cache->ats.array[1] = 0; + cache->ats.used = 2; + + cache->action.line_item = entry->items.array[cache->ats.array[0]].line; + cache->action.name_item.used = 0; + + status = f_string_dynamic_append_nulless(entry->items.array[cache->ats.array[0]].name, &cache->action.name_item); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), macro_controller_f(f_string_dynamic_append_nulless), F_true, &main->thread); + + return status; + } + + if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) || main->program.error.verbosity == f_console_verbosity_verbose_e || main->program.error.verbosity == f_console_verbosity_debug_e) { + if ((main->program.error.verbosity > f_console_verbosity_error_e)) { + controller_lock_print(main->program.output.to, &main->thread); + + fl_print_format("%rProcessing %r%r item '", main->program.output.to, f_string_eol_s, failsafe ? controller_entry_print_failsafe_s : f_string_empty_s, is_entry ? controller_entry_s : controller_exit_s); + fl_print_format("%[%Q%]'.%r", main->program.output.to, main->program.context.set.title, cache->action.name_item, main->program.context.set.notable, f_string_eol_s); + + controller_unlock_print_flush(main->program.output.to, &main->thread); + } + } + + // The pre-process determines if ready is explicitly specified within the entry file and if it is not start as ready. + if (main->setting.ready == controller_setting_ready_yes_e) { + status = controller_perform_ready(main, is_entry); + if (F_status_is_error(status)) return status; + } + + while (controller_thread_is_enabled(is_entry, &main->thread)) { + + entry_actions = &entry->items.array[cache->ats.array[at_i]].actions; + + for (; cache->ats.array[at_j] < entry_actions->used && controller_thread_is_enabled(is_entry, &main->thread); ++cache->ats.array[at_j]) { + + entry_action = &entry_actions->array[cache->ats.array[at_j]]; + + cache->action.line_action = entry_action->line; + cache->action.name_action.used = 0; + + status = f_string_dynamic_append_nulless(controller_entry_action_type_name(entry_action->type), &cache->action.name_action); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), macro_controller_f(f_string_dynamic_append_nulless), F_true, &main->thread); + + return status; + } + + if (F_status_is_error(entry_action->status)) { + if (main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.output.to, &main->thread); + + fl_print_format("%rThe %r item action '", main->program.output.to, f_string_eol_s, is_entry ? controller_entry_s : controller_exit_s); + fl_print_format(f_string_format_Q_single_s.string, main->program.output.to, main->program.context.set.title, cache->action.name_action, main->program.context.set.title); + + if (entry_action->parameters.used) { + fl_print_format(" %[", main->program.output.to, main->program.context.set.notable); + + controller_entry_action_parameters_print(&main->program.output, *entry_action); + + fl_print_format("%]", main->program.output.to, main->program.context.set.notable); + } + + fl_print_format("' is %[%r%] and is in a ", main->program.output.to, main->program.context.set.notable, entry_action->code & controller_entry_rule_code_require_d ? "required" : "optional", main->program.context.set.notable); + + fl_print_format("%[failed%] state, skipping.%r", main->program.output.to, main->program.context.set.notable, main->program.context.set.notable, main->program.context.set.notable, f_string_eol_s); + + controller_unlock_print_flush(main->program.output.to, &main->thread); + } + } + else { + if ((entry_action->code & controller_entry_rule_code_require_d) && main->program.error.verbosity > f_console_verbosity_quiet_e || !(entry_action->code & controller_entry_rule_code_require_d) && (main->program.warning.verbosity == f_console_verbosity_verbose_e || main->program.warning.verbosity == f_console_verbosity_debug_e)) { + fl_print_t *print = 0; + + if (entry_action->code & controller_entry_rule_code_require_d) { + print = &main->program.error; + } + else if (main->program.error.verbosity != f_console_verbosity_error_e) { + print = &main->program.warning; + } + + if (print) { + controller_lock_print(print->to, &main->thread); + + fl_print_format("%r%[%QThe %r item action '%]", print->to, f_string_eol_s, print->context, print->prefix, is_entry ? controller_entry_s : controller_exit_s, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, cache->action.name_action, print->notable); + + + if (entry_action->parameters.used) { + fl_print_format(" %[", print->to, main->program.context.set.notable); + + controller_entry_action_parameters_print(print, *entry_action); + + fl_print_format("%]", print->to, main->program.context.set.notable); + } + + if (entry_action->code & controller_entry_rule_code_require_d) { + fl_print_format("%[' is%] %[required%]", print->to, print->context, print->context, print->notable, print->notable); + } + else { + fl_print_format("%[' is%] %[optional%]", print->to, print->context, print->context, print->notable, print->notable); + } + + fl_print_format(" %[and is in a%] %[failed%]", print->to, print->context, print->context, print->notable, print->notable); + + if (entry_action->code & controller_entry_rule_code_require_d) { + fl_print_format(" %[state, aborting.%]%r", print->to, print->context, print->context, f_string_eol_s); + } + else { + fl_print_format(" %[state, skipping.%]%r", print->to, print->context, print->context, f_string_eol_s); + } + + controller_entry_print_error_cache(is_entry, print, cache->action); + + controller_unlock_print_flush(print->to, &main->thread); + } + } + + if (controller_entry_action_type_is_rule(entry_action->type) && entry_action->code & controller_entry_rule_code_require_d) { + return F_status_is_error(F_require); + } + } + + continue; + } + + if (entry_action->type == controller_entry_action_type_ready_e) { + if ((entry_action->code & controller_entry_rule_code_wait_d) || main->setting.ready == controller_setting_ready_wait_e) { + if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) || main->program.error.verbosity == f_console_verbosity_verbose_e || main->program.error.verbosity == f_console_verbosity_debug_e || entry->show == controller_entry_show_init_e) { + if (main->program.output.verbosity != f_console_verbosity_quiet_e && main->program.error.verbosity != f_console_verbosity_error_e) { + controller_lock_print(main->program.output.to, &main->thread); + + fl_print_format("%rWaiting before processing %r item action '", main->program.output.to, f_string_eol_s, is_entry ? controller_entry_s : controller_exit_s); + fl_print_format(f_string_format_r_single_s.string, main->program.output.to, main->program.context.set.title, controller_ready_s, main->program.context.set.title); + fl_print_format("'.%r", main->program.output.to, f_string_eol_s); + + controller_unlock_print_flush(main->program.output.to, &main->thread); + } + } + + if (!(main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) { + status = controller_rule_wait_all(main, is_entry, F_false); + if (F_status_is_error(status)) return status; + } + } + + if (main->setting.ready == controller_setting_ready_yes_e) { + if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) || main->program.error.verbosity == f_console_verbosity_verbose_e || main->program.error.verbosity == f_console_verbosity_debug_e) { + if (main->program.output.verbosity != f_console_verbosity_quiet_e && main->program.error.verbosity != f_console_verbosity_error_e) { + controller_lock_print(main->program.output.to, &main->thread); + + fl_print_format("%rIgnoring %r item action '", main->program.output.to, f_string_eol_s, is_entry ? controller_entry_s : controller_exit_s); + fl_print_format(f_string_format_r_single_s.string, main->program.output.to, main->program.context.set.title, controller_ready_s, main->program.context.set.title); + fl_print_format("', state already is ready.%r", main->program.output.to, f_string_eol_s); + + controller_unlock_print_flush(main->program.output.to, &main->thread); + } + } + } + else { + if (!failsafe && (main->program.error.verbosity == f_console_verbosity_verbose_e || entry->show == controller_entry_show_init_e) && !(main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) { + if (main->program.error.verbosity > f_console_verbosity_error_e) { + fl_print_format("%rState is now '%[%r%]'.%r", main->program.output.to, f_string_eol_s, main->program.context.set.notable, controller_ready_s, main->program.context.set.notable, f_string_eol_s); + } + } + + status = controller_perform_ready(main, is_entry); + if (F_status_is_error(status)) return status; + } + } + else if (entry_action->type == controller_entry_action_type_item_e) { + if (entry_action->number == 0 || entry_action->number >= entry->items.used || failsafe && entry_action->number == main->setting.failsafe_item_id) { + + // This should not happen if the pre-process is working as intended, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors. + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fl_print_format("%r%[Invalid %r item index '%]", main->program.error.to, f_string_eol_s, main->program.error.context, is_entry ? controller_entry_s : controller_exit_s, main->program.error.context); + fl_print_format("%[%un%]", main->program.error.to, main->program.error.notable, entry_action->number, main->program.error.notable); + fl_print_format("%[' detected.%]%r", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + return F_status_is_error(F_critical); + } + + status = f_memory_array_increase(controller_common_allocation_small_d, sizeof(f_number_unsigned_t), (void **) &cache->ats.array, &cache->ats.used, &cache->ats.size); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), macro_controller_f(f_memory_array_increase), F_true, &main->thread); + + return status; + } + + // continue into the requested item. + cache->ats.array[cache->ats.used] = entry_action->number; + cache->ats.array[cache->ats.used + 1] = 0; + + at_i = cache->ats.used; + at_j = cache->ats.used + 1; + + cache->ats.used += 2; + + cache->action.name_action.used = 0; + cache->action.line_action = 0; + + cache->action.name_item.used = 0; + cache->action.line_item = entry->items.array[cache->ats.array[at_i]].line; + + status = f_string_dynamic_append_nulless(entry->items.array[cache->ats.array[at_i]].name, &cache->action.name_item); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), macro_controller_f(f_string_dynamic_append_nulless), F_true, &main->thread); + + return status; + } + + if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) || main->program.error.verbosity == f_console_verbosity_verbose_e || main->program.error.verbosity == f_console_verbosity_debug_e) { + if (main->program.output.verbosity != f_console_verbosity_quiet_e && main->program.error.verbosity != f_console_verbosity_error_e) { + controller_lock_print(main->program.output.to, &main->thread); + + fl_print_format("%rProcessing %r item '", main->program.output.to, f_string_eol_s, is_entry ? controller_entry_s : controller_exit_s); + fl_print_format(f_string_format_Q_single_s.string, main->program.output.to, main->program.context.set.title, cache->action.name_item, main->program.context.set.title); + fl_print_format("'.%r", main->program.output.to, f_string_eol_s); + + controller_unlock_print_flush(main->program.output.to, &main->thread); + } + } + + // Exit inner loop to force restarting and start processing the requested item. + break; + } + else if (entry_action->type == controller_entry_action_type_consider_e || controller_entry_action_type_is_rule(entry_action->type)) { + status_lock = controller_lock_write(is_entry, &main->thread, &main->thread.lock.rule); + + if (F_status_is_error(status_lock)) { + controller_lock_print_error_critical(&main->program.error, F_status_set_fine(status_lock), F_false, &main->thread); + + break; + } + + status = controller_rules_increase(&main->setting.rules); + + f_thread_unlock(&main->thread.lock.rule); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), macro_controller_f(controller_rules_increase), F_true, &main->thread); + + return status; + } + + const f_number_unsigned_t id_rule_length = entry_action->parameters.array[0].used + entry_action->parameters.array[1].used + 1; + f_char_t id_rule_name[id_rule_length + 1]; + const f_string_static_t alias_rule = macro_f_string_static_t_initialize_1(id_rule_name, 0, id_rule_length); + + memcpy(id_rule_name, entry_action->parameters.array[0].string, sizeof(f_char_t) * entry_action->parameters.array[0].used); + memcpy(id_rule_name + entry_action->parameters.array[0].used + 1, entry_action->parameters.array[1].string, sizeof(f_char_t) * entry_action->parameters.array[1].used); + + id_rule_name[entry_action->parameters.array[0].used] = f_path_separator_s.string[0]; + id_rule_name[id_rule_length] = 0; + + status_lock = controller_lock_read(is_entry, &main->thread, &main->thread.lock.rule); + + if (F_status_is_error(status_lock)) { + controller_lock_print_error_critical(&main->program.error, F_status_set_fine(status_lock), F_true, &main->thread); + + break; + } + + status = controller_rule_find(alias_rule, main->setting.rules, 0); + + f_thread_unlock(&main->thread.lock.rule); + + if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) || main->program.error.verbosity == f_console_verbosity_verbose_e || main->program.error.verbosity == f_console_verbosity_debug_e || (entry->show == controller_entry_show_init_e && entry_action->type != controller_entry_action_type_consider_e)) { + if (main->program.output.verbosity != f_console_verbosity_quiet_e && main->program.error.verbosity != f_console_verbosity_error_e) { + controller_lock_print(main->program.output.to, &main->thread); + + fl_print_format("%r%r %r item rule ", main->program.output.to, f_string_eol_s, entry_action->type == controller_entry_action_type_consider_e ? controller_entry_print_considering_s : controller_entry_print_processing_s, is_entry ? controller_entry_s : controller_exit_s); + fl_print_format("'%[%Q%]'", main->program.output.to, main->program.context.set.title, alias_rule, main->program.context.set.title); + + if (entry->show == controller_entry_show_init_e && !(main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) { + fl_print_format(" [%[%r%]]", main->program.output.to, main->program.context.set.notable, entry_action->code == controller_entry_rule_code_asynchronous_d ? controller_asynchronous_s : controller_synchronous_s, main->program.context.set.notable); + + if (entry_action->code == controller_entry_rule_code_wait_d) { + fl_print_format(" [%[%r%]]", main->program.output.to, main->program.context.set.notable, controller_wait_s, main->program.context.set.notable); + } + + if (entry_action->code == controller_entry_rule_code_require_d) { + fl_print_format(" [%[%r%]]", main->program.output.to, main->program.context.set.notable, controller_required_s, main->program.context.set.notable); + } + } + + fl_print_format(".%r", main->program.output.to, f_string_eol_s); + + controller_unlock_print_flush(main->program.output.to, &main->thread); + } + } + + if (!controller_thread_is_enabled(is_entry, &main->thread)) break; + + // The rule is not yet loaded, ensure that it is loaded. + if (status != F_true) { + + // Rule execution will re-use the existing cache, so save the current cache. + const f_number_unsigned_t cache_line_action = cache->action.line_action; + const f_number_unsigned_t cache_line_item = cache->action.line_item; + + const f_number_unsigned_t cache_name_action_used = cache->action.name_action.used; + const f_number_unsigned_t cache_name_item_used = cache->action.name_item.used; + const f_number_unsigned_t cache_name_file_used = cache->action.name_file.used; + + f_char_t cache_name_action[cache_name_action_used]; + f_char_t cache_name_item[cache_name_item_used]; + f_char_t cache_name_file[cache_name_file_used]; + + memcpy(cache_name_action, cache->action.name_action.string, sizeof(f_char_t) * cache->action.name_action.used); + memcpy(cache_name_item, cache->action.name_item.string, sizeof(f_char_t) * cache->action.name_item.used); + memcpy(cache_name_file, cache->action.name_file.string, sizeof(f_char_t) * cache->action.name_file.used); + + status_lock = controller_lock_write(is_entry, &main->thread, &main->thread.lock.rule); + + if (F_status_is_fine(status_lock)) { + status = controller_rule_read(main, is_entry, alias_rule, cache, entry, &main->setting.rules.array[main->setting.rules.used]); + } + + // Restore cache. + memcpy(cache->action.name_action.string, cache_name_action, sizeof(f_char_t) * cache_name_action_used); + memcpy(cache->action.name_item.string, cache_name_item, sizeof(f_char_t) * cache_name_item_used); + memcpy(cache->action.name_file.string, cache_name_file, sizeof(f_char_t) * cache_name_file_used); + + cache->action.name_action.string[cache_name_action_used] = 0; + cache->action.name_item.string[cache_name_item_used] = 0; + cache->action.name_file.string[cache_name_file_used] = 0; + + cache->action.name_action.used = cache_name_action_used; + cache->action.name_item.used = cache_name_item_used; + cache->action.name_file.used = cache_name_file_used; + + cache->action.line_action = cache_line_action; + cache->action.line_item = cache_line_item; + + if (F_status_is_error(status_lock)) { + controller_lock_print_error_critical(&main->program.error, F_status_set_fine(status_lock), F_false, &main->thread); + + break; + } + + if (F_status_set_fine(status) == F_interrupt || !controller_thread_is_enabled(is_entry, &main->thread)) { + f_thread_unlock(&main->thread.lock.rule); + + break; + } + + if (F_status_is_error(status)) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + // Designate the action as failed. + entry_action->status = F_status_set_error(F_failure); + + if (!(main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) { + f_thread_unlock(&main->thread.lock.rule); + + if (entry_action->code & controller_entry_rule_code_require_d) { + return F_status_set_error(F_require); + } + + ++cache->ats.array[at_j]; + + break; + } + } + else { + ++main->setting.rules.used; + } + + f_thread_unlock(&main->thread.lock.rule); + } + + if (F_status_is_error_not(status)) { + options_force = 0; + options_process = 0; + + if (main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) { + options_process |= controller_process_option_simulate_d; + } + + if (entry_action->code & controller_entry_rule_code_require_d) { + options_process |= controller_process_option_require_d; + } + + if (entry_action->code & controller_entry_rule_code_wait_d) { + options_process |= controller_process_option_wait_d; + } + + if (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) { + options_process |= controller_process_option_validate_d; + } + + if (entry_action->code & controller_entry_rule_code_asynchronous_d) { + if (!(main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) { + options_force |= controller_process_option_asynchronous_d; + } + + options_process |= controller_process_option_asynchronous_d; + } + + status = controller_rule_process_begin(main, options_force, alias_rule, controller_entry_action_type_to_rule_action_type(entry_action->type), options_process, is_entry ? controller_data_type_entry_e : controller_data_type_exit_e, stack, *cache); + + if (F_status_set_fine(status) == F_memory_not || status == F_child || F_status_set_fine(status) == F_interrupt) { + break; + } + + if (F_status_is_error(status) && !(main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && (entry_action->code & controller_entry_rule_code_require_d)) { + return F_status_set_error(F_require); + } + } + } + else if (entry_action->type == controller_entry_action_type_execute_e) { + if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) || main->program.error.verbosity == f_console_verbosity_verbose_e || main->program.error.verbosity == f_console_verbosity_debug_e || entry->show == controller_entry_show_init_e) { + if (main->program.output.verbosity != f_console_verbosity_quiet_e && main->program.error.verbosity != f_console_verbosity_error_e) { + controller_lock_print(main->program.output.to, &main->thread); + + fl_print_format("%r%Q is executing '", main->program.output.to, f_string_eol_s, is_entry ? controller_entry_s : controller_exit_s); + + for (f_number_unsigned_t k = 0; k < entry_action->parameters.used; ++k) { + + fl_print_format(f_string_format_Q_single_s.string, main->program.output.to, main->program.context.set.title, entry_action->parameters.array[k], main->program.context.set.title); + + if (k + 1 < entry_action->parameters.used) { + f_print_dynamic_raw(f_string_space_s, main->program.output.to); + } + } // for + + fl_print_format("'.%r", main->program.output.to, f_string_eol_s); + + controller_unlock_print_flush(main->program.output.to, &main->thread); + } + } + + if (main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) return F_execute; + + controller_thread_process_cancel(main, is_entry, is_entry ? controller_thread_cancel_execute_e : controller_thread_cancel_exit_execute_e); + + int result = 0; + int option = FL_execute_parameter_option_path_d; + + if (entry->session == controller_entry_session_new_e) { + option |= FL_execute_parameter_option_session_d; + } + + status = fll_execute_into(f_string_empty_s, entry_action->parameters, option, 0, (void *) &result); + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_file_found_not) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fl_print_format("%r%[%QExecution failed, unable to find program or script '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, main->program.error.context); + fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, entry_action->parameters.array[0], main->program.error.notable); + fl_print_format(f_string_format_sentence_end_quote_s.string, main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + } + else { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), macro_controller_f(fll_execute_into), F_true, &main->thread); + } + + return F_status_set_error(F_execute); + } + else if (result != 0) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fl_print_format("%r%[%QExecution failed with return value of '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, main->program.error.context); + fl_print_format("%[%i%]", main->program.error.to, main->program.error.notable, result, main->program.error.notable); + fl_print_format("$['.%]%r", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + return F_status_set_error(F_execute); + } + + return F_execute; + } + else if (entry_action->type == controller_entry_action_type_timeout_e) { + if (entry_action->code == controller_entry_timeout_code_exit_d) { + entry->timeout_exit = entry_action->number; + + controller_entry_preprocess_print_simulate_setting_value(main, is_entry, controller_timeout_s, controller_exit_s, entry->items.array[main->setting.failsafe_item_id].name, controller_entry_print_suffix_megatime_s); + } + else if (entry_action->code == controller_entry_timeout_code_kill_d) { + entry->timeout_kill = entry_action->number; + + controller_entry_preprocess_print_simulate_setting_value(main, is_entry, controller_timeout_s, controller_kill_s, entry->items.array[main->setting.failsafe_item_id].name, controller_entry_print_suffix_megatime_s); + } + else if (entry_action->code == controller_entry_timeout_code_start_d) { + entry->timeout_start = entry_action->number; + + controller_entry_preprocess_print_simulate_setting_value(main, is_entry, controller_timeout_s, controller_start_s, entry->items.array[main->setting.failsafe_item_id].name, controller_entry_print_suffix_megatime_s); + } + else if (entry_action->code == controller_entry_timeout_code_stop_d) { + entry->timeout_stop = entry_action->number; + + controller_entry_preprocess_print_simulate_setting_value(main, is_entry, controller_timeout_s, controller_stop_s, entry->items.array[main->setting.failsafe_item_id].name, controller_entry_print_suffix_megatime_s); + } + } + else if (entry_action->type == controller_entry_action_type_failsafe_e) { + + if (failsafe) { + if (main->program.warning.verbosity == f_console_verbosity_debug_e) { + controller_lock_print(main->program.warning.to, &main->thread); + + fl_print_format("%r%[%QFailsafe may not be specified when running in failsafe, ignoring.%]%r", main->program.warning.to, f_string_eol_s, main->program.warning.context, main->program.warning.prefix, main->program.warning.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.warning, cache->action); + + controller_unlock_print_flush(main->program.warning.to, &main->thread); + } + } + else { + if (entry_action->number == 0 || entry_action->number >= entry->items.used) { + + // This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors. + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fl_print_format("%r%[%QInvalid %r item index '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, is_entry ? controller_entry_s : controller_exit_s, main->program.error.context); + fl_print_format("%[%un%]", main->program.error.to, main->program.error.notable, entry_action->number, main->program.error.notable); + fl_print_format("%[' detected.%]%r", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + } + + return F_status_is_error(F_critical); + } + else { + main->setting.flag |= controller_setting_flag_failsafe_e; + main->setting.failsafe_item_id = entry_action->number; + + controller_entry_preprocess_print_simulate_setting_value(main, is_entry, controller_failsafe_s, f_string_empty_s, entry->items.array[main->setting.failsafe_item_id].name, f_string_empty_s); + } + } + } + } // for + + if (status == F_child || F_status_set_fine(status) == F_interrupt) break; + + cache->action.line_action = 0; + cache->action.name_action.used = 0; + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_require) { + break; + } + } + + // End of actions found, so drop to previous loop in stack. + if (cache->ats.array[at_j] == entry_actions->used) { + + // All actions for "main" are processed so there is nothing left to do. + if (at_i == 0) break; + + at_i -= 2; + at_j -= 2; + + cache->ats.used -= 2; + ++cache->ats.array[at_j]; + + cache->action.line_item = entry->items.array[cache->ats.array[at_i]].line; + cache->action.name_item.used = 0; + + status = f_string_dynamic_append_nulless(entry->items.array[cache->ats.array[at_i]].name, &cache->action.name_item); + + if (F_status_is_error(status)) { + controller_entry_print_error(is_entry, &main->program.error, cache->action, F_status_set_fine(status), macro_controller_f(f_string_dynamic_append_nulless), F_true, &main->thread); + + break; + } + } + } // while + + if (!controller_thread_is_enabled(is_entry, &main->thread)) { + return F_status_set_error(F_interrupt); + } + + if (status == F_child) { + return status; + } + + if (F_status_is_error(status_lock)) { + return status_lock; + } + + // Check to see if any required processes failed, but do not do this if already operating in failsafe. + if (F_status_is_error_not(status) && !failsafe && !(main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) && main->setting.mode != controller_setting_mode_helper_e) { + const f_status_t status_wait = controller_rule_wait_all(main, is_entry, F_true); + if (F_status_is_error(status_wait)) return status_wait; + if (status_wait == F_require) return F_status_set_error(F_require); + } + + if (((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && main->program.error.verbosity > f_console_verbosity_quiet_e) && main->program.error.verbosity != f_console_verbosity_error_e || main->program.error.verbosity == f_console_verbosity_verbose_e) { + controller_lock_print(main->program.output.to, &main->thread); + + fl_print_format("%rDone processing %r item '", main->program.output.to, f_string_eol_s, is_entry ? controller_entry_s : controller_exit_s); + fl_print_format(f_string_format_r_single_s.string, main->program.output.to, main->program.context.set.title, controller_main_s, main->program.context.set.title); + fl_print_format("'.%r", main->program.output.to, f_string_eol_s); + + // failsafe should not print the extra newline because the failure exit from controller_main should handle this. + if (!failsafe) { + f_print_dynamic_raw(f_string_eol_s, main->program.output.to); + } + + controller_unlock_print_flush(main->program.output.to, &main->thread); + } + + return status; + } +#endif // _di_controller_entry_process_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/entry/process.h b/sources/c/main/entry/process.h new file mode 100644 index 0000000..ee3b1d5 --- /dev/null +++ b/sources/c/main/entry/process.h @@ -0,0 +1,59 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the entry process functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_entry_process_h +#define _controller_main_entry_process_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Process (execute) all Items for the loaded Entry or Exit. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param failsafe + * If TRUE, operate in failsafe mode (starts at designated failsafe Item). + * If FALSE, operate in normal mode (starts at "main" Item). + * @param is_entry + * If TRUE, then this operate as an entry. + * If FALSE, then this operate as an exit. + * + * @return + * F_okay on success. + * F_execute on success and program exiting (scripts may result in this) or when execute would have been executed but is instead simulated. + * + * F_require (with error bit) if a required Item failed. + * F_critical (with error bit) on any critical error. + * F_execute (with error bit) if the "execute" Item Action failed. + * + * Errors (with error bit) from: f_string_dynamic_append_nulless(). + * + * Errors (with error bit) from: macro_f_number_unsigneds_t_increase_by(). + * Errors (with error bit) from: controller_perform_ready(). + * + * @see f_string_dynamic_append_nulless() + * + * @see macro_f_number_unsigneds_t_increase_by() + * @see controller_perform_ready() + */ +#ifndef _di_controller_entry_process_ + extern f_status_t controller_entry_process(controller_t * const main, const bool failsafe, const uint8_t is_entry); +#endif // _di_controller_entry_process_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_entry_process_h diff --git a/sources/c/main/entry/setting.c b/sources/c/main/entry/setting.c new file mode 100644 index 0000000..3ec0197 --- /dev/null +++ b/sources/c/main/entry/setting.c @@ -0,0 +1,473 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_entry_setting_read_ + f_status_t controller_entry_setting_read(controller_t * const main, controller_cache_t * const cache, const uint8_t is_entry, const f_range_t content_range) { + + f_status_t status = F_okay; + + { + controller_interrupt_t custom = macro_controller_interrupt_t_initialize_1(is_entry, main); + f_state_t state = macro_f_state_t_initialize_1(controller_common_allocation_large_d, controller_common_allocation_small_d, F_okay, 0, 0, 0, &controller_thread_signal_state_fss, 0, (void *) &custom, 0); + f_range_t range = content_range; + + fll_fss_extended_read(cache->buffer_file, &range, &cache->object_actions, &cache->content_actions, 0, 0, &cache->delimits, 0, &state); + } + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(fll_fss_extended_read), F_true); + + return status; + } + + { + f_state_t state = f_state_t_initialize; + + f_fss_apply_delimit(cache->delimits, &cache->buffer_file, &state); + } + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(f_fss_apply_delimit), F_true); + + return status; + } + + cache->delimits.used = 0; + + f_number_unsigned_t i = 0; + + controller_entry_t *entry = is_entry ? &main->setting.entry : &main->setting.exit; + f_state_t state = f_state_t_initialize; + + for (; i < cache->object_actions.used; ++i) { + + cache->action.line_action = 0; + + f_fss_count_lines(cache->buffer_file, cache->object_actions.array[i].start, &cache->action.line_action, &main->setting.state); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(f_fss_count_lines), F_true); + + break; + } + + ++cache->action.line_action; + cache->action.name_action.used = 0; + + status = f_rip_dynamic_partial_nulless(cache->buffer_file, cache->object_actions.array[i], &cache->action.name_action); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(f_rip_dynamic_partial_nulless), F_true); + + break; + } + + if (is_entry && f_compare_dynamic(controller_control_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used < 1 || cache->content_actions.array[i].used > 2) { + controller_entry_setting_read_print_setting_requires_between(main, is_entry, *cache, 1, 2); + + continue; + } + + if (cache->content_actions.array[i].used == 2) { + if (f_compare_dynamic_partial_string(controller_readonly_s.string, cache->buffer_file, controller_readonly_s.used, cache->content_actions.array[i].array[1]) == F_equal_to) { + main->setting.control.flag |= controller_control_flag_readonly_e; + } + else { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, &main->thread); + + fl_print_format("%r%[%QThe %r item setting '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, is_entry ? controller_entry_s : controller_exit_s, main->program.error.context); + fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, controller_control_s, main->program.error.notable); + fl_print_format("%[' does not support the option '%]", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + fl_print_format(f_string_format_Q_range_single_s.string, main->program.error.to, main->program.error.notable, cache->buffer_file, cache->content_actions.array[i].array[1], main->program.error.notable); + + fl_print_format(f_string_format_sentence_end_quote_s.string, main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, &main->program.error, cache->action); + + controller_unlock_print_flush(main->program.error.to, &main->thread); + + continue; + } + } + } + else { + main->setting.control.flag &= ~controller_control_flag_readonly_e; + } + + cache->action.generic.used = 0; + main->setting.path_control.used = 0; + + status = f_rip_dynamic_partial_nulless(cache->buffer_file, cache->content_actions.array[i].array[0], &cache->action.generic); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(f_rip_dynamic_partial_nulless), F_true); + + break; + } + + main->setting.path_control.used = 0; + + status = controller_path_canonical_relative(main->setting, cache->action.generic, &main->setting.path_control); + + if (F_status_is_error(status)) { + controller_entry_print_error_file(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(controller_path_canonical_relative), F_true, cache->action.generic, f_file_operation_analyze_s, fll_error_file_type_path_e); + + continue; + } + } + else if (is_entry && f_compare_dynamic(controller_control_group_s, cache->action.name_action) == F_equal_to) { + gid_t number = 0; + + status = controller_convert_group_id(cache->buffer_file, cache->content_actions.array[i].array[0], cache, &number); + + if (F_status_is_error(status)) { + status = F_status_set_fine(status); + + if (status == F_exist_not) { + controller_entry_setting_read_print_error_with_range(&main->program.error, cache, is_entry, " has an invalid group", cache->content_actions.array[i].array[0], ", because no group was found by that name"); + } + else if (status == F_number_too_large) { + controller_entry_setting_read_print_error_with_range(&main->program.error, cache, is_entry, " has an invalid group", cache->content_actions.array[i].array[0], ", because the given ID is too large"); + } + else if (status == F_number) { + controller_entry_setting_read_print_error_with_range(&main->program.error, cache, is_entry, " has an invalid group", cache->content_actions.array[i].array[0], ", because the given ID is not a valid supported number"); + } + else { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(controller_convert_group_id), F_true); + } + + continue; + } + + main->setting.control.group = number; + main->setting.control.flag |= controller_control_flag_has_group_e; + } + else if (is_entry && f_compare_dynamic(controller_control_mode_s, cache->action.name_action) == F_equal_to) { + mode_t mode = 0; + uint8_t replace = 0; + f_file_mode_t mode_file = f_file_mode_t_initialize; + + cache->action.generic.used = 0; + + status = f_rip_dynamic_partial_nulless(cache->buffer_file, cache->content_actions.array[i].array[0], &cache->action.generic); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(f_rip_dynamic_partial_nulless), F_true); + + break; + } + + status = f_file_mode_from_string(cache->action.generic, main->program.umask, &mode_file, &replace); + + if (F_status_is_error(status)) { + controller_entry_setting_read_print_error_with_range(&main->program.error, cache, is_entry, " has an unsupported mode", cache->content_actions.array[i].array[0], ", because the format is unknown or contains invalid data"); + + continue; + } + + status = f_file_mode_to_mode(mode_file, &mode); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(f_file_mode_to_mode), F_true); + + continue; + } + + main->setting.control.mode = mode; + main->setting.control.flag |= controller_control_flag_has_mode_e; + } + else if (is_entry && f_compare_dynamic(controller_control_user_s, cache->action.name_action) == F_equal_to) { + uid_t number = 0; + + status = controller_convert_user_id(cache->buffer_file, cache->content_actions.array[i].array[0], cache, &number); + + if (F_status_is_error(status)) { + status = F_status_set_fine(status); + + if (status == F_exist_not) { + controller_entry_setting_read_print_error_with_range(&main->program.error, cache, is_entry, " has an invalid user", cache->content_actions.array[i].array[0], ", because no user was found by that name"); + } + else if (status == F_number_too_large) { + controller_entry_setting_read_print_error_with_range(&main->program.error, cache, is_entry, " has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is too large"); + } + else if (status == F_number) { + controller_entry_setting_read_print_error_with_range(&main->program.error, cache, is_entry, " has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is not a valid supported number"); + } + else { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(controller_convert_user_id), F_true); + } + + continue; + } + + main->setting.control.user = number; + main->setting.control.flag |= controller_control_flag_has_user_e; + } + else if (f_compare_dynamic(controller_define_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used != 2) { + controller_entry_setting_read_print_setting_requires_exactly(main, is_entry, *cache, 2); + + continue; + } + + status = controller_entry_setting_read_map(cache->buffer_file, cache->content_actions.array[i], &entry->define); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(controller_entry_setting_read_map), F_true); + + continue; + } + } + else if (is_entry && f_compare_dynamic(controller_mode_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used != 1) { + controller_entry_setting_read_print_setting_requires_exactly(main, is_entry, *cache, 1); + + continue; + } + + if (f_compare_dynamic_partial_string(controller_service_s.string, cache->buffer_file, controller_service_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + main->setting.mode = controller_setting_mode_service_e; + } + else if (f_compare_dynamic_partial_string(controller_helper_s.string, cache->buffer_file, controller_helper_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + main->setting.mode = controller_setting_mode_helper_e; + } + else if (f_compare_dynamic_partial_string(controller_program_s.string, cache->buffer_file, controller_program_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + main->setting.mode = controller_setting_mode_program_e; + } + else { + controller_entry_setting_read_print_setting_unknown_action_value(main, is_entry, *cache, i); + + continue; + } + } + else if (f_compare_dynamic(controller_parameter_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used != 2) { + controller_entry_setting_read_print_setting_requires_exactly(main, is_entry, *cache, 2); + + continue; + } + + status = controller_entry_setting_read_map(cache->buffer_file, cache->content_actions.array[i], &entry->parameter); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(controller_entry_setting_read_map), F_true); + + continue; + } + } + else if (f_compare_dynamic(controller_pid_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used != 1) { + controller_entry_setting_read_print_setting_requires_exactly(main, is_entry, *cache, 1); + + continue; + } + + if (f_compare_dynamic_partial_string(controller_disable_s.string, cache->buffer_file, controller_disable_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + entry->pid = controller_entry_pid_disable_e; + } + else if (f_compare_dynamic_partial_string(controller_ready_s.string, cache->buffer_file, controller_ready_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + entry->pid = controller_entry_pid_ready_e; + } + else if (f_compare_dynamic_partial_string(controller_require_s.string, cache->buffer_file, controller_require_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + entry->pid = controller_entry_pid_require_e; + } + else { + controller_entry_setting_read_print_setting_unknown_action_value(main, is_entry, *cache, i); + + continue; + } + } + else if (is_entry && f_compare_dynamic(controller_pid_file_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used != 1) { + controller_entry_setting_read_print_setting_requires_exactly(main, is_entry, *cache, 1); + + continue; + } + + if (main->program.parameters.array[controller_parameter_pid_e].result & f_console_result_value_e) { + controller_entry_setting_read_print_setting_ignored(main, is_entry, *cache, i); + } + else { + cache->action.generic.used = 0; + + status = f_rip_dynamic_partial_nulless(cache->buffer_file, cache->content_actions.array[i].array[0], &cache->action.generic); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(f_rip_dynamic_partial_nulless), F_true); + + continue; + } + + main->setting.path_pid.used = 0; + + status = controller_path_canonical_relative(main->setting, cache->action.generic, &main->setting.path_pid); + + if (F_status_is_error(status)) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(controller_path_canonical_relative), F_true); + + continue; + } + } + } + else if (f_compare_dynamic(controller_session_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used != 1) { + controller_entry_setting_read_print_setting_requires_exactly(main, is_entry, *cache, 1); + + continue; + } + + if (f_compare_dynamic_partial_string(controller_new_s.string, cache->buffer_file, controller_new_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + entry->session = controller_entry_session_new_e; + } + else if (f_compare_dynamic_partial_string(controller_same_s.string, cache->buffer_file, controller_same_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + entry->session = controller_entry_session_same_e; + } + else { + controller_entry_setting_read_print_setting_unknown_action_value(main, is_entry, *cache, i); + + continue; + } + } + else if (f_compare_dynamic(controller_show_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used != 1) { + controller_entry_setting_read_print_setting_requires_exactly(main, is_entry, *cache, 1); + + continue; + } + + if (f_compare_dynamic_partial_string(controller_normal_s.string, cache->buffer_file, controller_normal_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + entry->show = controller_entry_show_normal_e; + } + else if (f_compare_dynamic_partial_string(controller_init_s.string, cache->buffer_file, controller_init_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + entry->show = controller_entry_show_init_e; + } + else { + controller_entry_setting_read_print_setting_unknown_action_value(main, is_entry, *cache, i); + + continue; + } + } + else if (f_compare_dynamic(controller_timeout_s, cache->action.name_action) == F_equal_to) { + if (cache->content_actions.array[i].used < 1 || cache->content_actions.array[i].used > 2) { + controller_entry_setting_read_print_setting_requires_between(main, is_entry, *cache, 1, 2); + + continue; + } + + f_number_unsigned_t *time = 0; + + if (f_compare_dynamic_partial_string(controller_exit_s.string, cache->buffer_file, controller_exit_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + if (cache->content_actions.array[i].used == 1) { + entry->flag |= controller_entry_flag_timeout_exit_no_e; + + continue; + } + + entry->flag &= ~controller_entry_flag_timeout_exit_no_e; + time = &entry->timeout_exit; + } + else if (f_compare_dynamic_partial_string(controller_kill_s.string, cache->buffer_file, controller_kill_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + if (cache->content_actions.array[i].used == 1) { + entry->flag |= controller_entry_flag_timeout_kill_no_e; + + continue; + } + + entry->flag &= ~controller_entry_flag_timeout_kill_no_e; + time = &entry->timeout_kill; + } + else if (f_compare_dynamic_partial_string(controller_start_s.string, cache->buffer_file, controller_start_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + if (cache->content_actions.array[i].used == 1) { + entry->flag |= controller_entry_flag_timeout_start_no_e; + + continue; + } + + entry->flag &= ~controller_entry_flag_timeout_start_no_e; + time = &entry->timeout_start; + } + else if (f_compare_dynamic_partial_string(controller_stop_s.string, cache->buffer_file, controller_stop_s.used, cache->content_actions.array[i].array[0]) == F_equal_to) { + if (cache->content_actions.array[i].used == 1) { + entry->flag |= controller_entry_flag_timeout_stop_no_e; + + continue; + } + + entry->flag &= ~controller_entry_flag_timeout_stop_no_e; + time = &entry->timeout_stop; + } + else { + controller_entry_setting_read_print_setting_unknown_action_value(main, is_entry, *cache, i); + + continue; + } + + const f_number_unsigned_t time_previous = *time; + + status = fl_conversion_dynamic_partial_to_unsigned_detect(fl_conversion_data_base_10_c, cache->buffer_file, cache->content_actions.array[i].array[1], time); + + if (F_status_is_error(status) || status == F_data_not) { + *time = time_previous; + + if (F_status_set_fine(status) == F_memory_not) { + controller_entry_print_error(&main->program.error, cache->action, is_entry, F_status_set_fine(status), macro_controller_f(fl_conversion_dynamic_partial_to_unsigned_detect), F_true); + + continue; + } + + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + f_file_stream_lock(main->program.error.to); + + fl_print_format("%r%[%QThe %r setting '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, is_entry ? controller_entry_s : controller_exit_s, main->program.error.context); + fl_print_format(f_string_format_Q_range_single_s.string, main->program.error.to, main->program.error.notable, cache->buffer_file, cache->content_actions.array[i].array[1], main->program.error.notable); + fl_print_format("%[' is not a valid supported number.%]", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + f_file_stream_unlock(main->program.error.to); + } + } + } + else { + if (main->program.warning.verbosity == f_console_verbosity_debug_e) { + controller_entry_setting_read_print_setting_unknown_action(main, is_entry, *cache); + } + + continue; + } + } // for + + return f_status_is_error(status) ? status : F_okay; + } +#endif // _di_controller_entry_setting_read_ + +#ifndef _di_controller_entry_setting_read_map_ + f_status_t controller_entry_setting_read_map(const f_string_static_t buffer, const f_ranges_t ranges, f_string_maps_t * const setting_maps) { + + { + f_status_t status = f_memory_array_increase(controller_common_allocation_small_d, sizeof(f_string_map_t), (void **) &setting_maps->array, &setting_maps->used, &setting_maps->size); + if (F_status_is_error(status)) return status; + + setting_maps->array[setting_maps->used].key.used = 0; + setting_maps->array[setting_maps->used].value.used = 0; + + status = f_string_dynamic_partial_append_nulless(buffer, ranges.array[0], &setting_maps->array[setting_maps->used].key); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_partial_append_nulless(buffer, ranges.array[1], &setting_maps->array[setting_maps->used].value); + if (F_status_is_error(status)) return status; + } + + ++setting_maps->used; + + return F_okay; + } +#endif // _di_controller_entry_setting_read_map_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/entry/setting.h b/sources/c/main/entry/setting.h new file mode 100644 index 0000000..17347e9 --- /dev/null +++ b/sources/c/main/entry/setting.h @@ -0,0 +1,75 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the entry setting functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_entry_setting_h +#define _controller_main_entry_setting_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Read the entry settings, loading all settings. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param cache + * A structure for containing and caching relevant data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param content_range + * The range in the list buffer representing the content. + * + * @return + * F_okay on success. + * + * Errors (with error bit) from: controller_entry_print_error_file(). + * + * @see controller_entry_print_error_file() + */ +#ifndef _di_controller_entry_setting_read_ + extern f_status_t controller_entry_setting_read(controller_t * const main, controller_cache_t * const cache, const uint8_t is_entry, const f_range_t content_range); +#endif // _di_controller_entry_setting_read_ + +/** + * Load the given ranges within the buffer into the provided map. + * + * @param buffer + * The buffer the ranges are associated with. + * @param ranges + * The ranges to load from the buffer. + * This expects the caller to already ensure the ranges.used = 2. + * @param setting_maps + * The map to load the settings into. + * + * @return + * F_okay on success. + * + * Errors (with error bit) from: f_memory_aray_increase(). + * Errors (with error bit) from: f_string_dynamic_partial_append_nulless(). + * + * @see f_memory_aray_increase() + * @see f_string_dynamic_partial_append_nulless() + */ +#ifndef _di_controller_entry_setting_read_map_ + extern f_status_t controller_entry_setting_read_map(const f_string_static_t buffer, const f_ranges_t ranges, f_string_maps_t * const setting_maps); +#endif // _di_controller_entry_setting_read_map_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_entry_setting_h diff --git a/sources/c/main/perform.c b/sources/c/main/perform.c new file mode 100644 index 0000000..70d0538 --- /dev/null +++ b/sources/c/main/perform.c @@ -0,0 +1,191 @@ +#include "controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_perform_ready_ + f_status_t controller_perform_ready(controller_t * const main, const uint8_t is_entry) { + + if (!main) return F_status_set_error(F_parameter); + if (!is_entry) return F_okay; + + if (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) { + if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) { + controller_print_perform_debug_pid_file_control_socket(&main->program.debug); + } + + return F_okay; + } + + f_status_t status = F_okay; + + if (main->setting.entry.pid != controller_entry_pid_disable_e && !main->setting.path_pid.used) { + status = controller_file_pid_create(main->program.pid, main->setting.path_pid); + + // Report pid file error but because this could be an "init" program, consider the pid file as optional and continue on. + if (F_status_is_error(status)) { + + // Always return immediately on memory errors. + if (F_status_set_fine(status) == F_memory_not) { + controller_print_perform_error_pid_file_create(&main->program.error, macro_controller_f(controller_file_pid_create), is_entry); + + return status; + } + + controller_print_perform_debug_pid_file_create_problem(&main->program.debug, macro_controller_f(controller_file_pid_create), is_entry); + + status = F_okay; + } + else { + main->setting.flag |= controller_setting_flag_pid_created_e; + + controller_print_perform_debug_pid_file_create_success(&main->program.debug, is_entry); + } + } + + // Disabled, all parts are not yet implemented. + /*if (main->setting.path_control.used) { + status = controller_perform_ready_socket(main, is_entry); + + // Do not fail on non-memory errors related to creating the control socket. + if (F_status_is_error(status) && F_status_set_fine(status) != F_memory) { + status = F_okay; + } + }*/ + + return status; + } +#endif // _di_controller_perform_ready_ + +#ifndef _di_controller_perform_ready_socket_ + f_status_t controller_perform_ready_socket(controller_t * const main, const uint8_t is_entry) { + + f_status_t status = F_okay; + + if (main->setting.control.flag & controller_control_flag_readonly_e) { + if (f_file_exists(main->setting.path_control, F_true) != F_true) { + controller_print_perform_debug_control_socket_missing_read_only(&main->program.debug); + + return F_data_not; + } + } + + status = f_socket_create(&main->setting.control.server); + + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error_status(&main->program.error, macro_controller_f(f_socket_create), F_status_set_fine(status)); + } + else { + // @todo make all message strings passed to controller_print_perform_debug_control_socket_failure() into global static strings and update the function accordingly. + controller_print_perform_debug_control_socket_failure(&main->program.debug, F_status_set_fine(status), "could not be created"); + } + + return status; + } + + if (!(main->setting.control.flag & controller_control_flag_readonly_e)) { + status = f_file_remove(main->setting.path_control); + + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error(global->thread, &main->program.error, F_status_set_fine(status), macro_controller_f(f_file_remove), F_true); + + return status; + } + } + + main->setting.control.server.name = main->setting.path_control; + + status = f_socket_bind(&main->setting.control.server); + + if (F_status_is_error(status)) { + f_socket_disconnect(&main->setting.control.server, f_socket_close_fast_e); + + if (!(main->setting.control.flag & controller_control_flag_readonly_e)) { + f_file_remove(main->setting.path_control); + } + + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error(global->thread, &main->program.error, F_status_set_fine(status), macro_controller_f(f_socket_bind), F_true); + } + else { + controller_print_perform_debug_control_socket_failure(&main->program.debug, F_status_set_fine(status), "could not be bound"); + } + + return status; + } + + if (main->setting.control.flag & (controller_control_flag_has_user_e | controller_control_flag_has_group_e)) { + status = f_file_role_change(main->setting.path_control, main->setting.control.user, main->setting.control.group, F_true); + + if (F_status_is_error(status)) { + f_socket_disconnect(&main->setting.control.server, f_socket_close_fast_e); + + if (!(main->setting.control.flag & controller_control_flag_readonly_e)) { + f_file_remove(main->setting.path_control); + } + + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error(global->thread, &main->program.error, F_status_set_fine(status), macro_controller_f(f_file_role_change), F_true); + } + else { + controller_print_perform_debug_control_socket_failure(&main->program.debug, F_status_set_fine(status), "failed to set file roles"); + } + + return status; + } + } + + if (main->setting.control.flag & controller_control_flag_has_mode_e) { + status = f_file_mode_set(main->setting.path_control, main->setting.control.mode); + + if (F_status_is_error(status)) { + f_socket_disconnect(&main->setting.control.server, f_socket_close_fast_e); + + if (!(main->setting.control.flag & controller_control_flag_readonly_e)) { + f_file_remove(main->setting.path_control); + } + + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error(global->thread, &main->program.error, F_status_set_fine(status), macro_controller_f(f_file_role_change), F_true); + } + else { + controller_print_perform_debug_control_socket_failure(&main->program.debug, F_status_set_fine(status), "failed to set file mode"); + } + + return status; + } + } + + controller_print_perform_debug_control_socket_success(&main->program.debug); + + // Disabled, not yet implemented. + //status = f_thread_create(0, &global->thread->id_control, &controller_thread_control, (void *) global); + + if (status == F_child) return status; + + if (F_status_is_error(status)) { + f_socket_disconnect(&main->setting.control.server, f_socket_close_fast_e); + + if (!(main->setting.control.flag & controller_control_flag_readonly_e)) { + f_file_remove(main->setting.path_control); + } + + if (global->thread->id_control) { + f_thread_cancel(global->thread->id_control); + f_thread_join(global->thread->id_control, 0); + + global->thread->id_control = 0; + } + + controller_print_error_status(&main->program.error, macro_controller_f(f_thread_create), F_status_set_fine(status)); + } + + return F_okay; + } +#endif // _di_controller_perform_ready_socket_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/perform.h b/sources/c/main/perform.h new file mode 100644 index 0000000..cb332fe --- /dev/null +++ b/sources/c/main/perform.h @@ -0,0 +1,86 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides perform functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_perform_h +#define _controller_perform_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Perform all activities requiring the state to be "ready". + * + * This prints messages on errors. + * + * This does not do any locking or unlocking for the setting data, and so be sure to lock appropriately before and after calling this. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this operate as an entry. + * If FALSE, then this operate as an exit. + * + * @return + * F_okay on success. + * + * Errors from controller_file_pid_create() are not returned, unless it is a memory error. + * + * @see controller_file_pid_create() + */ +#ifndef _di_controller_perform_ready_ + extern f_status_t controller_perform_ready(controller_t * const main, const uint8_t is_entry); +#endif // _di_controller_perform_ready_ + +/** + * Perform the socket loading when "ready". + * + * This prints messages on errors. + * + * This does not do any locking or unlocking for the setting data, and so be sure to lock appropriately before and after calling this. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this operate as an entry. + * If FALSE, then this operate as an exit. + * + * @return + * F_okay on success. + * F_data_not on success but socket file not created. + * + * Errors (with error bit) from: f_file_mode_set(). + * Errors (with error bit) from: f_file_remove(). + * Errors (with error bit) from: f_file_role_change(). + * Errors (with error bit) from: f_socket_bind_local(). + * Errors (with error bit) from: f_socket_create(). + * Errors (with error bit) from: f_thread_create(). + * + * @see f_file_mode_set() + * @see f_file_remove() + * @see f_file_role_change() + * @see f_socket_bind_local() + * @see f_socket_create() + * @see f_thread_create() + */ +#ifndef _di_controller_perform_ready_socket_ + extern f_status_t controller_perform_ready_socket(controller_t * const main, const uint8_t is_entry); +#endif // _di_controller_perform_ready_socket_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_perform_h diff --git a/sources/c/main/print/entry.c b/sources/c/main/print/entry.c new file mode 100644 index 0000000..a7c42c3 --- /dev/null +++ b/sources/c/main/print/entry.c @@ -0,0 +1,117 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_entry_action_parameters_print_ + f_status_t controller_entry_action_parameters_print(fl_print_t * const print, controller_entry_action_t * const action) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + for (f_array_length_t index = 0; ;) { + + f_print_dynamic_safely(action.parameters.array[index], stream); + + ++index; + + if (index == action.parameters.used) break; + + f_print_dynamic_raw(f_string_space_s, stream); + } // for + + return F_okay; + } +#endif // _di_controller_entry_action_parameters_print_ + +#ifndef _di_controller_entry_print_error_ + f_status_t controller_entry_print_error(fl_print_t * const print, controller_cache_action_t * const cache, const uint8_t is_entry, const f_status_t status, const char *function, const bool fallback) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + if (print.verbosity == f_console_verbosity_quiet_e) return; + if (status == F_interrupt) return; + + // fll_error_print() automatically locks, so manually handle only the mutex locking and flushing rather than calling controller_lock_print(). + f_thread_mutex_lock(&main->thread.lock.print); + + fll_error_print(print, status, function, fallback); + + flockfile(print.to.stream); + + controller_entry_print_error_cache(is_entry, print, cache); + + controller_unlock_print_flush(print.to, &main->thread); + + return F_okay; + } +#endif // _di_controller_entry_print_error_ + +#ifndef _di_controller_entry_print_error_cache_ + f_status_t controller_entry_print_error_cache(fl_print_t * const print, controller_cache_action_t * const cache, const uint8_t is_entry) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + fl_print_format("%r%[%QWhile processing ", output.to.stream, f_string_eol_s, output.context, output.prefix); + + if (cache.name_action.used) { + fl_print_format("action '%]", output.to.stream, output.context); + fl_print_format("%[%Q%]", output.to.stream, output.notable, cache.name_action, output.notable); + fl_print_format("%[' on line%] ", output.to.stream, output.context, output.context); + fl_print_format("%[%un%]", output.to.stream, output.notable, cache.line_action, output.notable); + fl_print_format("%[ for ", output.to.stream, output.context); + } + + if (cache.name_item.used) { + fl_print_format("%r item '%]", output.to.stream, is_entry ? controller_entry_s : controller_exit_s, output.context); + fl_print_format("%[%Q%]", output.to.stream, output.notable, cache.name_item, output.notable); + fl_print_format("%[' on line%] ", output.to.stream, output.context, output.context); + fl_print_format("%[%un%]", output.to.stream, output.notable, cache.line_item, output.notable); + fl_print_format("%[ for ", output.to.stream, output.context); + } + + if (cache.name_file.used) { + fl_print_format("%r file '%]", output.to.stream, is_entry ? controller_entry_s : controller_exit_s, output.context); + fl_print_format("%[%Q%]%['", output.to.stream, output.notable, cache.name_file, output.notable, output.context); + } + + fl_print_format(".%]%r", output.to.stream, output.context, f_string_eol_s); + + return F_okay; + } +#endif // _di_controller_entry_print_error_cache_ + +#ifndef _di_controller_entry_print_error_file_ + f_status_t controller_entry_print_error_file(fl_print_t * const print, controller_cache_action_t * const cache, const uint8_t is_entry, const f_status_t status, const char *function, const bool fallback, const f_string_static_t name, const f_string_static_t operation, const uint8_t type) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + if (print.verbosity == f_console_verbosity_quiet_e) return; + if (status == F_interrupt) return; + + // fll_error_file_print() automatically locks, so manually handle only the mutex locking and flushing rather than calling controller_lock_print(). + f_thread_mutex_lock(&main->thread.lock.print); + + fll_error_file_print(print, status, function, fallback, name, operation, type); + + flockfile(print.to.stream); + + controller_entry_print_error_cache(is_entry, print, cache); + + controller_unlock_print_flush(print.to, &main->thread); + + return F_okay; + } +#endif // _di_controller_entry_print_error_file_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/print/entry.h b/sources/c/main/print/entry.h new file mode 100644 index 0000000..9a837d1 --- /dev/null +++ b/sources/c/main/print/entry.h @@ -0,0 +1,143 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the print entry functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_print_entry_h +#define _controller_main_print_entry_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print all parameters for some action, separated by a space. + * + * @param stream + * The file stream to print to. + * @param action + * The entry action whose parameters will be printed. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_entry_action_parameters_print_ + extern f_status_t controller_entry_action_parameters_print(fl_print_t * const print, controller_entry_action_t * const action); +#endif // _di_controller_entry_action_parameters_print_ + +/** + * Print the entry related error, locking the print mutex during the print. + * + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param print + * Designates how printing is to be performed. + * @param cache + * The action cache. + * @param status + * The status code to process. + * Make sure this has F_status_set_fine() called if the status code has any error or warning bits. + * @param function + * The name of the function where the error happened. + * Set to 0 to disable. + * @param fallback + * Set to F_true to print the fallback error message for unknown errors. + * @param thread + * The thread data. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fll_error_print() + * @see controller_entry_print_error_cache() + */ +#ifndef _di_controller_entry_print_error_ + extern f_status_t controller_entry_print_error(fl_print_t * const print, controller_cache_action_t * const cache, const uint8_t is_entry, const f_status_t status, const char *function, const bool fallback); +#endif // _di_controller_entry_print_error_ + +/** + * Print additional error/warning information in addition to existing error that is found within the cache. + * + * This is explicitly intended to be used in addition to the error message. + * + * This neither locks the thread nor does it check to see if output is enabled or disabled. + * + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param output + * Designates how printing is to be performed. + * @param cache + * The action cache. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see controller_entry_actions_read() + * @see controller_entry_read() + */ +#ifndef _di_controller_entry_print_error_cache_ + extern f_status_t controller_entry_print_error_cache(fl_print_t * const print, controller_cache_action_t * const cache, const uint8_t is_entry); +#endif // _di_controller_entry_print_error_cache_ + +/** + * Print the entry related file error, locking the print mutex during the print. + * + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param print + * Designates how printing is to be performed. + * @param cache + * The action cache. + * @param status + * The status code to process. + * Make sure this has F_status_set_fine() called if the status code has any error or warning bits. + * @param function + * The name of the function where the error happened. + * Set to 0 to disable. + * @param fallback + * Set to F_true to print the fallback error message for unknown errors. + * @param name + * The name of the file or directory. + * @param operation + * The operation that fails, such as 'create' or 'access'. + * @param type + * A valid file type code from the fll_error_file_type enum. + * @param thread + * The thread data. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fll_error_file_print() + * @see controller_entry_print_error_cache() + */ +#ifndef _di_controller_entry_print_error_file_ + extern f_status_t controller_entry_print_error_file(fl_print_t * const print, controller_cache_action_t * const cache, const uint8_t is_entry, const f_status_t status, const char *function, const bool fallback, const f_string_static_t name, const f_string_static_t operation, const uint8_t type); +#endif // _di_controller_entry_print_error_file_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_print_entry_h diff --git a/sources/c/main/print/entry/setting.c b/sources/c/main/print/entry/setting.c new file mode 100644 index 0000000..971e390 --- /dev/null +++ b/sources/c/main/print/entry/setting.c @@ -0,0 +1,162 @@ +#include "../../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_entry_setting_read_print_error_with_range_ + f_status_t controller_entry_setting_read_print_error_with_range(fl_print_t * const print, const uint8_t is_entry, const f_string_t before, const f_string_range_t range, const f_string_t after) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + if (main->warning.verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + controller_lock_print(print.to, thread); + + fl_print_format("%r%[%Q%r setting%S '%]", print.to.stream, f_string_eol_s, print.context, print.prefix, is_entry ? controller_Entry_s : controller_Exit_s, before, print.context); + fl_print_format("%[%/Q%]", print.to.stream, print.notable, cache->buffer_file, range, print.notable); + fl_print_format("%['%S.%]%r", print.to.stream, print.context, after, print.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, print, cache->action); + + controller_unlock_print_flush(print.to, thread); + + return F_okay; + } +#endif // _di_controller_entry_setting_read_print_error_with_range_ + +#ifndef _di_controller_print_entry_setting_read_ignored_ + f_status_t controller_print_entry_setting_read_ignored(fl_print_t * const print, const uint8_t is_entry, const f_array_length_t index) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + if (main->warning.verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + if (main->warning.verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_lock_print(main->warning.to, &main->thread); + + fl_print_format("%r%[%QThe %Q item setting '%]", main->warning.to.stream, f_string_eol_s, main->warning.context, main->warning.prefix, is_entry ? controller_entry_s : controller_exit_s, main->warning.context); + fl_print_format("%[%Q%]", main->warning.to.stream, main->warning.notable, cache->action.name_action, main->warning.notable); + fl_print_format("%[' is being ignored.%]%r", main->warning.to.stream, main->warning.context, main->warning.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, main->warning, cache->action); + + controller_unlock_print_flush(main->warning.to, &main->thread); + + return F_okay; + } +#endif // _di_controller_print_entry_setting_read_ignored_ + +#ifndef _di_controller_print_entry_setting_read_requires_between_ + f_status_t controller_print_entry_setting_read_requires_between(fl_print_t * const print, const uint8_t is_entry, const f_number_unsigned_t minimum, const f_number_unsigned_t maximum) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + if (main->warning.verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_lock_print(main->error.to, &main->thread); + + fl_print_format("%r%[%QThe %Q item setting '%]", main->error.to.stream, f_string_eol_s, main->error.context, main->error.prefix, is_entry ? controller_entry_s : controller_exit_s, main->error.context); + fl_print_format("%[%Q%]", main->error.to.stream, main->error.notable, cache->action.name_action, main->error.notable); + fl_print_format("%[' requires at least %]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%un%]", main->error.to.stream, main->error.notable, minimum, main->error.notable); + fl_print_format("%[ and at most %]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%un%]", main->error.to.stream, main->error.notable, maximum, main->error.notable); + fl_print_format("%[ Content.%]%r", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, main->error, cache->action); + + controller_unlock_print_flush(main->error.to, &main->thread); + + return F_okay; + } +#endif // _di_controller_print_entry_setting_read_requires_between_ + +#ifndef _di_controller_print_entry_setting_read_requires_exactly_ + f_status_t controller_print_entry_setting_read_requires_exactly(fl_print_t * const print, const uint8_t is_entry, const f_number_unsigned_t total) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + if (main->warning.verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_lock_print(main->error.to, &main->thread); + + fl_print_format("%r%[%QThe %Q item setting '%]", main->error.to.stream, f_string_eol_s, main->error.context, main->error.prefix, is_entry ? controller_entry_s : controller_exit_s, main->error.context); + fl_print_format("%[%Q%]", main->error.to.stream, main->error.notable, cache->action.name_action, main->error.notable); + fl_print_format("%[' requires exactly %]", main->error.to.stream, main->error.context, main->error.context); + fl_print_format("%[%un%]", main->error.to.stream, main->error.notable, total, main->error.notable); + fl_print_format("%[ Content.%]%r", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, main->error, cache->action); + + controller_unlock_print_flush(main->error.to, &main->thread); + + return F_okay; + } +#endif // _di_controller_print_entry_setting_read_requires_exactly_ + +#ifndef _di_controller_print_entry_setting_read_unknown_action_ + f_status_t controller_print_entry_setting_read_unknown_action(fl_print_t * const print, const uint8_t is_entry) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + if (main->warning.verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_lock_print(main->warning.to, &main->thread); + + fl_print_format("%r%[%QUnknown %r item setting '%]", main->warning.to.stream, f_string_eol_s, main->warning.context, main->warning.prefix, is_entry ? controller_entry_s : controller_exit_s, main->warning.context); + fl_print_format("%[%Q%]", main->warning.to.stream, main->warning.notable, cache->action.name_action, main->warning.notable); + fl_print_format("%['.%]%r", main->warning.to.stream, main->warning.context, main->warning.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, main->warning, cache->action); + + controller_unlock_print_flush(main->warning.to, &main->thread); + + return F_okay; + } +#endif // _di_controller_print_entry_setting_read_unknown_action_ + +#ifndef _di_controller_print_entry_setting_read_unknown_action_value_ + f_status_t controller_print_entry_setting_read_unknown_action_value(fl_print_t * const print, const uint8_t is_entry, const f_array_length_t index) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + if (!main || !cache) return F_status_set_error(F_output_not); + if (main->warning.verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_lock_print(main->warning.to, &main->thread); + + fl_print_format("%r%[%QThe %Q item setting '%]", main->warning.to.stream, f_string_eol_s, main->warning.context, main->warning.prefix, is_entry ? controller_entry_s : controller_exit_s, main->warning.context); + fl_print_format("%[%Q%]", main->warning.to.stream, main->warning.notable, cache->action.name_action, main->warning.notable); + fl_print_format("%[' has an unknown value '%]", main->warning.to.stream, main->warning.context, main->warning.context); + fl_print_format("%[%/Q%]", main->warning.to.stream, main->warning.notable, cache->buffer_file, cache->content_actions.array[index].array[0], main->warning.notable); + fl_print_format("%['.%]%r", main->warning.to.stream, main->warning.context, main->warning.context, f_string_eol_s); + + controller_entry_print_error_cache(is_entry, main->warning, cache->action); + + controller_unlock_print_flush(main->warning.to, &main->thread); + + return F_okay; + } +#endif // _di_controller_print_entry_setting_read_unknown_action_value_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/print/entry/setting.h b/sources/c/main/print/entry/setting.h new file mode 100644 index 0000000..598577c --- /dev/null +++ b/sources/c/main/print/entry/setting.h @@ -0,0 +1,184 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the print entry setting functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_print_entry_setting_h +#define _controller_main_print_entry_setting_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print a message about an entry setting problem, with additional messages about the value. + * + * This is intended to be explicitly called by controller_entry_settings_read(). + * This is intended only to be used for simple messages. + * + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param print + * The error or warning output structure. + * @param before + * The string to add to the message being printed (before the value). + * @param range + * The range within the cache item buffer representing the value. + * @param after + * The string to add to the message being printed (after the value). + * @param thread + * The thread data. + * @param cache + * A structure for containing and caching relevant data. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see controller_entry_settings_read() + */ +#ifndef _di_controller_entry_setting_read_print_error_with_range_ + extern f_status_t controller_entry_setting_read_print_error_with_range(fl_print_t * const print, const uint8_t is_entry, const fl_print_t print, const f_string_t before, const f_string_range_t range, const f_string_t after); +#endif // _di_controller_entry_setting_read_print_error_with_range_ + +/** + * Print a message for when an entry setting is being ignored. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param cache + * A structure for containing and caching relevant data. + * @param total + * The expected number of arguments. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_entry_setting_read_ignored_ + extern f_status_t controller_print_entry_setting_read_ignored(fl_print_t * const print, const uint8_t is_entry, const f_array_length_t index); +#endif // _di_controller_print_entry_setting_read_ignored_ + +/** + * Print a message for when an entry setting action has the incorrect number of parameters when the required amount is between a range. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param cache + * A structure for containing and caching relevant data. + * @param minimum + * The expected minimum number of arguments. + * @param maximum + * The expected maximum number of arguments. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_entry_setting_read_requires_between_ + extern f_status_t controller_print_entry_setting_read_requires_between(fl_print_t * const print, const uint8_t is_entry, const f_number_unsigned_t minimum, const f_number_unsigned_t maximum); +#endif // _di_controller_print_entry_setting_read_requires_between_ + +/** + * Print a message for when an entry setting action has the incorrect number of parameters when the required amount is fixed. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param cache + * A structure for containing and caching relevant data. + * @param total + * The expected number of arguments. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_entry_setting_read_requires_exactly_ + extern f_status_t controller_print_entry_setting_read_requires_exactly(fl_print_t * const print, const uint8_t is_entry, const f_number_unsigned_t total); +#endif // _di_controller_print_entry_setting_read_requires_exactly_ + +/** + * Print a message for when an entry setting action is unknown. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param cache + * A structure for containing and caching relevant data. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_entry_setting_read_unknown_action_ + extern f_status_t controller_print_entry_setting_read_unknown_action(fl_print_t * const print, const uint8_t is_entry); +#endif // _di_controller_print_entry_setting_read_unknown_action_ + +/** + * Print a message for when an entry setting action has an unknown value. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this loads as an entry. + * If FALSE, then this loads as an exit. + * @param cache + * A structure for containing and caching relevant data. + * @param total + * The expected number of arguments. + * @param index + * The location in the content actions array representing the action value. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_entry_setting_read_unknown_action_value_ + extern f_status_t controller_print_entry_setting_read_unknown_action_value(fl_print_t * const print, const uint8_t is_entry, const f_array_length_t index); +#endif // _di_controller_print_entry_setting_read_unknown_action_value_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_print_entry_setting_h diff --git a/sources/c/main/print/entry/simulate.c b/sources/c/main/print/entry/simulate.c new file mode 100644 index 0000000..e77f991 --- /dev/null +++ b/sources/c/main/print/entry/simulate.c @@ -0,0 +1,39 @@ +#include "../../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_entry_preprocess_print_simulate_setting_value_ + f_status_t controller_entry_preprocess_print_simulate_setting_value(fl_print_t * const print, const uint8_t is_entry, const f_string_static_t name, const f_string_static_t name_sub, const f_string_static_t value, const f_string_static_t suffix) { + + if (main->error.verbosity != f_console_verbosity_debug_e && !(main->error.verbosity == f_console_verbosity_verbose_e && main->parameters.array[controller_parameter_simulate_e].result == f_console_result_found_e)) { + return; + } + + controller_lock_print(main->output.to, &main->thread); + + fl_print_format("%rProcessing %r item action '", main->output.to.stream, f_string_eol_s, is_entry ? controller_entry_s : controller_exit_s); + + fl_print_format("%[%Q%]' setting ", main->output.to.stream, main->context.set.title, name, main->context.set.title); + + if (name_sub.used) { + fl_print_format("'%[%Q%]'", main->output.to.stream, main->context.set.notable, name_sub, main->context.set.notable); + } + else { + fl_print_format("value", main->output.to.stream); + } + + fl_print_format(" to '%[%Q%]", main->output.to.stream, main->context.set.important, value, main->context.set.important); + + fl_print_format("'%Q.%r", main->output.to.stream, suffix, f_string_eol_s); + + controller_unlock_print_flush(main->output.to, &main->thread); + + return F_okay; + } +#endif // _di_controller_entry_preprocess_print_simulate_setting_value_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/print/entry/simulate.h b/sources/c/main/print/entry/simulate.h new file mode 100644 index 0000000..dfc2f2d --- /dev/null +++ b/sources/c/main/print/entry/simulate.h @@ -0,0 +1,53 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the print entry simulate functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_print_entry_simulate_h +#define _controller_main_print_entry_simulate_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print message regarding the population of a setting when in simulation or verbose mode. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this operate as an entry. + * If FALSE, then this operate as an exit. + * @param name + * The Object name of the setting being populated. + * @param name_sub + * A sub-name associated with the setting being populated. + * Set to a string with used set to 0 to not use. + * @param value + * The value being set. + * @param suffix + * An additional message to append at the end (before the final period). + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_entry_preprocess_print_simulate_setting_value_ + extern f_status_t controller_entry_preprocess_print_simulate_setting_value(controller_t * const main, const uint8_t is_entry, const f_string_static_t name, const f_string_static_t name_sub, const f_string_static_t value, const f_string_static_t suffix); +#endif // _di_controller_entry_preprocess_print_simulate_setting_value_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_print_entry_simulate_h diff --git a/sources/c/main/print/entry/validate.c b/sources/c/main/print/entry/validate.c new file mode 100644 index 0000000..1505136 --- /dev/null +++ b/sources/c/main/print/entry/validate.c @@ -0,0 +1,404 @@ +#include "../../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_print_entry_validate_setting_ + f_status_t controller_print_entry_validate_setting(fl_print_t * const print, const uint8_t is_entry) { + + if (!main) return F_status_set_error(F_output_not); + + controller_entry_t * const entry = is_entry ? &main->process.entry : &main->process.exit; + + controller_lock_print(main->program.output.to, &main->thread); + + const f_string_static_t *string = 0; + + f_status_t status = F_okay; + f_number_unsigned_t i = 0; + f_number_unsigned_t j = 0; + + fl_print_format("%r%Q %[%Q%] {%r", main->program.output.to, f_string_eol_s, is_entry ? controller_Entry_s : controller_Exit_s, main->program.context.set.title, controller_settings_s, main->program.context.set.title, f_string_eol_s); + + + // Mode. + if (main->setting.mode == controller_setting_mode_service_e) { + string = &controller_mode_s; + } + else if (main->setting.mode == controller_setting_mode_helper_e) { + string = &controller_helper_s; + } + else if (main->setting.mode == controller_setting_mode_program_e) { + string = &controller_program_s; + } + else { + string = &f_string_empty_s; + } + + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_mode_s, main->program.context.set.important, f_string_eol_s); + + if (string->used) { + fl_print_format(" %r", main->program.output.to, *string); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Session. + if (entry->pid == controller_entry_session_new_e) { + string = &controller_new_s; + } + else if (entry->pid == controller_entry_session_same_e) { + string = &controller_same_s; + } + else { + string = &f_string_empty_s; + } + + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_session_s, main->program.context.set.important, f_string_eol_s); + + if (string->used) { + fl_print_format(" %r", main->program.output.to, *string, f_string_eol_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Show. + if (entry->pid == controller_entry_show_normal_e) { + string = &controller_normal_s; + } + else if (entry->pid == controller_entry_show_init_e) { + string = &controller_init_s; + } + else { + string = &f_string_empty_s; + } + + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_show_s, main->program.context.set.important, f_string_eol_s); + + if (string->used) { + fl_print_format(" %r", main->program.output.to, *string, f_string_eol_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Pid. + if (entry->pid == controller_entry_pid_disable_e) { + string = &controller_disable_s; + } + else if (entry->pid == controller_entry_pid_require_e) { + string = &controller_require_s; + } + else if (entry->pid == controller_entry_pid_ready_e) { + string = &controller_ready_s; + } + else { + string = &f_string_empty_s; + } + + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_pid_s, main->program.context.set.important); + + if (string->used) { + fl_print_format(" %r", main->program.output.to, *string); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Pid File. + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_pid_file_s, main->program.context.set.important); + + if (main->setting.path_pid.used) { + fl_print_format(" %r", main->program.output.to, main->setting.path_pid); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Control. + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_control_s, main->program.context.set.important); + + if (main->setting.path_control.used) { + fl_print_format(" %Q", main->program.output.to, main->setting.path_control); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Control Has. + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_control_has_s, main->program.context.set.important); + + if (main->setting.control.flag & controller_control_flag_readonly_e) { + fl_print_format(" %r", main->program.output.to, controller_readonly_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Control User. + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_control_user_s, main->program.context.set.important); + + if (main->setting.control.flag & controller_control_flag_has_user_e) { + fl_print_format(" %u", main->program.output.to, (unsigned int) main->setting.control.user); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Control Group. + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_control_group_s, main->program.context.set.important); + + if (main->setting.control.flag & controller_control_flag_has_group_e) { + fl_print_format(" %u", main->program.output.to, (unsigned int) main->setting.control.group); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Control Mode. + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_control_mode_s, main->program.context.set.important); + + if (F_status_is_error_not(status)) { + if (main->setting.control.flag & controller_control_flag_has_group_e) { + fl_print_format(" %@05u", main->program.output.to, (unsigned int) main->setting.control.mode); + } + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Timeout: Exit. + fl_print_format(" %[%r%] %r", main->program.output.to, main->program.context.set.important, controller_timeout_s, main->program.context.set.important, controller_exit_s); + + if (!(entry->flag & controller_entry_flag_timeout_exit_no_e)) { + fl_print_format(" %ul", main->program.output.to, entry->timeout_exit, f_string_eol_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Timeout: Kill. + fl_print_format(" %[%r%] %r", main->program.output.to, main->program.context.set.important, controller_timeout_s, main->program.context.set.important, controller_kill_s); + + if (!(entry->flag & controller_entry_flag_timeout_kill_no_e)) { + fl_print_format(" %ul", main->program.output.to, entry->timeout_kill, f_string_eol_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Timeout: Start. + fl_print_format(" %[%r%] %r", main->program.output.to, main->program.context.set.important, controller_timeout_s, main->program.context.set.important, controller_start_s); + + if (!(entry->flag & controller_entry_flag_timeout_start_no_e)) { + fl_print_format(" %ul", main->program.output.to, entry->timeout_start, f_string_eol_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Timeout: Stop. + fl_print_format(" %[%r%] %r", main->program.output.to, main->program.context.set.important, controller_timeout_s, main->program.context.set.important, controller_stop_s); + + if (!(entry->flag & controller_entry_flag_timeout_stop_no_e)) { + fl_print_format(" %ul", main->program.output.to, entry->timeout_stop, f_string_eol_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Define. + fl_print_format(" %[%r%] {%r", main->program.output.to, main->program.context.set.important, controller_define_s, main->program.context.set.important, f_string_eol_s); + + for (i = 0; i < entry->define.used; ++i) { + fl_print_format(" %Q %Q%r", main->program.output.to, entry->define.array[i].key, entry->define.array[i].value, f_string_eol_s); + } // for + + fl_print_format(" }%r", main->program.output.to, f_string_eol_s, f_string_eol_s); + + + // Parameter. + fl_print_format(" %[%r%] {%r", main->program.output.to, main->program.context.set.important, controller_parameter_s, main->program.context.set.important, f_string_eol_s); + + for (i = 0; i < entry->parameter.used; ++i) { + fl_print_format(" %Q %Q%r", main->program.output.to, entry->parameter.array[i].key, entry->parameter.array[i].value, f_string_eol_s); + } // for + + fl_print_format(" }%r", main->program.output.to, f_string_eol_s); + + fl_print_format("}%r", main->program.output.to, f_string_eol_s); + + + // Entry Items. + if (entry->items.used) { + controller_entry_action_t *action = 0; + bool raw = F_false; + f_number_unsigned_t k = 0; + + for (i = 0; i < entry->items.used; ++i) { + + fl_print_format("%r%Q %Q %[%Q%] {%r", main->program.output.to, f_string_eol_s, is_entry ? controller_Entry_s : controller_Exit_s, controller_Item_s, main->program.context.set.title, entry->items.array[i].name, main->program.context.set.title, f_string_eol_s); + + for (j = 0; j < entry->items.array[i].actions.used; ++j) { + + action = &entry->items.array[i].actions.array[j]; + + fl_print_format(" %[%r%] {%r", main->program.output.to, main->program.context.set.important, controller_action_s, main->program.context.set.important, f_string_eol_s); + + + // Item Type. + if (action->type == controller_entry_action_type_consider_e) { + string = &controller_consider_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_execute_e) { + string = &controller_execute_s; + raw = F_true; + } + else if (action->type == controller_entry_action_type_failsafe_e) { + string = &controller_failsafe_s; + raw = F_true; + } + else if (action->type == controller_entry_action_type_freeze_e) { + string = &controller_freeze_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_item_e) { + string = &controller_item_s; + raw = F_true; + } + else if (action->type == controller_entry_action_type_kexec_e) { + string = &controller_kexec_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_kill_e) { + string = &controller_kill_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_pause_e) { + string = &controller_pause_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_ready_e) { + string = &controller_ready_s; + raw = F_true; + } + else if (action->type == controller_entry_action_type_reboot_e) { + string = &controller_reboot_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_reload_e) { + string = &controller_reload_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_restart_e) { + string = &controller_restart_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_resume_e) { + string = &controller_resume_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_shutdown_e) { + string = &controller_shutdown_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_start_e) { + string = &controller_start_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_stop_e) { + string = &controller_stop_s; + raw = F_false; + } + else if (action->type == controller_entry_action_type_timeout_e) { + string = &controller_timeout_s; + raw = F_true; + } + else if (action->type == controller_entry_action_type_thaw_e) { + string = &controller_thaw_s; + raw = F_false; + } + else { + string = &f_string_empty_s; + } + + fl_print_format(" %[%r%] %r%r", main->program.output.to, main->program.context.set.important, controller_type_s, main->program.context.set.important, *string, f_string_eol_s); + + + // Item Code (How). + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_how_s, main->program.context.set.important); + + if (action->code) { + if (action->code == controller_entry_rule_code_asynchronous_d) { + fl_print_format(" %r", main->program.output.to, controller_asynchronous_s); + } + + if (action->type == controller_entry_rule_code_require_d) { + fl_print_format(" %r", main->program.output.to, controller_require_s); + } + + if (action->type == controller_entry_rule_code_wait_d) { + fl_print_format(" %r", main->program.output.to, controller_wait_s); + } + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Parameters. + if (action->type == controller_entry_action_type_item_e) { + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_item_s, main->program.context.set.important); + + if (action->parameters.used && action->parameters.array[0].used) { + fl_print_format(" %Q", main->program.output.to, action->parameters.array[0], f_string_eol_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + } + else if (raw) { + for (k = 0; k < action->parameters.used; ++k) { + fl_print_format(" %[%r%] %Q%r", main->program.output.to, main->program.context.set.important, controller_parameter_s, main->program.context.set.important, action->parameters.array[k], f_string_eol_s); + } // for + } + else { + + // Parameter, Directory. + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_directory_s, main->program.context.set.important); + + if (action->parameters.used && action->parameters.array[0].used) { + fl_print_format(" %Q", main->program.output.to, action->parameters.array[0], f_string_eol_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + + + // Parameter, File. + fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_file_s, main->program.context.set.important); + + if (action->parameters.used && action->parameters.array[0].used > 1) { + fl_print_format(" %Q", main->program.output.to, action->parameters.array[1], f_string_eol_s); + } + + fl_print_format("%r", main->program.output.to, f_string_eol_s); + } + + fl_print_format(" }%r", main->program.output.to, f_string_eol_s); + } // for + + fl_print_format("}%r", main->program.output.to, f_string_eol_s); + } // for + } + + controller_unlock_print_flush(main->program.output.to, &main->thread); + + return F_okay; + } +#endif // _di_controller_print_entry_validate_setting_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/print/entry/validate.h b/sources/c/main/print/entry/validate.h new file mode 100644 index 0000000..888fd76 --- /dev/null +++ b/sources/c/main/print/entry/validate.h @@ -0,0 +1,48 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the print entry validate functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_print_entry_validate_h +#define _controller_main_print_entry_validate_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print a simulated execution of the given entry. + * + * @param main + * The main program data. + * + * Must not be NULL. + * @param cache + * A structure for containing and caching relevant data. + * + * Must not be NULL. + * @param is_entry + * If TRUE, then this is an entry. + * If FALSE, then this is an exit. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_entry_validate_setting_ + extern f_status_t controller_print_entry_validate_setting(fl_print_t * const print, const uint8_t is_entry); +#endif // _di_controller_print_entry_validate_setting_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_print_entry_validate_h diff --git a/sources/c/main/print/perform.c b/sources/c/main/print/perform.c new file mode 100644 index 0000000..2d5da06 --- /dev/null +++ b/sources/c/main/print/perform.c @@ -0,0 +1,157 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_print_perform_debug_control_socket_failure_ + f_status_t controller_print_perform_debug_control_socket_failure(fl_print_t * const print, const f_status_t status, const f_string_t message) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + controller_lock_print(print->to, &main->thread); + + fl_print_format("%r%[%QControl socket '%]", print->to, f_string_eol_s, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, main->setting.path_control, print->notable); + fl_print_format("%[' %S, code %]", print->to, print->context, message, print->context); + fl_print_format(f_string_format_ui_single_s.string, print->to, print->notable, status, print->notable); + fl_print_format(f_string_format_sentence_end_s.string, print->to, print->context, print->context, f_string_eol_s); + + controller_unlock_print_flush(print->to, &main->thread); + } +#endif // _di_controller_print_perform_debug_control_socket_failure_ + +#ifndef _di_controller_print_perform_debug_control_socket_success_ + f_status_t controller_print_perform_debug_control_socket_success(fl_print_t * const print, const f_status_t status, const f_string_t message) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + controller_lock_print(print->to, &main->thread); + + fl_print_format("%rControl socket '", print->to, f_string_eol_s); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, main->setting.path_control, print->notable); + fl_print_format("' created.%r", print->to, f_string_eol_s); + + controller_unlock_print_flush(print->to, &main->thread); + } +#endif // _di_controller_print_perform_debug_control_socket_success_ + +#ifndef _di_controller_print_perform_debug_control_socket_missing_read_only_ + f_status_t controller_print_perform_debug_control_socket_missing_read_only(fl_print_t * const print) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + controller_lock_print(print->to, &main->thread); + + fl_print_format("%r%[%QControl socket '%]", print->to, f_string_eol_s, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, main->setting.path_control, print->notable); + fl_print_format("' .%r", print->to, f_string_eol_s); + fl_print_format("%[' cannot be found while read only mode is enabled and so the Control socket is unavailable.%]%r", print->to, print->context, print->context, f_string_eol_s); + + controller_unlock_print_flush(print->to, &main->thread); + + return F_okay; + } +#endif // _di_controller_print_perform_debug_control_socket_missing_read_only_ + +#ifndef _di_controller_print_perform_debug_pid_file_control_socket_ + f_status_t controller_print_perform_debug_pid_file_control_socket(fl_print_t * const print) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + controller_lock_print(print->to, &main->thread); + + fl_print_format("%rPID file '", print->to, f_string_eol_s); + fl_print_format("%[%Q%]'.%r", print->to, print->notable, main->setting.path_pid, print->notable, f_string_eol_s); + + if (main->setting.path_control.used) { + fl_print_format("%rControl socket '", print->to, f_string_eol_s); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, main->setting.path_control, print->notable); + fl_print_format("'.%r", print->to, f_string_eol_s); + } + + controller_unlock_print_flush(print->to, &main->thread); + + return F_okay; + } +#endif // _di_controller_print_perform_debug_pid_file_control_socket_ + +#ifndef _di_controller_print_perform_debug_pid_file_create_problem_ + f_status_t controller_print_perform_debug_pid_file_create_problem(fl_print_t * const print, const f_string_t function, const f_status_t status, const uint8_t is_entry) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + controller_lock_print(print->to, &main->thread); + + if (F_status_set_fine(status) == F_read_only) { + fl_print_format("%r%[%QThe pid file '%]", print->to, f_string_eol_s, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, main->setting.path_pid, print->notable); + fl_print_format("%[' could not be written because the destination is read only.%]%r", print->to, print->context, print->context, f_string_eol_s); + } + else { + controller_print_error_file_status(print, function, F_true, main->setting.path_pid, f_file_operation_create_s, fll_error_file_type_file_e, status); + } + + f_file_stream_lock(print->to); + + controller_entry_print_error_cache(print->to, main->thread.cache.action, is_entry); + + controller_unlock_print_flush(print->to, &main->thread); + } +#endif // _di_controller_print_perform_debug_pid_file_create_problem_ + +#ifndef _di_controller_print_perform_debug_pid_file_create_success_ + f_status_t controller_print_perform_debug_pid_file_create_success(fl_print_t * const print, const uint8_t is_entry) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_debug_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + controller_lock_print(print->to, &main->thread); + + fl_print_format("%rPID file '", print->to, f_string_eol_s); + fl_print_format("%[%Q%]' created.%r", print->to, print->notable, main->setting.path_pid, print->notable, f_string_eol_s); + + controller_unlock_print_flush(print->to, &main->thread); + } +#endif // _di_controller_print_perform_debug_pid_file_create_success_ + +#ifndef _di_controller_print_perform_error_pid_file_create_ + f_status_t controller_print_perform_error_pid_file_create(fl_print_t * const print, const f_string_t function, const f_status_t status, const uint8_t is_entry) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + controller_t * const main = (controller_t *) print->custom; + + controller_lock_print(print->to, &main->thread); + + controller_print_error_file_status(print, function, F_true, main->setting.path_pid, f_file_operation_create_s, fll_error_file_type_file_e, status); + + f_file_stream_lock(print->to); + + controller_entry_print_error_cache(print->to, main->thread.cache.action, is_entry); + + controller_unlock_print_flush(print->to, &main->thread); + } +#endif // _di_controller_print_perform_error_pid_file_create_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/print/perform.h b/sources/c/main/print/perform.h new file mode 100644 index 0000000..c9c276f --- /dev/null +++ b/sources/c/main/print/perform.h @@ -0,0 +1,186 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the print perform functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_print_perform_h +#define _controller_main_print_perform_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print debug message about control socket failing for the reason specified. + * + * @param print + * The output structure to print to. + * + * This requires print.custom to be controller_t. + * + * This does not alter print.custom.setting.state.status. + * @param status + * The status code relating to the failure. + * @param message + * A short message describing the reason for the failure. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_perform_debug_control_socket_failure_ + extern f_status_t controller_print_perform_debug_control_socket_failure(fl_print_t * const print, const f_status_t status, const f_string_t message); +#endif // _di_controller_print_perform_debug_control_socket_failure_ + +/** + * Print debug message about control socket being created. + * + * @param print + * The output structure to print to. + * + * This requires print.custom to be controller_t. + * + * This does not alter print.custom.setting.state.status. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_perform_debug_control_socket_success_ + extern f_status_t controller_print_perform_debug_control_socket_success(fl_print_t * const print); +#endif // _di_controller_print_perform_debug_control_socket_success_ + +/** + * Print debug message about control socket missing in read only mode. + * + * @param print + * The output structure to print to. + * + * This requires print.custom to be controller_t. + * + * This does not alter print.custom.setting.state.status. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_perform_debug_control_socket_missing_read_only_ + extern f_status_t controller_print_perform_debug_control_socket_missing_read_only(fl_print_t * const print); +#endif // _di_controller_print_perform_debug_pid_file_control_socket_ + +/** + * Print debug message about PID file and control socket. + * + * @param print + * The output structure to print to. + * + * This requires print.custom to be controller_t. + * + * This does not alter print.custom.setting.state.status. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_perform_debug_pid_file_control_socket_ + extern f_status_t controller_print_perform_debug_pid_file_control_socket(fl_print_t * const print); +#endif // _di_controller_print_perform_debug_pid_file_control_socket_ + +/** + * Print debug message on problems when creating PID file. + * + * @param print + * The output structure to print to. + * + * This requires print.custom to be controller_t. + * + * This does not alter print.custom.setting.state.status. + * @param function + * The name of the function associated with the error. + * @param status + * The status code to process. + * Make sure this has F_status_set_fine() called if the status code has any error or warning bits. + * @param is_entry + * If TRUE, then this operate as an entry. + * If FALSE, then this operate as an exit. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_perform_debug_pid_file_create_problem_ + extern f_status_t controller_print_perform_debug_pid_file_create_problem(fl_print_t * const print, const f_string_t function, const f_status_t status, const uint8_t is_entry); +#endif // _di_controller_print_perform_debug_pid_file_create_problem_ + +/** + * Print debug message on success when creating PID file. + * + * @param print + * The output structure to print to. + * + * This requires print.custom to be controller_t. + * + * This does not alter print.custom.setting.state.status. + * @param is_entry + * If TRUE, then this operate as an entry. + * If FALSE, then this operate as an exit. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_perform_debug_pid_file_create_success_ + extern f_status_t controller_print_perform_debug_pid_file_create_success(fl_print_t * const print, const uint8_t is_entry); +#endif // _di_controller_print_perform_debug_pid_file_create_success_ + +/** + * Print error message on problems when creating PID file. + * + * @param print + * The output structure to print to. + * + * This requires print.custom to be controller_t. + * + * This does not alter print.custom.setting.state.status. + * @param function + * The name of the function associated with the error. + * @param status + * The status code to process. + * Make sure this has F_status_set_fine() called if the status code has any error or warning bits. + * @param is_entry + * If TRUE, then this operate as an entry. + * If FALSE, then this operate as an exit. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_controller_print_perform_error_pid_file_create_ + extern f_status_t controller_print_perform_error_pid_file_create(fl_print_t * const print, const f_string_t function, const f_status_t status, const uint8_t is_entry); +#endif // _di_controller_print_perform_error_pid_file_create_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_print_perform_h diff --git a/sources/c/main/print/rule/setting.c b/sources/c/main/print/rule/setting.c index b4e8ca1..20db1b8 100644 --- a/sources/c/main/print/rule/setting.c +++ b/sources/c/main/print/rule/setting.c @@ -5,7 +5,7 @@ extern "C" { #endif #ifndef _di_controller_print_rule_setting_read_error_ - f_status_t controller_print_rule_setting_read_error(fl_print_t * const print, const f_string_t message, const f_number_unsigned_t index, const f_number_unsigned_t line_item, controller_thread_t * const thread, controller_cache_t * const cache) { + f_status_t controller_print_rule_setting_read_error(fl_print_t * const print, controller_thread_t * const thread, controller_cache_t * const cache, const f_string_t message, const f_number_unsigned_t index, const f_number_unsigned_t line_item) { if (!print->custom) return F_status_set_error(F_output_not); if (print->verbosity == f_console_verbosity_quiet_e) return F_output_not; @@ -33,7 +33,7 @@ extern "C" { #endif // _di_controller_print_rule_setting_read_error_ #ifndef _di_controller_print_rule_setting_read_error_with_range_ - f_status_t controller_print_rule_setting_read_error_with_range(fl_print_t * const print, const f_string_t before, const f_range_t range, const f_string_t after, const f_number_unsigned_t index, const f_number_unsigned_t line_item, controller_thread_t * const thread, controller_cache_t * const cache) { + f_status_t controller_print_rule_setting_read_error_with_range(fl_print_t * const print, controller_thread_t * const thread, controller_cache_t * const cache, const f_string_t before, const f_range_t range, const f_string_t after, const f_number_unsigned_t index, const f_number_unsigned_t line_item) { if (!print->custom) return F_status_set_error(F_output_not); if (print->verbosity == f_console_verbosity_quiet_e) return F_output_not; @@ -113,7 +113,7 @@ extern "C" { #endif // _di_controller_print_rule_setting_read_value_ #ifndef _di_controller_print_rule_setting_read_values_ - f_status_t controller_print_rule_setting_read_values(controller_t * const main, const f_string_static_t name, const f_number_unsigned_t index, controller_cache_t * const cache) { + f_status_t controller_print_rule_setting_read_values(controller_t * const main, controller_cache_t * const cache, const f_string_static_t name, const f_number_unsigned_t index) { if (main->program.error.verbosity != f_console_verbosity_debug_e) { if (!(main->program.error.verbosity == f_console_verbosity_verbose_e && (main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e))) { diff --git a/sources/c/main/print/rule/setting.h b/sources/c/main/print/rule/setting.h index 1d856a4..6e1c26c 100644 --- a/sources/c/main/print/rule/setting.h +++ b/sources/c/main/print/rule/setting.h @@ -44,7 +44,7 @@ extern "C" { * @see controller_rule_setting_read() */ #ifndef _di_controller_print_rule_setting_read_error_ - extern f_status_t controller_print_rule_setting_read_error(fl_print_t * const print, const f_string_t message, const f_number_unsigned_t index, const f_number_unsigned_t line_item, controller_thread_t * const thread, controller_cache_t * const cache); + extern f_status_t controller_print_rule_setting_read_error(fl_print_t * const print, controller_thread_t * const thread, controller_cache_t * const cache, const f_string_t message, const f_number_unsigned_t index, const f_number_unsigned_t line_item); #endif // _di_controller_print_rule_setting_read_error_ /** @@ -79,7 +79,7 @@ extern "C" { * @see controller_rule_setting_read() */ #ifndef _di_controller_print_rule_setting_read_error_with_range_ - extern f_status_t controller_print_rule_setting_read_error_with_range(fl_print_t * const print, const f_string_t before, const f_range_t range, const f_string_t after, const f_number_unsigned_t index, const f_number_unsigned_t line_item, controller_thread_t * const thread, controller_cache_t * const cache); + extern f_status_t controller_print_rule_setting_read_error_with_range(fl_print_t * const print, controller_thread_t * const thread, controller_cache_t * const cache, const f_string_t before, const f_range_t range, const f_string_t after, const f_number_unsigned_t index, const f_number_unsigned_t line_item); #endif // _di_controller_print_rule_setting_read_error_with_range_ /** @@ -154,7 +154,7 @@ extern "C" { * F_output_not (with error bit) if setting is NULL. */ #ifndef _di_controller_print_rule_setting_read_values_ - extern f_status_t controller_print_rule_setting_read_values(controller_t * const main, const f_string_static_t name, const f_number_unsigned_t index, controller_cache_t * const cache); + extern f_status_t controller_print_rule_setting_read_values(controller_t * const main, controller_cache_t * const cache, const f_string_static_t name, const f_number_unsigned_t index); #endif // _di_controller_print_rule_setting_read_values_ #ifdef __cplusplus diff --git a/sources/c/main/rule/action.c b/sources/c/main/rule/action.c index 053ac87..71486a2 100644 --- a/sources/c/main/rule/action.c +++ b/sources/c/main/rule/action.c @@ -32,7 +32,7 @@ extern "C" { #endif // _di_controller_rule_action_type_to_action_execute_type_ #ifndef _di_controller_rule_action_read_ - f_status_t controller_rule_action_read(controller_t * const main, const bool is_normal, const uint8_t type, const uint8_t method, controller_cache_t * const cache, controller_rule_item_t * const item, controller_rule_actions_t * const actions, f_range_t * const range) { + f_status_t controller_rule_action_read(controller_t * const main, controller_cache_t * const cache, const bool is_normal, const uint8_t type, const uint8_t method, controller_rule_item_t * const item, controller_rule_actions_t * const actions, f_range_t * const range) { if (!main || !item || !actions || !range) return F_status_set_error(F_parameter); @@ -415,7 +415,7 @@ extern "C" { #endif // _di_controller_rule_action_read_ #ifndef _di_controller_rule_action_read_rerun_number_ - f_status_t controller_rule_action_read_rerun_number(controller_t * const main, const f_string_t name, controller_cache_t * const cache, f_number_unsigned_t * const index, f_number_unsigned_t * const number) { + f_status_t controller_rule_action_read_rerun_number(controller_t * const main, controller_cache_t * const cache, const f_string_t name, f_number_unsigned_t * const index, f_number_unsigned_t * const number) { f_status_t status = F_okay; f_number_signed_t parsed = 0; diff --git a/sources/c/main/rule/action.h b/sources/c/main/rule/action.h index e94cf59..58c02a5 100644 --- a/sources/c/main/rule/action.h +++ b/sources/c/main/rule/action.h @@ -93,7 +93,7 @@ extern "C" { * @see f_memory_array_increase_by() */ #ifndef _di_controller_rule_action_read_ - extern f_status_t controller_rule_action_read(controller_t * const main, const bool is_normal, const uint8_t type, const uint8_t method, controller_cache_t * const cache, controller_rule_item_t * const item, controller_rule_actions_t * const actions, f_range_t * const range); + extern f_status_t controller_rule_action_read(controller_t * const main, controller_cache_t * const cache, const bool is_normal, const uint8_t type, const uint8_t method, controller_rule_item_t * const item, controller_rule_actions_t * const actions, f_range_t * const range); #endif // _di_controller_rule_action_read_ /** @@ -129,7 +129,7 @@ extern "C" { * @see fl_conversion_dynamic_partial_to_signed_detect() */ #ifndef _di_controller_rule_action_read_rerun_number_ - extern f_status_t controller_rule_action_read_rerun_number(controller_t * const main, const f_string_t name, controller_cache_t * const cache, f_number_unsigned_t * const index, f_number_unsigned_t * const number); + extern f_status_t controller_rule_action_read_rerun_number(controller_t * const main, controller_cache_t * const cache, const f_string_t name, f_number_unsigned_t * const index, f_number_unsigned_t * const number); #endif // _di_controller_rule_action_read_rerun_number_ diff --git a/sources/c/main/rule/instance.c b/sources/c/main/rule/instance.c index 87209f1..88cbda6 100644 --- a/sources/c/main/rule/instance.c +++ b/sources/c/main/rule/instance.c @@ -566,7 +566,7 @@ extern "C" { #endif // _di_controller_rule_instance_ #ifndef _di_controller_rule_instance_begin_ - f_status_t controller_rule_instance_begin(controller_t * const main, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_number_unsigneds_t stack, const controller_cache_t cache) { + f_status_t controller_rule_instance_begin(controller_t * const main, controller_cache_t * const cache, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_number_unsigneds_t stack) { if (!main) return F_status_set_error(F_parameter); diff --git a/sources/c/main/rule/instance.h b/sources/c/main/rule/instance.h index f2b2473..7733ac2 100644 --- a/sources/c/main/rule/instance.h +++ b/sources/c/main/rule/instance.h @@ -57,6 +57,10 @@ extern "C" { * Must not be NULL. * * This does not alter main.setting.state.status. + * @param cache + * A structure for containing and caching relevant data. + * + * Must not be NULL. * @param options_force * Force the given instance options, only supporting a subset of instance options. * @@ -73,8 +77,6 @@ extern "C" { * @param stack * A stack representing the instances already running in this rule instance dependency tree. * This is used to prevent circular dependencies. - * @param cache - * A structure for containing and caching relevant data. * * @return * F_okay on success. @@ -95,7 +97,7 @@ extern "C" { * @see f_thread_create() */ #ifndef _di_controller_rule_instance_begin_ - extern f_status_t controller_rule_instance_begin(controller_t * const main, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_number_unsigneds_t stack, const controller_cache_t cache); + extern f_status_t controller_rule_instance_begin(controller_t * const main, controller_cache_t * const cache, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_number_unsigneds_t stack); #endif // _di_controller_rule_instance_begin_ /** diff --git a/sources/c/main/rule/item.c b/sources/c/main/rule/item.c index d866bb8..d7bdf5b 100644 --- a/sources/c/main/rule/item.c +++ b/sources/c/main/rule/item.c @@ -5,7 +5,7 @@ extern "C" { #endif #ifndef _di_controller_rule_item_read_ - f_status_t controller_rule_item_read(controller_t * const main, const bool is_normal, controller_cache_t * const cache, controller_rule_item_t * const item) { + f_status_t controller_rule_item_read(controller_t * const main, controller_cache_t * const cache, const bool is_normal, controller_rule_item_t * const item) { if (!main || !cache || !item) return F_status_set_error(F_parameter); diff --git a/sources/c/main/rule/item.h b/sources/c/main/rule/item.h index 329ba5c..4eea1f6 100644 --- a/sources/c/main/rule/item.h +++ b/sources/c/main/rule/item.h @@ -47,7 +47,7 @@ extern "C" { * @see f_string_dynamic_partial_append_nulless() */ #ifndef _di_controller_rule_item_read_ - extern f_status_t controller_rule_item_read(controller_t * const main, const bool is_normal, controller_cache_t * const cache, controller_rule_item_t * const item); + extern f_status_t controller_rule_item_read(controller_t * const main, controller_cache_t * const cache, const bool is_normal, controller_rule_item_t * const item); #endif // _di_controller_rule_item_read_ #ifdef __cplusplus diff --git a/sources/c/main/rule/read.c b/sources/c/main/rule/read.c index c406aa2..7c9611f 100644 --- a/sources/c/main/rule/read.c +++ b/sources/c/main/rule/read.c @@ -5,7 +5,7 @@ extern "C" { #endif #ifndef _di_controller_rule_read_ - f_status_t controller_rule_read(controller_t * const main, const bool is_normal, const f_string_static_t alias, controller_cache_t * const cache, controller_entry_t * const entry, controller_rule_t * const rule) { + f_status_t controller_rule_read(controller_t * const main, controller_cache_t * const cache, const bool is_normal, const f_string_static_t alias, controller_entry_t * const entry, controller_rule_t * const rule) { if (!main || !cache || !entry || !rule) return F_status_set_error(F_parameter); diff --git a/sources/c/main/rule/read.h b/sources/c/main/rule/read.h index 2b9978f..0f52db9 100644 --- a/sources/c/main/rule/read.h +++ b/sources/c/main/rule/read.h @@ -55,7 +55,7 @@ extern "C" { * @see fll_fss_basic_list_read(). */ #ifndef _di_controller_rule_read_ - extern f_status_t controller_rule_read(controller_t * const main, const bool is_normal, const f_string_static_t alias, controller_cache_t * const cache, controller_entry_t * const entry, controller_rule_t * const rule); + extern f_status_t controller_rule_read(controller_t * const main, controller_cache_t * const cache, const bool is_normal, const f_string_static_t alias, controller_entry_t * const entry, controller_rule_t * const rule); #endif // _di_controller_rule_read_ diff --git a/sources/c/main/rule/setting.c b/sources/c/main/rule/setting.c index 6dc0f5f..118b009 100644 --- a/sources/c/main/rule/setting.c +++ b/sources/c/main/rule/setting.c @@ -86,7 +86,7 @@ extern "C" { #endif // _di_controller_rule_setting_limit_type_name_ #ifndef _di_controller_rule_setting_read_ - f_status_t controller_rule_setting_read(controller_t * const main, const bool is_normal, controller_cache_t * const cache, controller_rule_t * const rule) { + f_status_t controller_rule_setting_read(controller_t * const main, controller_cache_t * const cache, const bool is_normal, controller_rule_t * const rule) { if (!main || !cache || !rule) return F_status_set_error(F_parameter); diff --git a/sources/c/main/rule/setting.h b/sources/c/main/rule/setting.h index a5e1e0d..a0ded7b 100644 --- a/sources/c/main/rule/setting.h +++ b/sources/c/main/rule/setting.h @@ -86,7 +86,7 @@ extern "C" { * @see controller_path_canonical_relative() */ #ifndef _di_controller_rule_setting_read_ - extern f_status_t controller_rule_setting_read(controller_t * const main, const bool is_normal, controller_cache_t * const cache, controller_rule_t * const rule); + extern f_status_t controller_rule_setting_read(controller_t * const main, controller_cache_t * const cache, const bool is_normal, controller_rule_t * const rule); #endif // _di_controller_rule_setting_read_ #ifdef __cplusplus diff --git a/sources/c/main/rule/validate.c b/sources/c/main/rule/validate.c index 9f0ca7a..1c0f389 100644 --- a/sources/c/main/rule/validate.c +++ b/sources/c/main/rule/validate.c @@ -5,7 +5,7 @@ extern "C" { #endif #ifndef _di_controller_rule_validate_ - void controller_rule_validate(controller_t * const main, const controller_rule_t rule, const uint8_t action, const uint8_t options, controller_cache_t * const cache) { + void controller_rule_validate(controller_t * const main, controller_cache_t * const cache, const controller_rule_t rule, const uint8_t action, const uint8_t options) { if (!main || !cache) return; @@ -339,7 +339,7 @@ extern "C" { fl_print_format(" %[%r%] {%r", main->program.output.to, main->program.context.set.important, controller_item_s, main->program.context.set.important, f_string_eol_s); // Type. - fl_print_format(" %[%r%] %Q%r", main->program.output.to, main->program.context.set.important, controller_type_s, main->program.context.set.important, controller_rule_item_type_name(item->type), f_string_eol_s); + fl_print_format(" %[%r%] %Q%r", main->program.output.to, main->program.context.set.important, controller_type_s, main->program.context.set.important, controller_convert_rule_item_type_string(item->type), f_string_eol_s); // Pid file. fl_print_format(" %[%r%]", main->program.output.to, main->program.context.set.important, controller_pid_file_s, main->program.context.set.important); diff --git a/sources/c/main/rule/validate.h b/sources/c/main/rule/validate.h index 052afb3..0cc3694 100644 --- a/sources/c/main/rule/validate.h +++ b/sources/c/main/rule/validate.h @@ -42,7 +42,7 @@ extern "C" { * A structure for containing and caching relevant data. */ #ifndef _di_controller_rule_validate_ - extern void controller_rule_validate(controller_t * const main, const controller_rule_t rule, const uint8_t action, const uint8_t options, controller_cache_t * const cache); + extern void controller_rule_validate(controller_t * const main, controller_cache_t * const cache, const controller_rule_t rule, const uint8_t action, const uint8_t options); #endif // _di_controller_rule_validate_ #ifdef __cplusplus diff --git a/sources/c/main/thread/entry.c b/sources/c/main/thread/entry.c index dc209b7..b5a739f 100644 --- a/sources/c/main/thread/entry.c +++ b/sources/c/main/thread/entry.c @@ -29,7 +29,7 @@ extern "C" { *status = controller_entry_preprocess(main, F_true); if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) { - controller_entry_setting_validate(main, F_true); + controller_print_entry_validate_setting(main, F_true); } } @@ -145,10 +145,10 @@ extern "C" { main->process.ready = controller_process_ready_done_e; } else if (*status != F_child) { - *status = controller_entry_preprocess(main, F_false, cache); + *status = controller_entry_preprocess(main, F_false); if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) { - controller_entry_setting_validate(main, F_false, cache); + controller_print_entry_validate_setting(main, F_false); } }