]> Kevux Git Server - controller/commitdiff
Progress: Continue migrating the project.
authorKevin Day <Kevin@kevux.org>
Tue, 4 Jun 2024 05:35:02 +0000 (00:35 -0500)
committerKevin Day <Kevin@kevux.org>
Tue, 4 Jun 2024 05:35:02 +0000 (00:35 -0500)
43 files changed:
data/build/settings
sources/c/main/common/print.c
sources/c/main/common/print.h
sources/c/main/controller.h
sources/c/main/convert.c
sources/c/main/convert.h
sources/c/main/entry.c [new file with mode: 0644]
sources/c/main/entry.h [new file with mode: 0644]
sources/c/main/entry/action.c [new file with mode: 0644]
sources/c/main/entry/action.h [new file with mode: 0644]
sources/c/main/entry/preprocess.c [new file with mode: 0644]
sources/c/main/entry/preprocess.h [new file with mode: 0644]
sources/c/main/entry/process.c [new file with mode: 0644]
sources/c/main/entry/process.h [new file with mode: 0644]
sources/c/main/entry/setting.c [new file with mode: 0644]
sources/c/main/entry/setting.h [new file with mode: 0644]
sources/c/main/perform.c [new file with mode: 0644]
sources/c/main/perform.h [new file with mode: 0644]
sources/c/main/print/entry.c [new file with mode: 0644]
sources/c/main/print/entry.h [new file with mode: 0644]
sources/c/main/print/entry/setting.c [new file with mode: 0644]
sources/c/main/print/entry/setting.h [new file with mode: 0644]
sources/c/main/print/entry/simulate.c [new file with mode: 0644]
sources/c/main/print/entry/simulate.h [new file with mode: 0644]
sources/c/main/print/entry/validate.c [new file with mode: 0644]
sources/c/main/print/entry/validate.h [new file with mode: 0644]
sources/c/main/print/perform.c [new file with mode: 0644]
sources/c/main/print/perform.h [new file with mode: 0644]
sources/c/main/print/rule/setting.c
sources/c/main/print/rule/setting.h
sources/c/main/rule/action.c
sources/c/main/rule/action.h
sources/c/main/rule/instance.c
sources/c/main/rule/instance.h
sources/c/main/rule/item.c
sources/c/main/rule/item.h
sources/c/main/rule/read.c
sources/c/main/rule/read.h
sources/c/main/rule/setting.c
sources/c/main/rule/setting.h
sources/c/main/rule/validate.c
sources/c/main/rule/validate.h
sources/c/main/thread/entry.c

index 256af7105beea98ff977eb3693a8a918b8ad3be6..5c17d3d4882d8cdf1657ddd825856cf80ffddcd6 100644 (file)
@@ -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
index 999d311cbfe842a17c73a69127febc6c4d052a4d..a48950369f0f686ebb0f0b4f5a618a64dca91312 100644 (file)
@@ -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",
index a8b6feb02eedea86adeb228abc27aa2a86bc5c26..7bf23810c5d5de4c9b4c63ebc5882e2ad9249194 100644 (file)
@@ -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,
index b1a004775554f85eb187fccb8353dc6d482b7c20..d767d8476c8f9b9045c075a8c1b99b23c80a9ea3 100644 (file)
 #include <program/controller/main/convert.h>
 #include <program/controller/main/lock.h>
 #include <program/controller/main/path.h>
+#include <program/controller/main/perform.h>
 #include <program/controller/main/print/action.h>
 #include <program/controller/main/print/data.h>
 #include <program/controller/main/print/debug.h>
index b58200d1c513998511e83ec79518b50919ff9025..59c59cbd5e1d5f62c8e5d47aa11ec3fc2d190726 100644 (file)
@@ -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
index 07850ffe373fa803f6d20899978ef6a9729aec38..d07096a0bc9e94ba7a8e4901c64c35418f58088b 100644 (file)
@@ -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 (file)
index 0000000..ea4d9a2
--- /dev/null
@@ -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 (file)
index 0000000..a9d340d
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/sources/c/main/entry/action.h b/sources/c/main/entry/action.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/sources/c/main/entry/preprocess.c b/sources/c/main/entry/preprocess.c
new file mode 100644 (file)
index 0000000..dc6e3ea
--- /dev/null
@@ -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 (file)
index 0000000..d3f02f5
--- /dev/null
@@ -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 (file)
index 0000000..164a36f
--- /dev/null
@@ -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 (file)
index 0000000..ee3b1d5
--- /dev/null
@@ -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 (file)
index 0000000..3ec0197
--- /dev/null
@@ -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 (file)
index 0000000..17347e9
--- /dev/null
@@ -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 (file)
index 0000000..70d0538
--- /dev/null
@@ -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 (file)
index 0000000..cb332fe
--- /dev/null
@@ -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 (file)
index 0000000..a7c42c3
--- /dev/null
@@ -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 (file)
index 0000000..9a837d1
--- /dev/null
@@ -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 (file)
index 0000000..971e390
--- /dev/null
@@ -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 (file)
index 0000000..598577c
--- /dev/null
@@ -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 (file)
index 0000000..e77f991
--- /dev/null
@@ -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 (file)
index 0000000..dfc2f2d
--- /dev/null
@@ -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 (file)
index 0000000..1505136
--- /dev/null
@@ -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 (file)
index 0000000..888fd76
--- /dev/null
@@ -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 (file)
index 0000000..2d5da06
--- /dev/null
@@ -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 (file)
index 0000000..c9c276f
--- /dev/null
@@ -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
index b4e8ca141bba5a1b4a9fce5114c6a6e69e896db5..20db1b860bc57661234e941ce91cca3e67bd75c8 100644 (file)
@@ -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))) {
index 1d856a440afa4264bfe38cb0418aad68da203b23..6e1c26c16675059553858d48ce97f412a3c8727f 100644 (file)
@@ -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
index 053ac876aa632df79e759eb3a64d08839a173e83..71486a2b28ffb1aac7c241a130f6128610453314 100644 (file)
@@ -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;
index e94cf5912063f432e53d30021118b9054bbe7bb4..58c02a54707e114adf422c6c1ec949f557220e08 100644 (file)
@@ -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_
 
 
index 87209f1ba76345db167c45ec5ed206ce52da1a06..88cbda65bd6340e82ac6938e1642e91398c87cd5 100644 (file)
@@ -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);
 
index f2b24732315e20208167b818aea17d76fc78ac44..7733ac21a967b97dbab54d8bfca7d562663a0cfe 100644 (file)
@@ -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_
 
 /**
index d866bb8ea79b8bbd8872f112c305dfc099becf67..d7bdf5b6c5e774d6d3ae5f2be11721a0cdc30643 100644 (file)
@@ -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);
 
index 329ba5c63a7ef8bb6d55826a89d7aff99a50df47..4eea1f6302887b1a4ed856a83060f805bb5e4843 100644 (file)
@@ -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
index c406aa2709bfba7ba16c0a81e7f3b84c3f863d7b..7c9611f2c61dfebab0ae2f51f59b0bbca3b8d03c 100644 (file)
@@ -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);
 
index 2b9978f688dc73e80b4c0f3075b6b2f488527920..0f52db923783dcf7483ae31d1d5b7949ad815b8b 100644 (file)
@@ -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_
 
 
index 6dc0f5fa95e643a4f4828d889babb7e766cdcc95..118b009c637fe8df9ce3c34fa3a4c56617683f2b 100644 (file)
@@ -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);
 
index a5e1e0d6e34c9079448035e0a834976a53ee7137..a0ded7b8c71751eafbc368947a47a33c2e28b933 100644 (file)
@@ -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
index 9f0ca7a29cec2f30f0fdf5284c3ac80a8a8d3ed3..1c0f389fa34f2ecd2fa13b33698a418603702c63 100644 (file)
@@ -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);
index 052afb3c1ad0dc88a7423c959da368b1288c69cd..0cc3694cb1d50ba2b413a469a24a9f980fb96fb5 100644 (file)
@@ -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
index dc209b74ffb6ecbe17327ffe8125476c27bad9a1..b5a739f169bfe3ee0b5b0a228c0354069dd5b2f5 100644 (file)
@@ -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);
       }
     }