]> Kevux Git Server - fll/commitdiff
Progress: controller program.
authorKevin Day <thekevinday@gmail.com>
Thu, 10 Dec 2020 04:14:45 +0000 (22:14 -0600)
committerKevin Day <thekevinday@gmail.com>
Thu, 10 Dec 2020 04:14:45 +0000 (22:14 -0600)
This includes changes using static variables that was introduced in a previous commit at the entire fll project level.

Begin implementing the simulation execution.
There is much to do here and the simulation is already showing problems that need to be resolved (such as in the rule loading process).

level_3/controller/c/controller.c
level_3/controller/c/private-common.h
level_3/controller/c/private-controller.c
level_3/controller/c/private-controller.h
level_3/controller/c/private-entry.c
level_3/controller/c/private-entry.h
level_3/controller/c/private-rule.c
level_3/controller/c/private-rule.h

index d95d6adb706720b5206bbf1624cb5e7484cdedf3..56d575801d7fb0f0f0773f99aea0d8f9f9584ae3 100644 (file)
@@ -24,7 +24,7 @@ extern "C" {
     fll_program_print_help_option(output, context, f_console_standard_short_debug, f_console_standard_long_debug, f_console_symbol_short_disable, f_console_symbol_long_disable, "   Enable debugging, inceasing verbosity beyond normal output.");
     fll_program_print_help_option(output, context, f_console_standard_short_version, f_console_standard_long_version, f_console_symbol_short_disable, f_console_symbol_long_disable, " Print only the version number.");
 
-    fprintf(output.stream, "%c", f_string_eol[0]);
+    fprintf(output.stream, "%c", f_string_eol_s[0]);
 
     fll_program_print_help_option(output, context, controller_short_daemon, controller_long_daemon, f_console_symbol_short_enable, f_console_symbol_long_enable, "       Run in daemon only mode (do not process the entry).");
     fll_program_print_help_option(output, context, controller_short_interruptable, controller_long_interruptable, f_console_symbol_short_enable, f_console_symbol_long_enable, "Designate that this program can be interrupted.");
@@ -60,21 +60,38 @@ extern "C" {
           data->warning.notable = data->context.set.notable;
         }
         else {
-          data->error.context.before = &fll_error_string_null_s;
-          data->error.context.after = &fll_error_string_null_s;
-          data->error.notable.before = &fll_error_string_null_s;
-          data->error.notable.after = &fll_error_string_null_s;
-
-          data->warning.context.before = &fll_error_string_null_s;
-          data->warning.context.after = &fll_error_string_null_s;
-          data->warning.notable.before = &fll_error_string_null_s;
-          data->warning.notable.after = &fll_error_string_null_s;
+          data->context.set.warning.before = &f_color_set_string_null_s;
+          data->context.set.warning.after = &f_color_set_string_null_s;
+          data->context.set.error.before = &f_color_set_string_null_s;
+          data->context.set.error.after = &f_color_set_string_null_s;
+          data->context.set.title.before = &f_color_set_string_null_s;
+          data->context.set.title.after = &f_color_set_string_null_s;
+          data->context.set.notable.before = &f_color_set_string_null_s;
+          data->context.set.notable.after = &f_color_set_string_null_s;
+          data->context.set.important.before = &f_color_set_string_null_s;
+          data->context.set.important.after = &f_color_set_string_null_s;
+          data->context.set.standout.before = &f_color_set_string_null_s;
+          data->context.set.standout.after = &f_color_set_string_null_s;
+          data->context.set.normal.before = &f_color_set_string_null_s;
+          data->context.set.normal.after = &f_color_set_string_null_s;
+          data->context.set.normal_reset.before = &f_color_set_string_null_s;
+          data->context.set.normal_reset.after = &f_color_set_string_null_s;
+
+          data->error.context.before = &f_color_set_string_null_s;
+          data->error.context.after = &f_color_set_string_null_s;
+          data->error.notable.before = &f_color_set_string_null_s;
+          data->error.notable.after = &f_color_set_string_null_s;
+
+          data->warning.context.before = &f_color_set_string_null_s;
+          data->warning.context.after = &f_color_set_string_null_s;
+          data->warning.notable.before = &f_color_set_string_null_s;
+          data->warning.notable.after = &f_color_set_string_null_s;
         }
 
         if (F_status_is_error(status)) {
           if (data->error.verbosity != f_console_verbosity_quiet) {
             fll_error_print(data->error, F_status_set_fine(status), "fll_program_parameter_process", F_true);
-            fprintf(data->error.to.stream, "%c", f_string_eol[0]);
+            fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
           }
 
           controller_delete_data(data);
@@ -148,10 +165,10 @@ extern "C" {
 
     if (data->parameters[controller_parameter_settings].result == f_console_result_found) {
       if (data->error.verbosity != f_console_verbosity_quiet) {
-        fprintf(data->error.to.stream, "%c", f_string_eol[0]);
-        fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : "");
+        fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+        fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
         fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_settings, data->error.notable.after->string);
-        fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol[0]);
+        fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
       }
 
       status = F_status_set_error(F_parameter);
@@ -179,10 +196,10 @@ extern "C" {
 
     if (data->parameters[controller_parameter_pid].result == f_console_result_found) {
       if (data->error.verbosity != f_console_verbosity_quiet) {
-        fprintf(data->error.to.stream, "%c", f_string_eol[0]);
-        fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : "");
+        fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+        fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
         fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_pid, data->error.notable.after->string);
-        fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol[0]);
+        fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
       }
 
       status = F_status_set_error(F_parameter);
@@ -201,10 +218,10 @@ extern "C" {
       }
       else {
         if (data->warning.verbosity == f_console_verbosity_debug) {
-          fprintf(data->warning.to.stream, "%c", f_string_eol[0]);
-          fprintf(data->warning.to.stream, "%s%sThe parameter '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : "");
+          fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data->warning.to.stream, "%s%sThe parameter '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s);
           fprintf(data->warning.to.stream, "%s%s%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, f_console_symbol_long_enable, controller_long_pid, data->warning.notable.after->string);
-          fprintf(data->warning.to.stream, "%s' must be a file path but instead is an empty string, falling back to the default.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol[0]);
+          fprintf(data->warning.to.stream, "%s' must be a file path but instead is an empty string, falling back to the default.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]);
         }
       }
     }
@@ -224,12 +241,12 @@ extern "C" {
 
       if (data->parameters[controller_parameter_validate].result == f_console_result_found) {
         if (data->error.verbosity != f_console_verbosity_quiet) {
-          fprintf(data->error.to.stream, "%c", f_string_eol[0]);
-          fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : "");
+          fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
           fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_validate, data->error.notable.after->string);
           fprintf(data->error.to.stream, "%s' must not be specified with the parameter '", data->error.context.before->string);
           fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_daemon, data->error.notable.after->string);
-          fprintf(data->error.to.stream, "%s'.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol[0]);
+          fprintf(data->error.to.stream, "%s'.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
         }
 
         status = F_status_set_error(F_parameter);
@@ -240,8 +257,8 @@ extern "C" {
 
         if (f_file_exists(setting.path_pid.string) == F_true) {
           if (data->error.verbosity != f_console_verbosity_quiet) {
-            fprintf(data->error.to.stream, "%c", f_string_eol[0]);
-            fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : "", data->error.context.after->string, f_string_eol[0]);
+            fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s, data->error.context.after->string, f_string_eol_s[0]);
           }
 
           status = F_status_set_error(F_available_not);
@@ -269,8 +286,8 @@ extern "C" {
 
           if (f_file_exists(setting.path_pid.string) == F_true) {
             if (data->error.verbosity != f_console_verbosity_quiet) {
-              fprintf(data->error.to.stream, "%c", f_string_eol[0]);
-              fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : "", data->error.context.after->string, f_string_eol[0]);
+              fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data->error.to.stream, "%s%sThe pid file must not already exist.%s%c", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s, data->error.context.after->string, f_string_eol_s[0]);
             }
 
             status = F_status_set_error(F_available_not);
@@ -298,7 +315,7 @@ extern "C" {
     // ensure a newline is always put at the end of the program execution, unless in quiet mode.
     if (data->error.verbosity != f_console_verbosity_quiet) {
       if (F_status_is_error(status)) {
-        fprintf(data->error.to.stream, "%c", f_string_eol[0]);
+        fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
       }
     }
 
index 342e233c9c4dd6964a83e68bcb54d974faf5e379..5208035fcf39b05a7eff91af58d28205497d0155 100644 (file)
@@ -13,6 +13,7 @@ extern "C" {
 #endif
 
 #ifndef _di_controller_string_
+  #define controller_string_action        "action"
   #define controller_string_asynchronous  "asynchronous"
   #define controller_string_create        "create"
   #define controller_string_command       "command"
@@ -28,6 +29,7 @@ extern "C" {
   #define controller_string_item          "item"
   #define controller_string_kill          "kill"
   #define controller_string_main          "main"
+  #define controller_string_method        "method"
   #define controller_string_name          "name"
   #define controller_string_need          "need"
   #define controller_string_parameter     "parameter"
@@ -41,16 +43,18 @@ extern "C" {
   #define controller_string_rules         "rules"
   #define controller_string_script        "script"
   #define controller_string_service       "service"
-  #define controller_string_settings      "settings"
+  #define controller_string_setting       "setting"
   #define controller_string_start         "start"
   #define controller_string_stop          "stop"
   #define controller_string_timeout       "timeout"
+  #define controller_string_type          "type"
   #define controller_string_use           "use"
   #define controller_string_user          "user"
   #define controller_string_wait          "wait"
   #define controller_string_want          "want"
   #define controller_string_wish          "wish"
 
+  #define controller_string_action_length        6
   #define controller_string_asynchronous_length  12
   #define controller_string_create_length        6
   #define controller_string_command_length       7
@@ -66,6 +70,7 @@ extern "C" {
   #define controller_string_item_length          4
   #define controller_string_kill_length          4
   #define controller_string_main_length          4
+  #define controller_string_method_length        6
   #define controller_string_name_length          4
   #define controller_string_need_length          4
   #define controller_string_parameter_length     9
@@ -79,10 +84,11 @@ extern "C" {
   #define controller_string_rules_length         5
   #define controller_string_script_length        6
   #define controller_string_service_length       7
-  #define controller_string_settings_length      8
+  #define controller_string_setting_length       7
   #define controller_string_start_length         5
   #define controller_string_stop_length          4
   #define controller_string_timeout_length       7
+  #define controller_string_type_length          4
   #define controller_string_use_length           3
   #define controller_string_user_length          4
   #define controller_string_wait_length          4
@@ -91,6 +97,12 @@ extern "C" {
 #endif // _di_controller_string_
 
 #ifndef _di_controller_rule_action_t_
+  #define controller_rule_action_method_string_extended      "FSS-0001 (Extended)"
+  #define controller_rule_action_method_string_extended_list "FSS-0003 (Extended List)"
+
+  #define controller_rule_action_method_string_extended_length      19
+  #define controller_rule_action_method_string_extended_list_length 24
+
   enum {
     controller_rule_action_method_extended = 1,
     controller_rule_action_method_extended_list,
@@ -162,7 +174,7 @@ extern "C" {
     controller_rule_item_type_command = 1,
     controller_rule_item_type_script,
     controller_rule_item_type_service,
-    controller_rule_item_type_settings,
+    controller_rule_item_type_setting,
   };
 
   typedef struct {
index 057ebf9d5fb58c6826565ab52c30014acd744b42..f7b93d197b94bfb790e0afd4e309aae0abd215f0 100644 (file)
@@ -9,49 +9,6 @@
 extern "C" {
 #endif
 
-#ifndef _di_controller_entry_action_type_name_
-  f_string_static_t controller_entry_action_type_name(const uint8_t type) {
-
-    f_string_static_t buffer = f_string_static_t_initialize;
-
-    switch (type) {
-      case controller_entry_action_type_consider:
-        buffer.string = controller_string_consider;
-        buffer.used = controller_string_consider_length;
-        break;
-
-      case controller_entry_action_type_failsafe:
-        buffer.string = controller_string_failsafe;
-        buffer.used = controller_string_failsafe_length;
-        break;
-
-      case controller_entry_action_type_item:
-        buffer.string = controller_string_item;
-        buffer.used = controller_string_item_length;
-        break;
-
-      case controller_entry_action_type_ready:
-        buffer.string = controller_string_ready;
-        buffer.used = controller_string_ready_length;
-        break;
-
-      case controller_entry_action_type_rule:
-        buffer.string = controller_string_rule;
-        buffer.used = controller_string_rule_length;
-        break;
-
-      case controller_entry_action_type_timeout:
-        buffer.string = controller_string_timeout;
-        buffer.used = controller_string_timeout_length;
-        break;
-    }
-
-    buffer.size = buffer.used;
-
-    return buffer;
-  }
-#endif // _di_controller_entry_action_type_name_
-
 #ifndef _di_controller_string_dynamic_append_terminated_
   f_return_status controller_string_dynamic_append_terminated(const f_string_static_t source, f_string_dynamic_t *destination) {
 
@@ -358,10 +315,10 @@ extern "C" {
 
           if (setting->ready == controller_setting_ready_wait) {
             if (data.warning.verbosity == f_console_verbosity_debug) {
-              fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-              fprintf(data.warning.to.stream, "%s%sMultiple '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "");
+              fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data.warning.to.stream, "%s%sMultiple '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
               fprintf(data.warning.to.stream, "%s%s%s%s", data.warning.context.after->string, data.warning.notable.before->string, controller_string_ready, data.warning.notable.after->string);
-              fprintf(data.warning.to.stream, "%s' entry item actions detected; only the first will be used.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol[0]);
+              fprintf(data.warning.to.stream, "%s' entry item actions detected; only the first will be used.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]);
 
               controller_entry_error_print(data.warning, *cache);
             }
@@ -387,10 +344,10 @@ extern "C" {
 
                 if (cache->ats.array[j] == i) {
                   if (data.error.verbosity != f_console_verbosity_quiet) {
-                    fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                    fprintf(data.error.to.stream, "%s%sThe entry item named '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+                    fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                    fprintf(data.error.to.stream, "%s%sThe entry item named '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
                     fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting->entry.items.array[i].name.string, data.error.notable.after->string);
-                    fprintf(data.error.to.stream, "%s' cannot be executed because recursion is not allowed.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                    fprintf(data.error.to.stream, "%s' cannot be executed because recursion is not allowed.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
                   }
 
                   controller_entry_error_print(data.error, *cache);
@@ -448,10 +405,10 @@ extern "C" {
           if (error_has || i >= setting->entry.items.used) {
             if (i >= setting->entry.items.used) {
               if (data.error.verbosity != f_console_verbosity_quiet) {
-                fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                fprintf(data.error.to.stream, "%s%sThe entry item named '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sThe entry item named '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
                 fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, actions->array[cache->ats.array[at_j]].parameters.array[0].string, data.error.notable.after->string);
-                fprintf(data.error.to.stream, "%s' does not exist.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                fprintf(data.error.to.stream, "%s' does not exist.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
               }
 
               controller_entry_error_print(data.error, *cache);
@@ -590,10 +547,10 @@ extern "C" {
 
             // 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 (data.error.verbosity != f_console_verbosity_quiet) {
-              fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-              fprintf(data.error.to.stream, "%s%sInvalid entry item index ", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data.error.to.stream, "%s%sInvalid entry item index ", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
               fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data.error.notable.after->string);
-              fprintf(data.error.to.stream, "%s detected.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+              fprintf(data.error.to.stream, "%s detected.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
             }
 
             controller_entry_error_print(data.error, *cache);
index 9467033d3089aa724c17cba653c85c0c2512d7a8..06352daf02d914e3344cf37fdc76aad66a8b76a9 100644 (file)
@@ -13,20 +13,6 @@ extern "C" {
 #endif
 
 /**
- * Get a string representing the entry action type.
- *
- * @param type
- *   The entry action type code.
- *
- * @return
- *   The string with used > 0 on success.
- *   The string with used == 0 if no match was found.
- */
-#ifndef _di_controller_entry_action_type_name_
-  extern f_string_static_t controller_entry_action_type_name(const uint8_t type) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_entry_action_type_name_
-
-/**
  * Append a string and then add a NULL after the end of the string.
  *
  * @param source
index 4d124ae5fd787df6db010168902d1bcebebf8f97..a53be8614d8fa236801cb310b5739f75f4410552 100644 (file)
@@ -7,6 +7,49 @@
 extern "C" {
 #endif
 
+#ifndef _di_controller_entry_action_type_name_
+  f_string_static_t controller_entry_action_type_name(const uint8_t type) {
+
+    f_string_static_t buffer = f_string_static_t_initialize;
+
+    switch (type) {
+      case controller_entry_action_type_consider:
+        buffer.string = controller_string_consider;
+        buffer.used = controller_string_consider_length;
+        break;
+
+      case controller_entry_action_type_failsafe:
+        buffer.string = controller_string_failsafe;
+        buffer.used = controller_string_failsafe_length;
+        break;
+
+      case controller_entry_action_type_item:
+        buffer.string = controller_string_item;
+        buffer.used = controller_string_item_length;
+        break;
+
+      case controller_entry_action_type_ready:
+        buffer.string = controller_string_ready;
+        buffer.used = controller_string_ready_length;
+        break;
+
+      case controller_entry_action_type_rule:
+        buffer.string = controller_string_rule;
+        buffer.used = controller_string_rule_length;
+        break;
+
+      case controller_entry_action_type_timeout:
+        buffer.string = controller_string_timeout;
+        buffer.used = controller_string_timeout_length;
+        break;
+    }
+
+    buffer.size = buffer.used;
+
+    return buffer;
+  }
+#endif // _di_controller_entry_action_type_name_
+
 #ifndef _di_controller_entry_actions_increase_by_
   f_return_status controller_entry_actions_increase_by(const f_array_length_t amount, controller_entry_actions_t *actions) {
 
@@ -109,8 +152,7 @@ extern "C" {
         break;
       }
 
-      cache->line_action++;
-      action->line = cache->line_action;
+      action->line = ++cache->line_action;
 
       status = fl_string_dynamic_rip_nulless(cache->buffer_file, cache->object_actions.array[i], &cache->name_action);
 
@@ -146,8 +188,8 @@ extern "C" {
       }
       else {
         if (data.warning.verbosity == f_console_verbosity_debug) {
-          fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-          fprintf(data.warning.to.stream, "%s%sUnknown entry item type.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
+          fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.warning.to.stream, "%s%sUnknown entry item type.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s, data.warning.context.after->string, f_string_eol_s[0]);
 
           controller_entry_error_print(data.warning, *cache);
         }
@@ -181,14 +223,14 @@ extern "C" {
         action->status = F_status_set_error(F_parameter);
 
         if (data.error.verbosity != f_console_verbosity_quiet) {
-          fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-          fprintf(data.error.to.stream, "%s%sThe entry item action '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.error.to.stream, "%s%sThe entry item action '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
           fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->name_action.string, data.error.notable.after->string);
           fprintf(data.error.to.stream, "%s' requires ", data.error.context.before->string);
 
           if (action->type == controller_entry_action_type_failsafe || action->type == controller_entry_action_type_item) {
             fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, cache->line_action, data.error.notable.after->string);
-            fprintf(data.error.to.stream, "%s or more parameters.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+            fprintf(data.error.to.stream, "%s or more parameters.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
           }
           else {
             uint8_t parameters = 0;
@@ -202,7 +244,7 @@ extern "C" {
 
             fprintf(data.error.to.stream, "exactly ", data.error.context.before->string);
             fprintf(data.error.to.stream, "%s%s%u%s", data.error.context.after->string, parameters, data.error.notable.after->string);
-            fprintf(data.error.to.stream, "%s parameters.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+            fprintf(data.error.to.stream, "%s parameters.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
           }
         }
       }
@@ -284,8 +326,8 @@ extern "C" {
               }
 
               if (data.error.verbosity != f_console_verbosity_quiet) {
-                fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                fprintf(data.error.to.stream, "%s%sThe entry item action must not have an empty string for a path (the first parameter).%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sThe entry item action must not have an empty string for a path (the first parameter).%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
               }
             }
 
@@ -326,12 +368,12 @@ extern "C" {
                       break;
                     }
 
-                    fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                    fprintf(data.error.to.stream, "%s%sThe entry item action second parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+                    fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                    fprintf(data.error.to.stream, "%s%sThe entry item action second parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
                     fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, action->parameters.array[1].string, data.error.notable.after->string);
                     fprintf(data.error.to.stream, "%s' must be a base path name, such as '", data.error.context.before->string);
                     fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->buffer_path.string, data.error.notable.after->string);
-                    fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                    fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
                   }
 
                   action->status = F_status_set_error(F_parameter);
@@ -350,8 +392,8 @@ extern "C" {
               }
 
               if (data.error.verbosity != f_console_verbosity_quiet) {
-                fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                fprintf(data.error.to.stream, "%s%sThe entry item action must not have an empty string for a rule name (the second parameter).%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sThe entry item action must not have an empty string for a rule name (the second parameter).%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
               }
             }
 
@@ -376,8 +418,8 @@ extern "C" {
                 }
 
                 if (data.error.verbosity != f_console_verbosity_quiet) {
-                  fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                  fprintf(data.error.to.stream, "%s%sThe entry item action third parameter (and beyond) must be one of '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+                  fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                  fprintf(data.error.to.stream, "%s%sThe entry item action third parameter (and beyond) must be one of '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
                   fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_asynchronous, data.error.notable.after->string);
                   fprintf(data.error.to.stream, "%s', '", data.error.context.before->string);
                   fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_require, data.error.notable.after->string);
@@ -385,7 +427,7 @@ extern "C" {
                   fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_wait, data.error.notable.after->string);
                   fprintf(data.error.to.stream, "%s' but instead has '", data.error.context.before->string);
                   fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, action->parameters.array[j].string, data.error.notable.after->string);
-                  fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                  fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
                 }
               }
             } // for
@@ -399,10 +441,10 @@ extern "C" {
               }
 
               if (data.error.verbosity != f_console_verbosity_quiet) {
-                fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                fprintf(data.error.to.stream, "%s%sThe entry item action may not specify the reserved item '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sThe entry item action may not specify the reserved item '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
                 fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_main, data.error.notable.after->string);
-                fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
               }
             }
           }
@@ -424,8 +466,8 @@ extern "C" {
               }
 
               if (data.error.verbosity != f_console_verbosity_quiet) {
-                fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                fprintf(data.error.to.stream, "%s%sThe entry item action must have one of '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sThe entry item action must have one of '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
                 fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_kill, data.error.notable.after->string);
                 fprintf(data.error.to.stream, "%s', '", data.error.context.before->string);
                 fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_start, data.error.notable.after->string);
@@ -433,7 +475,7 @@ extern "C" {
                 fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_stop, data.error.notable.after->string);
                 fprintf(data.error.to.stream, "%s' but instead has '", data.error.context.before->string);
                 fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, action->parameters.array[0].string, data.error.notable.after->string);
-                fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
               }
             }
 
@@ -460,10 +502,10 @@ extern "C" {
                 }
 
                 if (data.error.verbosity != f_console_verbosity_quiet) {
-                  fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                  fprintf(data.error.to.stream, "%s%sThe entry item action parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+                  fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                  fprintf(data.error.to.stream, "%s%sThe entry item action parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
                   fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, action->parameters.array[1].string, data.error.notable.after->string);
-                  fprintf(data.error.to.stream, "%s' is not a valid supported number.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                  fprintf(data.error.to.stream, "%s' is not a valid supported number.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
                 }
               }
             }
@@ -486,8 +528,8 @@ extern "C" {
   void controller_entry_error_print(const fll_error_print_t output, const controller_cache_t cache) {
 
     if (output.verbosity != f_console_verbosity_quiet) {
-      fprintf(output.to.stream, "%c", f_string_eol[0]);
-      fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : "");
+      fprintf(output.to.stream, "%c", f_string_eol_s[0]);
+      fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : f_string_empty_s);
 
       if (cache.name_action.used) {
         fprintf(output.to.stream, "action '");
@@ -508,7 +550,7 @@ extern "C" {
       if (cache.name_file.used) {
         fprintf(output.to.stream, "file '");
         fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, cache.name_file.string, output.notable.after->string);
-        fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol[0]);
+        fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
       }
     }
   }
@@ -585,8 +627,8 @@ extern "C" {
       }
       else {
         if (data.error.verbosity != f_console_verbosity_quiet) {
-          fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-          fprintf(data.error.to.stream, "%s%sThe entry file is empty.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.error.to.stream, "%s%sThe entry file is empty.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
         }
 
         status = F_status_set_error(F_data_not);
@@ -662,10 +704,10 @@ extern "C" {
 
             if (fl_string_dynamic_compare(entry->items.array[j].name, cache->name_item) == F_equal_to) {
               if (data.warning.verbosity == f_console_verbosity_debug) {
-                fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-                fprintf(data.warning.to.stream, "%s%sIgnoring duplicate entry item '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "");
+                fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.warning.to.stream, "%s%sIgnoring duplicate entry item '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
                 fprintf(data.warning.to.stream, "%s%s%s%s", data.warning.context.after->string, data.warning.notable.before->string, cache->name_file.string, data.warning.notable.after->string);
-                fprintf(data.warning.to.stream, "%s'.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol[0]);
+                fprintf(data.warning.to.stream, "%s'.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]);
 
                 controller_entry_error_print(data.warning, *cache);
               }
@@ -726,10 +768,10 @@ extern "C" {
 
           if (!(code & 0x1)) {
             if (data.error.verbosity != f_console_verbosity_quiet) {
-              fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-              fprintf(data.error.to.stream, "%s%sThe required entry item '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data.error.to.stream, "%s%sThe required entry item '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
               fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_main, data.error.notable.after->string);
-              fprintf(data.error.to.stream, "%s' was not found.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+              fprintf(data.error.to.stream, "%s' was not found.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
             }
 
             status = F_status_set_error(F_found_not);
@@ -780,10 +822,10 @@ extern "C" {
                     }
 
                     if (data.error.verbosity != f_console_verbosity_quiet) {
-                      fprintf(data.error.to.stream, "%c", f_string_eol[0]);
+                      fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
                       fprintf(data.error.to.stream, "The requested entry item '");
                       fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, action->parameters.array[0].string, data.error.notable.after->string);
-                      fprintf(data.error.to.stream, "%s' does not exist.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                      fprintf(data.error.to.stream, "%s' does not exist.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
                       controller_entry_error_print(data.error, *cache);
                     }
index 3857d20b2c06d9fe4bfc34b27076343c4175a38c..1db153f4f3c91bd87c2aa2e2b5d79c7c6846d81b 100644 (file)
@@ -13,6 +13,20 @@ extern "C" {
 #endif
 
 /**
+ * Get a string representing the entry action type.
+ *
+ * @param type
+ *   The entry action type code.
+ *
+ * @return
+ *   The string with used > 0 on success.
+ *   The string with used == 0 if no match was found.
+ */
+#ifndef _di_controller_entry_action_type_name_
+  extern f_string_static_t controller_entry_action_type_name(const uint8_t type) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_entry_action_type_name_
+
+/**
  * Increase the size of the entry item actions array by the specified amount, but only if necessary.
  *
  * This only increases size if the current used plus amount is greater than the currently allocated size.
index 41a94aebad68cb8f97b024c809af9a5bdb6666ae..bf0dd2fceff82f5f2915f32cc1dba8d5247c689b 100644 (file)
@@ -7,6 +7,29 @@
 extern "C" {
 #endif
 
+#ifndef _di_controller_rule_action_method_name_
+  f_string_static_t controller_rule_action_method_name(const uint8_t type) {
+
+    f_string_static_t buffer = f_string_static_t_initialize;
+
+    switch (type) {
+      case controller_rule_action_method_extended:
+        buffer.string = controller_rule_action_method_string_extended;
+        buffer.used = controller_rule_action_method_string_extended_length;
+        break;
+
+      case controller_rule_action_method_extended_list:
+        buffer.string = controller_rule_action_method_string_extended_list;
+        buffer.used = controller_rule_action_method_string_extended_list_length;
+        break;
+    }
+
+    buffer.size = buffer.used;
+
+    return buffer;
+  }
+#endif // _di_controller_rule_action_method_name_
+
 #ifndef _di_controller_rule_action_read_
   f_return_status controller_rule_action_read(const controller_data_t data, const f_string_static_t buffer, f_fss_object_t *object, f_fss_content_t *content, controller_rule_action_t *action) {
     f_status_t status = F_none;
@@ -53,6 +76,64 @@ extern "C" {
   }
 #endif // _di_controller_rule_action_read_
 
+#ifndef _di_controller_rule_action_type_name_
+  f_string_static_t controller_rule_action_type_name(const uint8_t type) {
+
+    f_string_static_t buffer = f_string_static_t_initialize;
+
+    switch (type) {
+      case controller_rule_action_type_create:
+        buffer.string = controller_string_create;
+        buffer.used = controller_string_create_length;
+        break;
+
+      case controller_rule_action_type_group:
+        buffer.string = controller_string_group;
+        buffer.used = controller_string_group_length;
+        break;
+
+      case controller_rule_action_type_kill:
+        buffer.string = controller_string_kill;
+        buffer.used = controller_string_kill_length;
+        break;
+
+      case controller_rule_action_type_restart:
+        buffer.string = controller_string_restart;
+        buffer.used = controller_string_restart_length;
+        break;
+
+      case controller_rule_action_type_reload:
+        buffer.string = controller_string_reload;
+        buffer.used = controller_string_reload_length;
+        break;
+
+      case controller_rule_action_type_start:
+        buffer.string = controller_string_start;
+        buffer.used = controller_string_start_length;
+        break;
+
+      case controller_rule_action_type_stop:
+        buffer.string = controller_string_stop;
+        buffer.used = controller_string_stop_length;
+        break;
+
+      case controller_rule_action_type_use:
+        buffer.string = controller_string_use;
+        buffer.used = controller_string_use_length;
+        break;
+
+      case controller_rule_action_type_user:
+        buffer.string = controller_string_user;
+        buffer.used = controller_string_user_length;
+        break;
+    }
+
+    buffer.size = buffer.used;
+
+    return buffer;
+  }
+#endif // _di_controller_rule_action_type_name_
+
 #ifndef _di_controller_rule_actions_increase_by_
   f_return_status controller_rule_actions_increase_by(const f_array_length_t amount, controller_rule_actions_t *actions) {
 
@@ -145,7 +226,7 @@ extern "C" {
                 break;
               }
 
-              actions->array[actions->used].line += item->line;
+              actions->array[actions->used].line += ++item->line;
               actions->array[actions->used].parameters.used = 0;
               actions->array[actions->used].status = F_known_not;
 
@@ -198,7 +279,7 @@ extern "C" {
               fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true);
             }
             else {
-              actions->array[0].line += item->line;
+              actions->array[0].line += ++item->line;
               actions->array[0].parameters.used = 0;
               actions->array[0].status = F_known_not;
 
@@ -225,8 +306,8 @@ extern "C" {
 
     if (F_status_is_error_not(status) && status == F_data_not) {
       if (data.warning.verbosity == f_console_verbosity_debug) {
-        fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-        fprintf(data.warning.to.stream, "%s%sAction is empty, nothing to do.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
+        fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+        fprintf(data.warning.to.stream, "%s%sAction is empty, nothing to do.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s, data.warning.context.after->string, f_string_eol_s[0]);
 
         controller_rule_error_print(data.warning, *cache, F_true);
       }
@@ -240,8 +321,8 @@ extern "C" {
   void controller_rule_error_print(const fll_error_print_t output, const controller_cache_t cache, const bool item) {
 
     if (output.verbosity != f_console_verbosity_quiet) {
-      fprintf(output.to.stream, "%c", f_string_eol[0]);
-      fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : "");
+      fprintf(output.to.stream, "%c", f_string_eol_s[0]);
+      fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : f_string_empty_s);
 
       if (cache.name_action.used) {
         fprintf(output.to.stream, "%s '", item ? "action" : "value");
@@ -262,12 +343,18 @@ extern "C" {
       if (cache.name_file.used) {
         fprintf(output.to.stream, "file '");
         fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, cache.name_file.string, output.notable.after->string);
-        fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol[0]);
+        fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
       }
     }
   }
 #endif // _di_controller_rule_error_print_
 
+#ifndef _di_controller_rule_execute_
+  f_return_status controller_rule_execute(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, controller_setting_t *setting) {
+    // @todo
+  }
+#endif // _di_controller_rule_execute_
+
 #ifndef _di_controller_rule_find_loaded_
   f_array_length_t controller_rule_find_loaded(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id) {
     f_array_length_t i = 0;
@@ -305,8 +392,8 @@ extern "C" {
       if (range.start >= range.stop || range.start >= cache->buffer_item.used) {
         if (status == FL_fss_found_object || status == FL_fss_found_object_content_not) {
           if (data.error.verbosity != f_console_verbosity_quiet) {
-            fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-            fprintf(data.error.to.stream, "%s%sUnterminated FSS Extended List at end of rule file.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+            fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data.error.to.stream, "%s%sUnterminated FSS Extended List at end of rule file.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
           }
 
           status = F_status_set_error(FL_fss_found_object_content_not);
@@ -351,7 +438,7 @@ extern "C" {
           break;
         }
 
-        cache->line_action += item->line;
+        cache->line_action += ++item->line;
         cache->name_action.used = 0;
 
         status = fl_string_dynamic_rip_nulless(cache->buffer_item, cache->range_action, &cache->name_action);
@@ -397,8 +484,8 @@ extern "C" {
         }
         else {
           if (data.warning.verbosity == f_console_verbosity_debug) {
-            fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-            fprintf(data.warning.to.stream, "%s%sUnknown rule item action type.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
+            fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data.warning.to.stream, "%s%sUnknown rule item action type.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s, data.warning.context.after->string, f_string_eol_s[0]);
 
             controller_rule_error_print(data.warning, *cache, F_true);
           }
@@ -409,8 +496,8 @@ extern "C" {
         if (multiple) {
           if (item->actions.type == controller_rule_action_type_create || item->actions.type == controller_rule_action_type_group || item->actions.type == controller_rule_action_type_use || item->actions.type == controller_rule_action_type_user) {
             if (data.error.verbosity != f_console_verbosity_quiet) {
-              fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-              fprintf(data.error.to.stream, "%s%sFSS Extended List is not allowed for this rule item action type.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data.error.to.stream, "%s%sFSS Extended List is not allowed for this rule item action type.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
             }
 
             status = F_status_set_error(F_supported_not);
@@ -432,6 +519,39 @@ extern "C" {
   }
 #endif // _di_controller_rule_item_read_
 
+#ifndef _di_controller_rule_item_type_name_
+  f_string_static_t controller_rule_item_type_name(const uint8_t type) {
+
+    f_string_static_t buffer = f_string_static_t_initialize;
+
+    switch (type) {
+      case controller_rule_item_type_command:
+        buffer.string = controller_string_command;
+        buffer.used = controller_string_command_length;
+        break;
+
+      case controller_rule_item_type_script:
+        buffer.string = controller_string_script;
+        buffer.used = controller_string_script_length;
+        break;
+
+      case controller_rule_item_type_service:
+        buffer.string = controller_string_service;
+        buffer.used = controller_string_service_length;
+        break;
+
+      case controller_rule_item_type_setting:
+        buffer.string = controller_string_setting;
+        buffer.used = controller_string_setting_length;
+        break;
+    }
+
+    buffer.size = buffer.used;
+
+    return buffer;
+  }
+#endif // _di_controller_rule_item_type_name_
+
 #ifndef _di_controller_rule_items_increase_by_
   f_return_status controller_rule_items_increase_by(const f_array_length_t amount, controller_rule_items_t *items) {
 
@@ -453,197 +573,6 @@ extern "C" {
   }
 #endif // _di_controller_rule_items_increase_by_
 
-#ifndef _di_controller_rule_read_
-  f_return_status controller_rule_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id, controller_cache_t *cache, controller_rule_t *rule) {
-    f_status_t status = F_none;
-
-    bool for_item = F_true;
-
-    rule->status = F_known_not;
-
-    f_macro_time_spec_t_clear(rule->timestamp);
-
-    rule->id.used = 0;
-    rule->name.used = 0;
-
-    rule->define.used = 0;
-    rule->parameter.used = 0;
-
-    rule->environment.used = 0;
-    rule->need.used = 0;
-    rule->want.used = 0;
-    rule->wish.used = 0;
-
-    rule->items.used = 0;
-
-    cache->line_item = 0;
-    cache->line_action = 0;
-
-    cache->range_action.start = 1;
-    cache->range_action.stop = 0;
-
-    cache->comments.used = 0;
-    cache->delimits.used = 0;
-
-    cache->buffer_file.used = 0;
-    cache->buffer_item.used = 0;
-    cache->buffer_path.used = 0;
-
-    cache->content_items.used = 0;
-
-    cache->object_items.used = 0;
-
-    cache->name_action.used = 0;
-    cache->name_file.used = 0;
-    cache->name_item.used = 0;
-
-    status = fl_string_dynamic_append_nulless(rule_id, &rule->id);
-
-    if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append_nulless", F_true);
-    }
-    else {
-      status = controller_file_load(data, setting, controller_string_rules, rule->id, controller_string_rule, controller_string_rules_length, controller_string_rule_length, cache);
-    }
-
-    if (F_status_is_error_not(status)) {
-      rule->timestamp = cache->timestamp;
-
-      if (cache->buffer_file.used) {
-        f_string_range_t range = f_macro_string_range_t_initialize(cache->buffer_file.used);
-
-        status = fll_fss_basic_list_read(cache->buffer_file, &range, &cache->object_items, &cache->content_items, &cache->delimits, 0, &cache->comments);
-
-        if (F_status_is_error(status)) {
-          fll_error_print(data.error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true);
-        }
-        else {
-          status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_file);
-
-          if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
-          }
-        }
-      }
-    }
-
-    if (F_status_is_error_not(status) && cache->object_items.used) {
-      status = controller_rule_items_increase_by(cache->object_items.used, &rule->items);
-
-      if (F_status_is_error(status)) {
-        fll_error_print(data.error, F_status_set_fine(status), "controller_rule_items_increase_by", F_true);
-      }
-      else {
-        for (f_array_length_t i = 0; i < cache->object_items.used; ++i) {
-
-          cache->line_item = 0;
-          cache->line_action = 0;
-
-          cache->range_action.start = 1;
-          cache->range_action.stop = 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_item.used = 0;
-          cache->buffer_path.used = 0;
-
-          cache->name_action.used = 0;
-          cache->name_item.used = 0;
-
-          for_item = F_true;
-
-          status = f_fss_count_lines(cache->buffer_file, cache->object_items.array[i].start, &cache->line_item);
-
-          if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true);
-            break;
-          }
-
-          rule->items.array[rule->items.used].line = cache->line_item;
-
-          status = fl_string_dynamic_rip_nulless(cache->buffer_file, cache->object_items.array[i], &cache->name_item);
-
-          if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_rip_nulless", F_true);
-            break;
-          }
-
-          status = fl_string_dynamic_terminate_after(&cache->name_item);
-
-          if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
-            break;
-          }
-
-          if (fl_string_dynamic_compare_string(controller_string_settings, cache->name_item, controller_string_settings_length) == F_equal_to) {
-            rule->items.array[rule->items.used].type = 0;
-          }
-          else if (fl_string_dynamic_compare_string(controller_string_command, cache->name_item, controller_string_command_length) == F_equal_to) {
-            rule->items.array[rule->items.used].type = controller_rule_item_type_command;
-          }
-          else if (fl_string_dynamic_compare_string(controller_string_script, cache->name_item, controller_string_script_length) == F_equal_to) {
-            rule->items.array[rule->items.used].type = controller_rule_item_type_script;
-          }
-          else if (fl_string_dynamic_compare_string(controller_string_service, cache->name_item, controller_string_service_length) == F_equal_to) {
-            rule->items.array[rule->items.used].type = controller_rule_item_type_service;
-          }
-          else {
-            if (data.warning.verbosity == f_console_verbosity_debug) {
-              fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-              fprintf(data.warning.to.stream, "%s%sUnknown rule item type.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
-
-              controller_rule_error_print(data.warning, *cache, F_true);
-            }
-
-            continue;
-          }
-
-          status = fl_string_dynamic_partial_append(cache->buffer_file, cache->content_items.array[i].array[0], &cache->buffer_item);
-
-          if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append", F_true);
-            break;
-          }
-
-          if (rule->items.array[rule->items.used].type) {
-            status = controller_rule_item_read(data, cache, &rule->items.array[rule->items.used]);
-            if (F_status_is_error(status)) break;
-
-            rule->items.used++;
-          }
-          else {
-            for_item = F_false;
-
-            status = controller_rule_setting_read(data, cache, rule);
-
-            if (F_status_is_error(status)) {
-              if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
-                break;
-              }
-            }
-          }
-        } // for
-      }
-    }
-
-    if (F_status_is_error(status)) {
-      controller_rule_error_print(data.error, *cache, for_item);
-
-      rule->status = controller_status_simplify(F_status_set_fine(status));
-      return F_false;
-    }
-
-    rule->status = F_none;
-    return F_true;
-  }
-#endif // _di_controller_rule_read_
-
 #ifndef _di_controller_rule_process_
   f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const bool simulate, controller_setting_t *setting, controller_cache_t *cache) {
 
@@ -669,10 +598,10 @@ extern "C" {
 
       if (cache->stack.array[i] == index) {
         if (data.error.verbosity != f_console_verbosity_quiet) {
-          fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-          fprintf(data.error.to.stream, "%s%sThe rule '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.error.to.stream, "%s%sThe rule '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
           fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting->rules.array[i].name.string, data.error.notable.after->string);
-          fprintf(data.error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+          fprintf(data.error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
           controller_rule_error_print(data.error, *cache, F_true);
         }
@@ -682,8 +611,6 @@ extern "C" {
       }
     }
 
-    cache->stack.array[cache->stack.used++] = index;
-
     cache->name_action.used = 0;
     cache->name_item.used = 0;
     cache->name_file.used = 0;
@@ -732,6 +659,8 @@ extern "C" {
       return status;
     }
 
+    cache->stack.array[cache->stack.used++] = index;
+
     controller_rule_t *rule = &setting->rules.array[index];
 
     {
@@ -739,7 +668,7 @@ extern "C" {
       f_array_length_t k = 0;
       f_array_length_t at = 0;
 
-      f_string_dynamics_t *dynamics[] = {
+      f_string_dynamics_t * const dynamics[] = {
         &rule->need,
         &rule->want,
         &rule->wish,
@@ -754,10 +683,10 @@ extern "C" {
             if (i == 0) {
 
               if (data.error.verbosity != f_console_verbosity_quiet) {
-                fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                fprintf(data.error.to.stream, "%s%sThe needed rule '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sThe needed rule '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
                 fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, dynamics[i]->array[j].string, data.error.notable.after->string);
-                fprintf(data.error.to.stream, "%s' was not found.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                fprintf(data.error.to.stream, "%s' was not found.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
                 controller_rule_error_print(data.error, *cache, F_true);
               }
@@ -768,10 +697,10 @@ extern "C" {
             }
             else {
               if (data.warning.verbosity == f_console_verbosity_debug) {
-                fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-                fprintf(data.warning.to.stream, "%s%sThe %s rule '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", i == 1 ? "wanted" : "wished for");
+                fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.warning.to.stream, "%s%sThe %s rule '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s, i == 1 ? "wanted" : "wished for");
                 fprintf(data.warning.to.stream, "%s%s%s%s", data.warning.context.after->string, data.error.notable.before->string, dynamics[i]->array[j].string, data.warning.notable.after->string);
-                fprintf(data.warning.to.stream, "%s' was not found.%s%c", data.warning.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                fprintf(data.warning.to.stream, "%s' was not found.%s%c", data.warning.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
                 controller_rule_error_print(data.warning, *cache, F_true);
               }
@@ -833,10 +762,10 @@ extern "C" {
                 if (i == 0 || i == 1 || F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
 
                   if (data.error.verbosity != f_console_verbosity_quiet) {
-                    fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                    fprintf(data.error.to.stream, "%s%sThe %s rule '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", i ? "wanted" : "needed");
+                    fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                    fprintf(data.error.to.stream, "%s%sThe %s rule '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, i ? "wanted" : "needed");
                     fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, dynamics[i]->array[j].string, data.error.notable.after->string);
-                    fprintf(data.error.to.stream, "%s' failed during execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                    fprintf(data.error.to.stream, "%s' failed during execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
                     controller_rule_error_print(data.error, *cache, F_true);
                   }
@@ -847,10 +776,10 @@ extern "C" {
                 }
                 else {
                   if (data.warning.verbosity == f_console_verbosity_debug) {
-                    fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-                    fprintf(data.warning.to.stream, "%s%sThe wished for rule '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "");
+                    fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+                    fprintf(data.warning.to.stream, "%s%sThe wished for rule '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
                     fprintf(data.warning.to.stream, "%s%s%s%s", data.warning.context.after->string, data.error.notable.before->string, dynamics[i]->array[j].string, data.warning.notable.after->string);
-                    fprintf(data.warning.to.stream, "%s' failed during execution.%s%c", data.warning.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                    fprintf(data.warning.to.stream, "%s' failed during execution.%s%c", data.warning.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
                     controller_rule_error_print(data.warning, *cache, F_true);
                   }
@@ -862,10 +791,10 @@ extern "C" {
               if (i == 0 || i == 1) {
 
                 if (data.error.verbosity != f_console_verbosity_quiet) {
-                  fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-                  fprintf(data.error.to.stream, "%s%sThe %s rule '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", i ? "wanted" : "needed");
+                  fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                  fprintf(data.error.to.stream, "%s%sThe %s rule '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, i ? "wanted" : "needed");
                   fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, dynamics[i]->array[j].string, data.error.notable.after->string);
-                  fprintf(data.error.to.stream, "%s' is in a failed state.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                  fprintf(data.error.to.stream, "%s' is in a failed state.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
                   controller_rule_error_print(data.error, *cache, F_true);
                 }
@@ -876,10 +805,10 @@ extern "C" {
               }
               else {
                 if (data.warning.verbosity == f_console_verbosity_debug) {
-                  fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-                  fprintf(data.warning.to.stream, "%s%sThe wished for rule '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "");
+                  fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+                  fprintf(data.warning.to.stream, "%s%sThe wished for rule '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
                   fprintf(data.warning.to.stream, "%s%s%s%s", data.warning.context.after->string, data.error.notable.before->string, dynamics[i]->array[j].string, data.warning.notable.after->string);
-                  fprintf(data.warning.to.stream, "%s' is in a failed state.%s%c", data.warning.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                  fprintf(data.warning.to.stream, "%s' is in a failed state.%s%c", data.warning.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
                   controller_rule_error_print(data.warning, *cache, F_true);
                 }
@@ -894,10 +823,17 @@ extern "C" {
 
     if (F_status_is_error_not(status)) {
       if (simulate) {
-        //status = controller_rule_simulate();
+        controller_rule_simulate(data, *cache, index, setting);
       }
       else {
-        //status = controller_rule_execute();
+        status = controller_rule_execute(data, *cache, index, setting);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(data.error, F_status_set_fine(status), "controller_rule_execute", F_true);
+          controller_rule_error_print(data.error, *cache, F_true);
+
+          return status;
+        }
       }
     }
 
@@ -912,6 +848,197 @@ extern "C" {
   }
 #endif // _di_controller_rule_process_
 
+#ifndef _di_controller_rule_read_
+  f_return_status controller_rule_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id, controller_cache_t *cache, controller_rule_t *rule) {
+    f_status_t status = F_none;
+
+    bool for_item = F_true;
+
+    rule->status = F_known_not;
+
+    f_macro_time_spec_t_clear(rule->timestamp);
+
+    rule->id.used = 0;
+    rule->name.used = 0;
+
+    rule->define.used = 0;
+    rule->parameter.used = 0;
+
+    rule->environment.used = 0;
+    rule->need.used = 0;
+    rule->want.used = 0;
+    rule->wish.used = 0;
+
+    rule->items.used = 0;
+
+    cache->line_item = 0;
+    cache->line_action = 0;
+
+    cache->range_action.start = 1;
+    cache->range_action.stop = 0;
+
+    cache->comments.used = 0;
+    cache->delimits.used = 0;
+
+    cache->buffer_file.used = 0;
+    cache->buffer_item.used = 0;
+    cache->buffer_path.used = 0;
+
+    cache->content_items.used = 0;
+
+    cache->object_items.used = 0;
+
+    cache->name_action.used = 0;
+    cache->name_file.used = 0;
+    cache->name_item.used = 0;
+
+    status = fl_string_dynamic_append_nulless(rule_id, &rule->id);
+
+    if (F_status_is_error(status)) {
+      fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append_nulless", F_true);
+    }
+    else {
+      status = controller_file_load(data, setting, controller_string_rules, rule->id, controller_string_rule, controller_string_rules_length, controller_string_rule_length, cache);
+    }
+
+    if (F_status_is_error_not(status)) {
+      rule->timestamp = cache->timestamp;
+
+      if (cache->buffer_file.used) {
+        f_string_range_t range = f_macro_string_range_t_initialize(cache->buffer_file.used);
+
+        status = fll_fss_basic_list_read(cache->buffer_file, &range, &cache->object_items, &cache->content_items, &cache->delimits, 0, &cache->comments);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(data.error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true);
+        }
+        else {
+          status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_file);
+
+          if (F_status_is_error(status)) {
+            fll_error_print(data.error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
+          }
+        }
+      }
+    }
+
+    if (F_status_is_error_not(status) && cache->object_items.used) {
+      status = controller_rule_items_increase_by(cache->object_items.used, &rule->items);
+
+      if (F_status_is_error(status)) {
+        fll_error_print(data.error, F_status_set_fine(status), "controller_rule_items_increase_by", F_true);
+      }
+      else {
+        for (f_array_length_t i = 0; i < cache->object_items.used; ++i) {
+
+          cache->line_item = 0;
+          cache->line_action = 0;
+
+          cache->range_action.start = 1;
+          cache->range_action.stop = 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_item.used = 0;
+          cache->buffer_path.used = 0;
+
+          cache->name_action.used = 0;
+          cache->name_item.used = 0;
+
+          for_item = F_true;
+
+          status = f_fss_count_lines(cache->buffer_file, cache->object_items.array[i].start, &cache->line_item);
+
+          if (F_status_is_error(status)) {
+            fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true);
+            break;
+          }
+
+          rule->items.array[rule->items.used].line = ++cache->line_item;
+
+          status = fl_string_dynamic_rip_nulless(cache->buffer_file, cache->object_items.array[i], &cache->name_item);
+
+          if (F_status_is_error(status)) {
+            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_rip_nulless", F_true);
+            break;
+          }
+
+          status = fl_string_dynamic_terminate_after(&cache->name_item);
+
+          if (F_status_is_error(status)) {
+            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+            break;
+          }
+
+          if (fl_string_dynamic_compare_string(controller_string_setting, cache->name_item, controller_string_setting_length) == F_equal_to) {
+            rule->items.array[rule->items.used].type = 0;
+          }
+          else if (fl_string_dynamic_compare_string(controller_string_command, cache->name_item, controller_string_command_length) == F_equal_to) {
+            rule->items.array[rule->items.used].type = controller_rule_item_type_command;
+          }
+          else if (fl_string_dynamic_compare_string(controller_string_script, cache->name_item, controller_string_script_length) == F_equal_to) {
+            rule->items.array[rule->items.used].type = controller_rule_item_type_script;
+          }
+          else if (fl_string_dynamic_compare_string(controller_string_service, cache->name_item, controller_string_service_length) == F_equal_to) {
+            rule->items.array[rule->items.used].type = controller_rule_item_type_service;
+          }
+          else {
+            if (data.warning.verbosity == f_console_verbosity_debug) {
+              fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data.warning.to.stream, "%s%sUnknown rule item type.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s, data.warning.context.after->string, f_string_eol_s[0]);
+
+              controller_rule_error_print(data.warning, *cache, F_true);
+            }
+
+            continue;
+          }
+
+          status = fl_string_dynamic_partial_append(cache->buffer_file, cache->content_items.array[i].array[0], &cache->buffer_item);
+
+          if (F_status_is_error(status)) {
+            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append", F_true);
+            break;
+          }
+
+          if (rule->items.array[rule->items.used].type) {
+            status = controller_rule_item_read(data, cache, &rule->items.array[rule->items.used]);
+            if (F_status_is_error(status)) break;
+
+            rule->items.used++;
+          }
+          else {
+            for_item = F_false;
+
+            status = controller_rule_setting_read(data, cache, rule);
+
+            if (F_status_is_error(status)) {
+              if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+                break;
+              }
+            }
+          }
+        } // for
+      }
+    }
+
+    if (F_status_is_error(status)) {
+      controller_rule_error_print(data.error, *cache, for_item);
+
+      rule->status = controller_status_simplify(F_status_set_fine(status));
+      return F_false;
+    }
+
+    rule->status = F_none;
+    return F_true;
+  }
+#endif // _di_controller_rule_read_
+
 #ifndef _di_controller_rule_setting_read_
   f_return_status controller_rule_setting_read(const controller_data_t data, controller_cache_t *cache, controller_rule_t *rule) {
     f_status_t status = F_none;
@@ -988,8 +1115,12 @@ extern "C" {
       }
       else {
         if (data.warning.verbosity == f_console_verbosity_debug) {
-          fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-          fprintf(data.warning.to.stream, "%s%sUnknown rule setting.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
+          fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.warning.to.stream, "%s%sUnknown rule setting.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s, data.warning.context.after->string, f_string_eol_s[0]);
+
+          fprintf(data.warning.to.stream, "%s%sUnknown rule setting '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s);
+          fprintf(data.warning.to.stream, "%s%s%s%s", data.warning.context.after->string, data.warning.notable.before->string, cache->name_item.string, data.warning.notable.after->string);
+          fprintf(data.warning.to.stream, "%s'.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]);
 
           controller_rule_error_print(data.warning, *cache, F_false);
         }
@@ -999,8 +1130,8 @@ extern "C" {
 
       if (!cache->content_actions.array[i].used) {
         if (data.warning.verbosity == f_console_verbosity_debug) {
-          fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
-          fprintf(data.warning.to.stream, "%s%sEmpty rule setting.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
+          fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.warning.to.stream, "%s%sEmpty rule setting.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s, data.warning.context.after->string, f_string_eol_s[0]);
 
           controller_rule_error_print(data.warning, *cache, F_false);
         }
@@ -1035,8 +1166,8 @@ extern "C" {
       if (type == controller_rule_setting_type_define || type == controller_rule_setting_type_parameter) {
 
         if (cache->content_actions.array[i].used != 2) {
-          fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-          fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
 
           controller_rule_error_print(data.error, *cache, F_false);
 
@@ -1124,8 +1255,8 @@ extern "C" {
         }
 
         if (setting_value->used || cache->content_actions.array[i].used != 1) {
-          fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-          fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
 
           controller_rule_error_print(data.error, *cache, F_false);
 
@@ -1162,10 +1293,10 @@ extern "C" {
 
           if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) {
             if (status == F_false) {
-              fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-              fprintf(data.error.to.stream, "%s%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data.error.to.stream, "%s%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
               fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_value->string, data.error.notable.after->string);
-              fprintf(data.error.to.stream, "%s', there must be at least 1 graph character.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+              fprintf(data.error.to.stream, "%s', there must be at least 1 graph character.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
               controller_rule_error_print(data.error, *cache, F_false);
 
@@ -1260,10 +1391,10 @@ extern "C" {
 
           if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) {
             if (status == F_false) {
-              fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-              fprintf(data.error.to.stream, "%s%sRule setting has an invalid environment variable name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data.error.to.stream, "%s%sRule setting has an invalid environment variable name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
               fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used].string, data.error.notable.after->string);
-              fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+              fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
               controller_rule_error_print(data.error, *cache, F_false);
 
@@ -1294,8 +1425,8 @@ extern "C" {
       }
 
       if (cache->content_actions.array[i].used != 2) {
-        fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-        fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+        fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+        fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
 
         controller_rule_error_print(data.error, *cache, F_false);
 
@@ -1441,12 +1572,12 @@ extern "C" {
               continue;
             }
 
-            fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-            fprintf(data.error.to.stream, "%s%sThe rule item action second parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+            fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data.error.to.stream, "%s%sThe rule item action second parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
             fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used + 1].string, data.error.notable.after->string);
             fprintf(data.error.to.stream, "%s' must be a base path name, such as '", data.error.context.before->string);
             fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->buffer_path.string, data.error.notable.after->string);
-            fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+            fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
           }
 
           setting_values->array[setting_values->used].used = 0;
@@ -1463,6 +1594,133 @@ extern "C" {
   }
 #endif // _di_controller_rule_setting_read_
 
+#ifndef _di_controller_rule_simulate_
+  void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, controller_setting_t *setting) {
+
+    controller_rule_t * const rule = &setting->rules.array[index];
+
+    fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+    fprintf(data.output.stream, "Rule %s%s%s {%c", data.context.set.title.before->string, rule->id.used ? rule->id.string : f_string_empty_s, data.context.set.title.after->string, f_string_eol_s[0]);
+    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_name, data.context.set.important.after->string, rule->name.used ? rule->name.string : f_string_empty_s, f_string_eol_s[0]);
+    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_control_group, data.context.set.important.after->string, rule->control_group.used ? rule->control_group.string : f_string_empty_s, f_string_eol_s[0]);
+
+    f_array_length_t i = 0;
+
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_define, data.context.set.important.after->string, f_string_eol_s[0]);
+
+    if (rule->define.used) {
+      for (; i < rule->define.used; ++i) {
+
+        if (rule->define.array[i].name.used && rule->define.array[i].value.used) {
+          fprintf(data.output.stream, "    %s %s=%s %s%c", rule->define.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->define.array[i].value.string, f_string_eol_s[0]);
+        }
+      } // for
+    }
+
+    fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
+
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_parameter, data.context.set.important.after->string, f_string_eol_s[0]);
+
+    if (rule->parameter.used) {
+      for (i = 0; i < rule->parameter.used; ++i) {
+
+        if (rule->parameter.array[i].name.used && rule->parameter.array[i].value.used) {
+          fprintf(data.output.stream, "    %s %s=%s %s%c", rule->parameter.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->parameter.array[i].value.string, f_string_eol_s[0]);
+        }
+      } // for
+    }
+
+    fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
+
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_environment, data.context.set.important.after->string, f_string_eol_s[0]);
+
+    if (rule->environment.used) {
+      for (i = 0; i < rule->environment.used; ++i) {
+
+        if (rule->environment.array[i].used) {
+          fprintf(data.output.stream, "    %s%c", rule->environment.array[i].string, f_string_eol_s[0]);
+        }
+      } // for
+    }
+
+    fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
+
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_need, data.context.set.important.after->string, f_string_eol_s[0]);
+
+    if (rule->need.used) {
+      for (i = 0; i < rule->need.used; ++i) {
+
+        if (rule->need.array[i].used) {
+          fprintf(data.output.stream, "    %s%c", rule->need.array[i].string, f_string_eol_s[0]);
+        }
+      } // for
+    }
+
+    fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
+
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_want, data.context.set.important.after->string, f_string_eol_s[0]);
+
+    if (rule->want.used) {
+      for (i = 0; i < rule->want.used; ++i) {
+
+        if (rule->want.array[i].used) {
+          fprintf(data.output.stream, "    %s%c", rule->want.array[i].string, f_string_eol_s[0]);
+        }
+      } // for
+    }
+
+    fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
+
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_wish, data.context.set.important.after->string, f_string_eol_s[0]);
+
+    if (rule->wish.used) {
+      for (i = 0; i < rule->wish.used; ++i) {
+
+        if (rule->wish.array[i].used) {
+          fprintf(data.output.stream, "    %s%c", rule->wish.array[i].string, f_string_eol_s[0]);
+        }
+      } // for
+    }
+
+    fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
+
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_item, data.context.set.important.after->string, f_string_eol_s[0]);
+
+    if (rule->items.used) {
+      controller_rule_action_t *action = 0;
+      controller_rule_item_t *item = 0;
+
+      f_array_length_t j = 0;
+
+      for (i = 0; i < rule->items.used; ++i) {
+
+        item = &rule->items.array[i];
+
+        fprintf(data.output.stream, "    %s%s%s %s%c", data.context.set.important.before->string, controller_string_type, data.context.set.important.after->string, controller_rule_item_type_name(item->type).string, f_string_eol_s[0]);
+
+        fprintf(data.output.stream, "    %s%s%s {%c", data.context.set.important.before->string, controller_string_action, data.context.set.important.after->string, f_string_eol_s[0]);
+
+        for (j = 0; j < item->actions.used; ++j) {
+
+          action = &item->actions.array[j];
+
+          // action method
+          // action type
+          // action parameters
+        }
+
+        fprintf(data.output.stream, "    }%c", f_string_eol_s[0]);
+      } // for
+
+      fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
+    }
+
+    fprintf(data.output.stream, "}%c%c", f_string_eol_s[0], f_string_eol_s[0]);
+
+    setting->rules.array[index].status = F_complete;
+  }
+#endif // _di_controller_rule_simulate_
+
 #ifndef _di_controller_rules_increase_by_
   f_return_status controller_rules_increase_by(const f_array_length_t amount, controller_rules_t *rules) {
 
index ef1abc6f78351445e459398a9adbcd133a1682b0..86bf3c693567d0b96c9e8382114cacd86a2ee5a2 100644 (file)
@@ -13,6 +13,20 @@ extern "C" {
 #endif
 
 /**
+ * Get a string representing the rule action method.
+ *
+ * @param type
+ *   The rule action type code.
+ *
+ * @return
+ *   The string with used > 0 on success.
+ *   The string with used == 0 if no match was found.
+ */
+#ifndef _di_controller_rule_action_method_name_
+  extern f_string_static_t controller_rule_action_method_name(const uint8_t type) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_action_method_name_
+
+/**
  * Read the rule action.
  *
  * The object and content ranges are merged together (in that order) as the action parameters.
@@ -46,6 +60,20 @@ extern "C" {
 #endif // _di_controller_rule_action_read_
 
 /**
+ * Get a string representing the rule action type.
+ *
+ * @param type
+ *   The rule action type code.
+ *
+ * @return
+ *   The string with used > 0 on success.
+ *   The string with used == 0 if no match was found.
+ */
+#ifndef _di_controller_rule_action_type_name_
+  extern f_string_static_t controller_rule_action_type_name(const uint8_t type) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_action_type_name_
+
+/**
  * Increase the size of the rule actions array by the specified amount, but only if necessary.
  *
  * This only increases size if the current used plus amount is greater than the currently allocated size.
@@ -115,10 +143,33 @@ extern "C" {
  * @see controller_rule_setting_read()
  */
 #ifndef _di_controller_rule_error_print_
-  void controller_rule_error_print(const fll_error_print_t output, const controller_cache_t cache, const bool item) f_gcc_attribute_visibility_internal;
+  extern void controller_rule_error_print(const fll_error_print_t output, const controller_cache_t cache, const bool item) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_error_print_
 
 /**
+ * Perform an execution of the given rule.
+ *
+ * @param data
+ *   The program data.
+ * @param cache
+ *   A structure for containing and caching relevant data.
+ * @param index
+ *   The position in the setting.rules array representing the rule to simulate.
+ * @param setting
+ *   The controller settings data.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   On success and the rule is run synchronously, then the individual status for the rule is set to F_complete.
+ *   On success and the rule is run asynchronously, then the individual status for the rule is set to F_busy.
+ *   On failure, the individual status for the rule is set to an appropriate error status.
+ */
+#ifndef _di_controller_rule_execute_
+  extern f_return_status controller_rule_execute(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_execute_
+
+/**
  * Search the already loaded rules to see if one is found.
  *
  * @param data
@@ -167,6 +218,20 @@ extern "C" {
 #endif // _di_controller_rule_item_read_
 
 /**
+ * Get a string representing the rule item type.
+ *
+ * @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_rule_item_type_name_
+  extern f_string_static_t controller_rule_item_type_name(const uint8_t type) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_item_type_name_
+
+/**
  * Increase the size of the rule items array by the specified amount, but only if necessary.
  *
  * This only increases size if the current used plus amount is greater than the currently allocated size.
@@ -189,6 +254,37 @@ extern "C" {
 #endif // _di_controller_rule_items_increase_by_
 
 /**
+ * Process and execute the given rule by the rule id.
+ *
+ * Any dependent rules are loaded and executed as per "need", "want", and "wish" rule settings.
+ * All dependent rules must be already loaded, this function will not load any rules.
+ *
+ * This function is recursively called for each "need", "want", and "wish", and has a max recursion length of the max size of the f_array_lengths_t array.
+ *
+ * @todo add asynchronous boolean? (will also need a wait boolean, so this should probably be a uint8_t with using bitwise states).
+ *
+ * @param data
+ *   The program data.
+ * @param index
+ *   Position in the rules array representing the rule to execute
+ * @param simulate
+ *   If TRUE, then the rule execution is simulated (printing a message that the rule would be executed but does not execut the rule).
+ *   If FALSE, the rule is not simulated and is executed as normal.
+ * @param setting
+ *   The controller settings data.
+ * @param cache
+ *   A structure for containing and caching relevant data.
+ *   This utilizes cache.stack for recursive executions, no function called by this may therefore safely use cache.stack for any other purpose.
+ *   This utilizes line_action, line_item, name_action, and name_item from cache, but they are backed up before starting and then restored after finishing.
+ *
+ * @return
+ *    F_none on success.
+ */
+#ifndef _di_controller_rule_process_
+  extern f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const bool simulate, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_process_
+
+/**
  * Read the rule file, extracting all valid items.
  *
  * @param data
@@ -225,37 +321,6 @@ extern "C" {
 #endif // _di_controller_rule_read_
 
 /**
- * Process and execute the given rule by the rule id.
- *
- * Any dependent rules are loaded and executed as per "need", "want", and "wish" rule settings.
- * All dependent rules must be already loaded, this function will not load any rules.
- *
- * This function is recursively called for each "need", "want", and "wish", and has a max recursion length of the max size of the f_array_lengths_t array.
- *
- * @todo add asynchronous boolean? (will also need a wait boolean, so this should probably be a uint8_t with using bitwise states).
- *
- * @param data
- *   The program data.
- * @param index
- *   Position in the rules array representing the rule to execute
- * @param simulate
- *   If TRUE, then the rule execution is simulated (printing a message that the rule would be executed but does not execut the rule).
- *   If FALSE, the rule is not simulated and is executed as normal.
- * @param setting
- *   The controller settings data.
- * @param cache
- *   A structure for containing and caching relevant data.
- *   This utilizes cache.stack for recursive executions, no function called by this may therefore safely use cache.stack for any other purpose.
- *   This utilizes line_action, line_item, name_action, and name_item from cache, but they are backed up before starting and then restored after finishing.
- *
- * @return
- *    F_none on success.
- */
-#ifndef _di_controller_rule_process_
-  extern f_return_status controller_rule_process(const controller_data_t data, const f_array_length_t index, const bool simulate, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_rule_process_
-
-/**
  * Read the content within the buffer, extracting all valid settings.
  *
  * This will perform additional FSS read functions as appropriate.
@@ -293,6 +358,26 @@ extern "C" {
 #endif // _di_controller_rule_setting_read_
 
 /**
+ * Perform a simulated execution of the given rule.
+ *
+ * This simply prints information about the rule.
+ *
+ * This automatically sets the rule's status to F_complete.
+ *
+ * @param data
+ *   The program data.
+ * @param cache
+ *   A structure for containing and caching relevant data.
+ * @param index
+ *   The position in the setting.rules array representing the rule to simulate.
+ * @param setting
+ *   The controller settings data.
+ */
+#ifndef _di_controller_rule_simulate_
+  extern void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_simulate_
+
+/**
  * Increase the size of the rules array by the specified amount, but only if necessary.
  *
  * This only increases size if the current used plus amount is greater than the currently allocated size.