]> Kevux Git Server - fll/commitdiff
Update: Implement timeout setting support, fix number handling, improve printing.
authorKevin Day <thekevinday@gmail.com>
Fri, 8 Oct 2021 02:36:09 +0000 (21:36 -0500)
committerKevin Day <thekevinday@gmail.com>
Fri, 8 Oct 2021 02:36:09 +0000 (21:36 -0500)
The timeout settings were never fully completed.
This implements the loading of the timeout settings but does not provide an usage of these settings.

Do some restructuring related to the timeout settings.

Fix detecting and processing of +/- as well as decimals.

Handle more errors returned by the number convert functions.

Cleanup the printing code.
Centralize some of the printing to functions, ideally reducing code size.
Add printing where it is not being done.
Fix debug vs verbose printing where debug isn't always including verbose printing messages.

Update the documentation.

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-rule.c
level_3/controller/c/private-rule.h
level_3/controller/documents/entry.txt
level_3/controller/documents/rule.txt

index f77c28ab13f5900245d7b6e82ab7fae2617abaa3..b018c04fe09112bd0afa356fc5db49e05be4f491 100644 (file)
@@ -796,6 +796,7 @@ extern "C" {
     controller_rule_setting_type_path,
     controller_rule_setting_type_scheduler,
     controller_rule_setting_type_script,
+    controller_rule_setting_type_timeout,
     controller_rule_setting_type_user,
   };
 
@@ -807,6 +808,11 @@ extern "C" {
   #define controller_rule_has_scheduler     0x10
   #define controller_rule_has_user          0x20
 
+  // Designate codes for timeout settings to be used during the loading of the rule timeout settings.
+  #define controller_rule_timeout_code_kill  1
+  #define controller_rule_timeout_code_start 2
+  #define controller_rule_timeout_code_stop  3
+
   typedef struct {
     f_status_t status[controller_rule_action_type__enum_size];
 
@@ -1090,11 +1096,6 @@ extern "C" {
  *   - require:      Require Rule operations to succeed or the Entry/Exit will fail.
  *   - wait:         Wait for all existing asynchronous processes to finish before operating Rule.
  *
- * controller_entry_timeout_code_*:
- *   - kill:  Designate time to wait before killing.
- *   - start: Designate time to wait before starting.
- *   - stop:  Designate time to wait before stopping.
- *
  * type:       The type of Action.
  * code:       A single code or sub-type associated with the Action.
  * line:       The line number where the Entry Item begins.
@@ -1238,10 +1239,13 @@ extern "C" {
  *   - normal: Do not print anything other than warnings and errors, but allow executed programs and scripts to output however they like.
  *   - init:   Print like an init program, printing status of entry and rules as they are being started, stopped, etc...
  *
- * status: The overall status.
- * pid:    The PID file generation setting.
- * show:   The show setting for controlling what to show when executing entry items and rules.
- * items:  The array of entry items.
+ * status:        The overall status.
+ * pid:           The PID file generation setting.
+ * show:          The show setting for controlling what to show when executing entry items and rules.
+ * timeout_kill:  The timeout to wait relating to using a kill signal.
+ * timeout_start: The timeout to wait relating to starting a process.
+ * timeout_stop:  The timeout to wait relating to stopping a process.
+ * items:         The array of entry items.
  */
 #ifndef _di_controller_entry_t_
   enum {
@@ -1261,6 +1265,10 @@ extern "C" {
     uint8_t pid;
     uint8_t show;
 
+    f_number_unsigned_t timeout_kill;
+    f_number_unsigned_t timeout_start;
+    f_number_unsigned_t timeout_stop;
+
     controller_entry_items_t items;
   } controller_entry_t;
 
@@ -1268,6 +1276,9 @@ extern "C" {
     F_known_not, \
     controller_entry_pid_require, \
     controller_entry_show_normal, \
+    0, \
+    0, \
+    0, \
     controller_entry_items_t_initialize, \
   }
 #endif // _di_controller_entry_t_
@@ -1289,9 +1300,6 @@ extern "C" {
  *
  * interruptable:    TRUE if the program responds to interrupt signals, FALSE to block/ignore interrupt signals.
  * ready:            State representing if the settings are all loaded and is ready to run program operations.
- * timeout_kill:     The timeout to wait relating to using a kill signal.
- * timeout_start:    The timeout to wait relating to starting a process.
- * timeout_stop:     The timeout to wait relating to stopping a process.
  * failsafe_enabled: TRUE if failsafe execution is enabled, FALSE otherwise.
  * failsafe_item_id: The Entry Item ID to execute when failsafe execution is enabled.
  * path_control:     File path to the control socket.
@@ -1321,10 +1329,6 @@ extern "C" {
     uint8_t ready;
     uint8_t mode;
 
-    f_number_unsigned_t timeout_kill;
-    f_number_unsigned_t timeout_start;
-    f_number_unsigned_t timeout_stop;
-
     bool failsafe_enabled;
     f_array_length_t failsafe_item_id;
 
@@ -1344,9 +1348,6 @@ extern "C" {
     F_false, \
     0, \
     0, \
-    3, \
-    3, \
-    3, \
     F_false, \
     0, \
     f_string_dynamic_t_initialize, \
index 3fe6bff0817930c13eb09cd157f2f0e05f2830c9..24a8ab64fbee9bfb05a5303cf5ff5aeee1e1212a 100644 (file)
 extern "C" {
 #endif
 
+#ifndef _di_controller_range_after_number_sign_
+  f_string_range_t controller_range_after_number_sign(const f_string_static_t buffer, const f_string_range_t range) {
+
+    f_string_range_t result = range;
+
+    for (; result.start <= result.stop; ++result.start) {
+
+      if (!buffer.string[result.start]) continue;
+
+      if (buffer.string[result.start] == '-' || buffer.string[result.start] == '+') {
+        ++result.start;
+      }
+
+      break;
+    } // while
+
+    return result;
+  }
+#endif // _di_controller_range_after_number_sign_
+
 #ifndef _di_controller_string_dynamic_rip_nulless_terminated_
   f_status_t controller_string_dynamic_rip_nulless_terminated(const f_string_static_t source, const f_string_range_t range, f_string_dynamic_t *destination) {
 
@@ -741,7 +761,7 @@ extern "C" {
       return status;
     }
 
-    if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
+    if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || global->main->error.verbosity == f_console_verbosity_debug) {
       if (global->main->error.verbosity != f_console_verbosity_quiet) {
         controller_print_lock(global->main->output, global->thread);
 
@@ -850,7 +870,7 @@ extern "C" {
 
         if (entry_action->type == controller_entry_action_type_ready) {
           if ((entry_action->code & controller_entry_rule_code_wait) || global->setting->ready == controller_setting_ready_wait) {
-            if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || entry->show == controller_entry_show_init) {
+            if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || global->main->error.verbosity == f_console_verbosity_debug || entry->show == controller_entry_show_init) {
               if (global->main->error.verbosity != f_console_verbosity_quiet) {
                 controller_print_lock(global->main->output, global->thread);
 
@@ -868,7 +888,7 @@ extern "C" {
           }
 
           if (global->setting->ready == controller_setting_ready_yes) {
-            if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
+            if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || global->main->error.verbosity == f_console_verbosity_debug) {
               if (global->main->error.verbosity != f_console_verbosity_quiet) {
                 controller_print_lock(global->main->output, global->thread);
 
@@ -939,7 +959,7 @@ extern "C" {
             return status;
           }
 
-          if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
+          if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || global->main->error.verbosity == f_console_verbosity_debug) {
             if (global->main->error.verbosity != f_console_verbosity_quiet) {
               controller_print_lock(global->main->output, global->thread);
 
@@ -994,7 +1014,7 @@ extern "C" {
 
           f_thread_unlock(&global->thread->lock.rule);
 
-          if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || (entry->show == controller_entry_show_init && entry_action->type != controller_entry_action_type_consider)) {
+          if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || global->main->error.verbosity == f_console_verbosity_debug || (entry->show == controller_entry_show_init && entry_action->type != controller_entry_action_type_consider)) {
             if (global->main->error.verbosity != f_console_verbosity_quiet) {
               controller_print_lock(global->main->output, global->thread);
 
@@ -1043,7 +1063,7 @@ extern "C" {
             status_lock = controller_lock_write(is_entry, global->thread, &global->thread->lock.rule);
 
             if (!(status_lock == F_signal || F_status_is_error(status_lock))) {
-              status = controller_rule_read(is_entry, alias_rule, *global, cache, &global->setting->rules.array[global->setting->rules.used]);
+              status = controller_rule_read(is_entry, alias_rule, *global, cache, entry, &global->setting->rules.array[global->setting->rules.used]);
             }
 
             // restore cache.
@@ -1146,7 +1166,7 @@ extern "C" {
           }
         }
         else if (entry_action->type == controller_entry_action_type_execute) {
-          if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || entry->show == controller_entry_show_init) {
+          if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || global->main->error.verbosity == f_console_verbosity_debug || entry->show == controller_entry_show_init) {
             if (global->main->error.verbosity != f_console_verbosity_quiet) {
               controller_print_lock(global->main->output, global->thread);
 
@@ -1216,40 +1236,22 @@ extern "C" {
           return F_execute;
         }
         else if (entry_action->type == controller_entry_action_type_timeout) {
-
-          if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
-            f_string_t code = "";
-
-            if (entry_action->code == controller_entry_timeout_code_kill) {
-              code = controller_string_kill_s;
-            }
-            else if (entry_action->code == controller_entry_timeout_code_start) {
-              code = controller_string_start_s;
-            }
-            else if (entry_action->code == controller_entry_timeout_code_stop) {
-              code = controller_string_stop_s;
-            }
-
-            if (global->main->error.verbosity != f_console_verbosity_quiet) {
-              controller_print_lock(global->main->output, global->thread);
-
-              fl_print_format("%cProcessing %s item action '", global->main->output.stream, f_string_eol_s[0], is_entry ? controller_string_entry_s : controller_string_exit_s);
-              fl_print_format("%[%s%]' setting '", global->main->output.stream, global->main->context.set.title, controller_string_timeout_s, global->main->context.set.title);
-              fl_print_format("%[%S%]' to '", global->main->output.stream, global->main->context.set.important, code, global->main->context.set.important);
-              fl_print_format("%[%un%]' MegaTime (milliseconds).%c", global->main->output.stream, global->main->context.set.important, entry_action->number, global->main->context.set.important, f_string_eol_s[0]);
-
-              controller_print_unlock_flush(global->main->output, global->thread);
-            }
-          }
+          const f_string_t suffix = " MegaTime (milliseconds)";
 
           if (entry_action->code == controller_entry_timeout_code_kill) {
-            global->setting->timeout_kill = entry_action->number;
+            entry->timeout_kill = entry_action->number;
+
+            controller_process_entry_print_simulate_setting_value(is_entry, *global, controller_string_timeout_s, controller_string_kill_s, entry->items.array[global->setting->failsafe_item_id].name, suffix);
           }
           else if (entry_action->code == controller_entry_timeout_code_start) {
-            global->setting->timeout_start = entry_action->number;
+            entry->timeout_start = entry_action->number;
+
+            controller_process_entry_print_simulate_setting_value(is_entry, *global, controller_string_timeout_s, controller_string_start_s, entry->items.array[global->setting->failsafe_item_id].name, suffix);
           }
           else if (entry_action->code == controller_entry_timeout_code_stop) {
-            global->setting->timeout_stop = entry_action->number;
+            entry->timeout_stop = entry_action->number;
+
+            controller_process_entry_print_simulate_setting_value(is_entry, *global, controller_string_timeout_s, controller_string_stop_s, entry->items.array[global->setting->failsafe_item_id].name, suffix);
           }
         }
         else if (entry_action->type == controller_entry_action_type_failsafe) {
@@ -1287,18 +1289,7 @@ extern "C" {
               global->setting->failsafe_enabled = F_true;
               global->setting->failsafe_item_id = entry_action->number;
 
-              if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
-                if (global->main->error.verbosity != f_console_verbosity_quiet) {
-                  controller_print_lock(global->main->output, global->thread);
-
-                  fl_print_format("%cProcessing %s item action '", global->main->output.stream, f_string_eol_s[0], is_entry ? controller_string_entry_s : controller_string_exit_s);
-                  fl_print_format("%[%s%]' setting value to '", global->main->output.stream, global->main->context.set.title, controller_string_failsafe_s, global->main->context.set.title);
-                  fl_print_format("%[%Q%]", global->main->output.stream, global->main->context.set.important, entry->items.array[global->setting->failsafe_item_id].name, global->main->context.set.important);
-                  fl_print_format("'.%c", global->main->output.stream, f_string_eol_s[0]);
-
-                  controller_print_unlock_flush(global->main->output, global->thread);
-                }
-              }
+              controller_process_entry_print_simulate_setting_value(is_entry, *global, controller_string_failsafe_s, 0, entry->items.array[global->setting->failsafe_item_id].name, 0);
             }
           }
         }
@@ -1384,6 +1375,34 @@ extern "C" {
   }
 #endif // _di_controller_process_entry_
 
+#ifndef _di_controller_process_entry_print_simulate_setting_value_
+  void controller_process_entry_print_simulate_setting_value(const bool is_entry, const controller_global_t global, const f_string_t name, const f_string_t name_sub, const f_string_static_t value, const f_string_t suffix) {
+
+    if (global.main->error.verbosity != f_console_verbosity_debug && !(global.main->error.verbosity == f_console_verbosity_verbose && global.main->parameters[controller_parameter_simulate].result == f_console_result_found)) {
+      return;
+    }
+
+    controller_print_lock(global.main->output, global.thread);
+
+    fl_print_format("%cProcessing %s item action '", global.main->output.stream, f_string_eol_s[0], is_entry ? controller_string_entry_s : controller_string_exit_s);
+
+    fl_print_format("%[%S%]' setting ", global.main->output.stream, global.main->context.set.title, name, global.main->context.set.title);
+
+    if (name_sub) {
+      fl_print_format("'%[%S%]'", global.main->output.stream, global.main->context.set.notable, name_sub, global.main->context.set.notable);
+    }
+    else {
+      fl_print_format("value", global.main->output.stream);
+    }
+
+    fl_print_format(" to '%[%Q%]", global.main->output.stream, global.main->context.set.important, value, global.main->context.set.important);
+
+    fl_print_format("'%S.%c", global.main->output.stream, suffix, f_string_eol_s[0]);
+
+    controller_print_unlock_flush(global.main->output, global.thread);
+  }
+#endif // _di_controller_process_entry_print_simulate_setting_value_
+
 #ifndef _di_controller_process_prepare_
   f_status_t controller_process_prepare(const bool is_normal, const uint8_t action, const f_string_static_t alias, const controller_global_t global, f_array_length_t *id) {
 
index 80a0289a7e23f1b46042eb6fea239994d72b3987..81422f8a423499d28c97d64db3e808f955eb60cc 100644 (file)
@@ -13,6 +13,26 @@ extern "C" {
 #endif
 
 /**
+ * Given a string whose range represents a number, seek past the first positive or negative sign.
+ *
+ * This will stop at the first non-NULL, non-'+' and non-'-' characters.
+ *
+ * Only the first '+' or '-' are processed.
+ *
+ * @param buffer
+ *   The string referenced by the range.
+ * @param range
+ *   The range within the buffer to process.
+ *
+ * @return
+ *   The string range.
+ *   The start range will be past the stop range on overflow or on any failure.
+ */
+#ifndef _di_controller_range_after_number_sign_
+  extern f_string_range_t controller_range_after_number_sign(const f_string_static_t buffer, const f_string_range_t range) f_attribute_visibility_internal;
+#endif // _di_controller_range_after_number_sign_
+
+/**
  * Rip a string fromt he source and then add a NULL after the end of the string.
  *
  * @param source
@@ -363,6 +383,28 @@ extern "C" {
 #endif // _di_controller_process_entry_
 
 /**
+ * Print message regarding the population of a setting when in simulation or verbose mode.
+ *
+ * @param is_entry
+ *   If TRUE, then this operate as an entry.
+ *   If FALSE, then this operate as an exit.
+ * @param global
+ *   The global data.
+ * @param name
+ *   The Object name of the setting being populated.
+ * @param name_sub
+ *   (optional) A sub-name associated with the setting being populated.
+ *   Set to NULL to disable.
+ * @param value
+ *   The value being set.
+ * @param suffix
+ *   An additional message to append at the end (before the final period).
+ */
+#ifndef _di_controller_process_entry_print_simulate_setting_value_
+  extern void controller_process_entry_print_simulate_setting_value(const bool is_entry, const controller_global_t global, const f_string_t name, const f_string_t name_sub, const f_string_static_t value, const f_string_t suffix) f_attribute_visibility_internal;
+#endif // _di_controller_process_entry_print_simulate_setting_value_
+
+/**
  * Prepare the process.
  *
  * The process is initialized with the process id, the rule alias, and the rule action type.
index e08e5e87b1994e4282b67bc06f4db5e87a5cff59..2055267c1793c8a8d6b158d55f4ec4477734792f 100644 (file)
@@ -3015,7 +3015,8 @@ extern "C" {
 #endif // _di_controller_rule_process_do_
 
 #ifndef _di_controller_rule_read_
-  f_status_t controller_rule_read(const bool is_normal, const f_string_static_t alias, controller_global_t global, controller_cache_t *cache, controller_rule_t *rule) {
+  f_status_t controller_rule_read(const bool is_normal, const f_string_static_t alias, controller_global_t global, controller_cache_t *cache, controller_entry_t *entry, controller_rule_t *rule) {
+
     f_status_t status = F_none;
 
     bool for_item = F_true;
@@ -3024,10 +3025,9 @@ extern "C" {
       rule->status[i] = F_known_not;
     } // for
 
-    // @todo timeouts may be passed from entry, consider to or not to initialize in a more consistent manner.
-    //rule->timeout_kill = 2;
-    //rule->timeout_start = 2;
-    //rule->timeout_stop = 2;
+    rule->timeout_kill = entry->timeout_kill ? entry->timeout_kill : 0;
+    rule->timeout_start = entry->timeout_start ? entry->timeout_start : 0;
+    rule->timeout_stop = entry->timeout_stop ? entry->timeout_stop : 0;
 
     rule->has = 0;
     rule->group = 0;
@@ -3402,6 +3402,9 @@ extern "C" {
       else if (fl_string_dynamic_compare_string(controller_string_script_s, cache->action.name_item, controller_string_script_length) == F_equal_to) {
         type = controller_rule_setting_type_script;
       }
+      else if (fl_string_dynamic_compare_string(controller_string_timeout_s, cache->action.name_item, controller_string_timeout_length) == F_equal_to) {
+        type = controller_rule_setting_type_timeout;
+      }
       else if (fl_string_dynamic_compare_string(controller_string_user_s, cache->action.name_item, controller_string_user_length) == F_equal_to) {
         type = controller_rule_setting_type_user;
       }
@@ -3494,22 +3497,7 @@ extern "C" {
         // @todo use sched_getaffinity() to get the available cpus and do not add an invalid cpu to the affinity array.
 
         if (!cache->content_actions.array[i].used) {
-          if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-            cache->action.line_action = ++cache->action.line_item;
-
-            controller_print_lock(global.main->error.to, global.thread);
-
-            fl_print_format("%c%[%SRule setting requires one or more Content.%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
-
-            controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-            controller_print_unlock_flush(global.main->error.to, global.thread);
-          }
+          controller_rule_setting_read_problem_print(global.main->error, "requires one or more Content", i, line_item, global.thread, cache);
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -3549,34 +3537,27 @@ extern "C" {
 
           status = fl_conversion_string_to_number_signed(cache->buffer_item.string, cache->content_actions.array[i].array[j], &number);
 
-          if (F_status_is_error(status)) {
-            status = F_status_set_fine(status);
-
-            if (status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow) {
-              if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-                // get the current line number within the settings item.
-                cache->action.line_item = line_item;
-                f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-                cache->action.line_action = ++cache->action.line_item;
-
-                controller_print_lock(global.main->error.to, global.thread);
+          if (F_status_set_fine(status) == F_number_positive) {
+            status = fl_conversion_string_to_number_signed(cache->buffer_item.string, controller_range_after_number_sign(cache->buffer_item, cache->content_actions.array[i].array[j]), &number);
 
-                if (status == F_number_overflow || status == F_number_underflow) {
-                  fl_print_format("%c%[%SRule setting has an unsupported number '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                  fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[j], global.main->error.notable);
-                  fl_print_format("%[', the number is too large for this system.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-                }
-                else {
-                  fl_print_format("%c%[%SRule setting has an invalid number '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                  fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[j], global.main->error.notable);
-                  fl_print_format("%[' only whole numbers are allowed for an affinity value.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-                }
+            // Restore error on parameter problem.
+            if (F_status_set_fine(status) == F_parameter) {
+              status = F_status_set_error(F_number_positive);
+            }
+          }
 
-                controller_rule_error_print_cache(global.main->error, cache->action, F_false);
+          if (F_status_is_error(status)) {
+            status = F_status_set_fine(status);
 
-                controller_print_unlock_flush(global.main->error.to, global.thread);
+            if (status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow || status == F_number_negative || status == F_number_decimal) {
+              if (status == F_number_underflow) {
+                controller_rule_setting_read_problem_print_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too small for this system", i, line_item, global.thread, cache);
+              }
+              else if (status == F_number_overflow || status == F_number_positive) {
+                controller_rule_setting_read_problem_print_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too large for this system", i, line_item, global.thread, cache);
+              }
+              else {
+                controller_rule_setting_read_problem_print_with_range(global.main->error, "has an invalid number", cache->content_actions.array[i].array[j], ", only whole numbers are allowed for an affinity value", i, line_item, global.thread, cache);
               }
 
               status = F_status_set_error(F_valid_not);
@@ -3601,28 +3582,15 @@ extern "C" {
           rule->affinity.array[rule->affinity.used++] = number;
         } // for
 
+        controller_rule_setting_read_print_values(global, controller_string_affinity_s, i, cache);
+
         continue;
       }
 
       if (type == controller_rule_setting_type_define || type == controller_rule_setting_type_parameter) {
 
         if (cache->content_actions.array[i].used != 2) {
-          if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-            cache->action.line_action = ++cache->action.line_item;
-
-            controller_print_lock(global.main->error.to, global.thread);
-
-            fl_print_format("%c%[%SRule setting requires exactly two Content.%]%c", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
-
-            controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-            controller_print_unlock_flush(global.main->error.to, global.thread);
-          }
+          controller_rule_setting_read_problem_print(global.main->error, "requires exactly two Content", i, line_item, global.thread, cache);
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -3725,29 +3693,16 @@ extern "C" {
           continue;
         }
 
+        controller_rule_setting_read_print_value(global, type == controller_rule_setting_type_define ? controller_string_define_s : controller_string_parameter_s, 0, setting_maps->array[setting_maps->used].name, 0);
+
         ++setting_maps->used;
 
         continue;
       }
 
       if (type == controller_rule_setting_type_control_group) {
-
         if (cache->content_actions.array[i].used < 2 || rule->has & controller_rule_has_control_group) {
-          if (global.main->error.verbosity != f_console_verbosity_quiet) {
-            controller_print_lock(global.main->error.to, global.thread);
-
-            fl_print_format("%c%[%SRule setting requires two or more Content.%]%c", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
-
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-            cache->action.line_action = ++cache->action.line_item;
-
-            controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-            controller_print_unlock_flush(global.main->error.to, global.thread);
-          }
+          controller_rule_setting_read_problem_print(global.main->error, "requires two or more Content", i, line_item, global.thread, cache);
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -3763,24 +3718,7 @@ extern "C" {
           rule->control_group.as_new = F_true;
         }
         else {
-          if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-            cache->action.line_action = ++cache->action.line_item;
-
-            controller_print_lock(global.main->error.to, global.thread);
-
-            fl_print_format("%c%[%SRule setting has an unknown option '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-            fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[0], global.main->error.notable);
-            fl_print_format("%['.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-
-            controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-            controller_print_unlock_flush(global.main->error.to, global.thread);
-          }
+          controller_rule_setting_read_problem_print_with_range(global.main->error, "has an unknown option", cache->content_actions.array[i].array[0], "", i, line_item, global.thread, cache);
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -3846,28 +3784,14 @@ extern "C" {
 
         rule->has |= controller_rule_has_control_group;
 
+        controller_rule_setting_read_print_values(global, controller_string_control_group_s, i, cache);
+
         continue;
       }
 
       if (type == controller_rule_setting_type_limit) {
         if (cache->content_actions.array[i].used != 3) {
-
-          if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-            cache->action.line_action = ++cache->action.line_item;
-
-            controller_print_lock(global.main->error.to, global.thread);
-
-            fl_print_format("%c%[%SRule setting requires three Content.%]%c", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
-
-            controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-            controller_print_unlock_flush(global.main->error.to, global.thread);
-          }
+          controller_rule_setting_read_problem_print(global.main->error, "requires three Content", i, line_item, global.thread, cache);
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -4012,35 +3936,27 @@ extern "C" {
 
           status = fl_conversion_string_to_number_signed(cache->buffer_item.string, cache->content_actions.array[i].array[j], &number);
 
-          if (F_status_is_error(status)) {
-            status = F_status_set_fine(status);
-
-            if (status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow) {
-
-              if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-                // get the current line number within the settings item.
-                cache->action.line_item = line_item;
-                f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-                cache->action.line_action = ++cache->action.line_item;
-
-                controller_print_lock(global.main->error.to, global.thread);
+          if (F_status_set_fine(status) == F_number_positive) {
+            status = fl_conversion_string_to_number_signed(cache->buffer_item.string, controller_range_after_number_sign(cache->buffer_item, cache->content_actions.array[i].array[j]), &number);
 
-                if (status == F_number_overflow || status == F_number_underflow) {
-                  fl_print_format("%c%[%SRule setting has an unsupported number'%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                  fl_print_format("%[%S%]", global.main->error.to.stream, global.main->error.notable, cache->content_actions.array[i].array[j], global.main->error.notable);
-                  fl_print_format("%[' the number is too large for this system.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-                }
-                else {
-                  fl_print_format("%c%[%SRule setting has an invalid number'%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                  fl_print_format("%[%S%]", global.main->error.to.stream, global.main->error.notable, cache->content_actions.array[i].array[j], global.main->error.notable);
-                  fl_print_format("%[' only whole numbers are allowed for a resource limit value.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-                }
+            // Restore error on parameter problem.
+            if (F_status_set_fine(status) == F_parameter) {
+              status = F_status_set_error(F_number_positive);
+            }
+          }
 
-                controller_rule_error_print_cache(global.main->error, cache->action, F_false);
+          if (F_status_is_error(status)) {
+            status = F_status_set_fine(status);
 
-                controller_print_unlock_flush(global.main->error.to, global.thread);
+            if (status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow || status == F_number_negative || status == F_number_positive || status == F_number_decimal) {
+              if (status == F_number_underflow) {
+                controller_rule_setting_read_problem_print_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too small for this system", i, line_item, global.thread, cache);
+              }
+              else if (status == F_number_overflow) {
+                controller_rule_setting_read_problem_print_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too large for this system", i, line_item, global.thread, cache);
+              }
+              else {
+                controller_rule_setting_read_problem_print_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", only whole numbers are allowed for a resource limit value", i, line_item, global.thread, cache);
               }
 
               status = F_status_set_error(F_valid_not);
@@ -4074,6 +3990,8 @@ extern "C" {
 
         rule->limits.array[rule->limits.used++].type = type;
 
+        controller_rule_setting_read_print_values(global, controller_string_limit_s, i, cache);
+
         continue;
       }
 
@@ -4090,22 +4008,7 @@ extern "C" {
         }
 
         if (setting_value->used || cache->content_actions.array[i].used != 1) {
-          if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-            cache->action.line_action = ++cache->action.line_item;
-
-            controller_print_lock(global.main->error.to, global.thread);
-
-            fl_print_format("%c%[%SRule setting requires exactly one Content.%]%c", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
-
-            controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-            controller_print_unlock_flush(global.main->error.to, global.thread);
-          }
+          controller_rule_setting_read_problem_print(global.main->error, "requires exactly one Content", i, line_item, global.thread, cache);
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -4140,53 +4043,53 @@ extern "C" {
             continue;
           }
 
-          if (type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) {
-            status = controller_validate_has_graph(*setting_value);
+          status = controller_validate_has_graph(*setting_value);
 
-            if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) {
-              if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-                // get the current line number within the settings item.
-                cache->action.line_item = line_item;
-                f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
+          if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) {
+            if (global.main->error.verbosity != f_console_verbosity_quiet) {
 
-                cache->action.line_action = ++cache->action.line_item;
-              }
+              // get the current line number within the settings item.
+              cache->action.line_item = line_item;
+              f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
 
-              if (status == F_false) {
-                if (global.main->error.verbosity != f_console_verbosity_quiet) {
-                  controller_print_lock(global.main->error.to, global.thread);
+              cache->action.line_action = ++cache->action.line_item;
+            }
 
-                  fl_print_format("%c%[%SRule setting has an invalid name '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                  fl_print_format("%[%Q%]", global.main->error.to.stream, global.main->error.notable, *setting_value, global.main->error.notable);
-                  fl_print_format("%[', there must be at least 1 graph character.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
+            if (status == F_false) {
+              if (global.main->error.verbosity != f_console_verbosity_quiet) {
+                controller_print_lock(global.main->error.to, global.thread);
 
-                  controller_rule_error_print_cache(global.main->error, cache->action, F_false);
+                fl_print_format("%c%[%SRule setting has an invalid name '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
+                fl_print_format("%[%Q%]", global.main->error.to.stream, global.main->error.notable, *setting_value, global.main->error.notable);
+                fl_print_format("%[', there must be at least 1 graph character.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
 
-                  controller_print_unlock_flush(global.main->error.to, global.thread);
-                }
+                controller_rule_error_print_cache(global.main->error, cache->action, F_false);
 
-                if (F_status_is_error_not(status_return)) {
-                  status_return = F_status_set_error(F_valid_not);
-                }
+                controller_print_unlock_flush(global.main->error.to, global.thread);
               }
-              else {
 
-                // this function should only return F_complete_not_utf on error.
-                controller_rule_error_print(global.main->error, cache->action, F_complete_not_utf, "controller_validate_has_graph", F_true, F_false, global.thread);
+              if (F_status_is_error_not(status_return)) {
+                status_return = F_status_set_error(F_valid_not);
+              }
+            }
+            else {
 
-                if (F_status_is_error_not(status_return)) {
-                  status_return = status;
-                }
+              // this function should only return F_complete_not_utf on error.
+              controller_rule_error_print(global.main->error, cache->action, F_complete_not_utf, "controller_validate_has_graph", F_true, F_false, global.thread);
 
-                controller_rule_item_error_print(global.main->error, cache->action, F_false, F_status_set_fine(status), global.thread);
+              if (F_status_is_error_not(status_return)) {
+                status_return = status;
               }
 
-              setting_value->used = 0;
-
-              continue;
+              controller_rule_item_error_print(global.main->error, cache->action, F_false, F_status_set_fine(status), global.thread);
             }
+
+            setting_value->used = 0;
+
+            continue;
           }
+
+          controller_rule_setting_read_print_value(global, type == controller_rule_setting_type_name ? controller_string_name_s : controller_string_script_s, 0, *setting_value, 0);
         }
         else if (type == controller_rule_setting_type_path) {
           status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value);
@@ -4224,6 +4127,8 @@ extern "C" {
 
             continue;
           }
+
+          controller_rule_setting_read_print_value(global, controller_string_path_s, 0, *setting_value, 0);
         }
 
         continue;
@@ -4232,22 +4137,7 @@ extern "C" {
       if (type == controller_rule_setting_type_scheduler) {
 
         if (cache->content_actions.array[i].used < 1 || cache->content_actions.array[i].used > 2 || rule->has & controller_rule_has_scheduler) {
-          if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-            cache->action.line_action = ++cache->action.line_item;
-
-            controller_print_lock(global.main->error.to, global.thread);
-
-            fl_print_format("%c%[%SRule setting requires either one or two Content.'%]%c", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
-
-            controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-            controller_print_unlock_flush(global.main->error.to, global.thread);
-          }
+          controller_rule_setting_read_problem_print(global.main->error, "requires either one or two Content", i, line_item, global.thread, cache);
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -4281,24 +4171,7 @@ extern "C" {
           rule->scheduler.priority = 49;
         }
         else {
-          if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-            cache->action.line_action = ++cache->action.line_item;
-
-            controller_print_lock(global.main->error.to, global.thread);
-
-            fl_print_format("%c%[%SRule setting has an unknown scheduler '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-            fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[0], global.main->error.notable);
-            fl_print_format("%['.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-
-            controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-            controller_print_unlock_flush(global.main->error.to, global.thread);
-          }
+          controller_rule_setting_read_problem_print_with_range(global.main->error, "has an unknown scheduler", cache->content_actions.array[i].array[0], "", i, line_item, global.thread, cache);
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -4314,10 +4187,19 @@ extern "C" {
 
           status = fl_conversion_string_to_number_signed(cache->buffer_item.string, cache->content_actions.array[i].array[1], &number);
 
+          if (F_status_set_fine(status) == F_number_positive) {
+            status = fl_conversion_string_to_number_signed(cache->buffer_item.string, controller_range_after_number_sign(cache->buffer_item, cache->content_actions.array[i].array[1]), &number);
+
+            // Restore error on parameter problem.
+            if (F_status_set_fine(status) == F_parameter) {
+              status = F_status_set_error(F_number_positive);
+            }
+          }
+
           if (F_status_is_error(status) || (zero_only && number) || (!zero_only && (number < 1 || number > 99))) {
             status = F_status_set_fine(status);
 
-            if ((zero_only && number) || (!zero_only && (number < 1 || number > 99)) || status == F_data_not || status == F_number || status == F_number_overflow) {
+            if ((zero_only && number) || (!zero_only && (number < 1 || number > 99)) || status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_negative || status == F_number_positive) {
 
               if (global.main->error.verbosity != f_console_verbosity_quiet) {
 
@@ -4370,13 +4252,34 @@ extern "C" {
 
         rule->has |= controller_rule_has_scheduler;
 
+        controller_rule_setting_read_print_values(global, controller_string_scheduler_s, i, cache);
+
         continue;
       }
 
-      if (type == controller_rule_setting_type_capability || type == controller_rule_setting_type_nice || type == controller_rule_setting_type_user) {
+      if (type == controller_rule_setting_type_timeout) {
+        if (cache->content_actions.array[i].used != 2) {
+          controller_rule_setting_read_problem_print(global.main->error, "requires exactly two Content", i, line_item, global.thread, cache);
 
-        if (cache->content_actions.array[i].used != 1 || type == controller_rule_setting_type_capability && rule->capability || type == controller_rule_setting_type_group && (rule->has & controller_rule_has_group) || type == controller_rule_setting_type_nice && (rule->has & controller_rule_has_nice) || type == controller_rule_setting_type_user && (rule->has & controller_rule_has_user)) {
+          if (F_status_is_error_not(status_return)) {
+            status_return = F_status_set_error(F_valid_not);
+          }
+
+          continue;
+        }
+
+        uint8_t timeout_code = 0;
 
+        if (fl_string_dynamic_partial_compare_string(controller_string_kill_s, cache->buffer_item, controller_string_kill_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+          timeout_code = controller_rule_timeout_code_kill;
+        }
+        else if (fl_string_dynamic_partial_compare_string(controller_string_start_s, cache->buffer_item, controller_string_start_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+          timeout_code = controller_rule_timeout_code_start;
+        }
+        else if (fl_string_dynamic_partial_compare_string(controller_string_stop_s, cache->buffer_item, controller_string_stop_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+          timeout_code = controller_rule_timeout_code_stop;
+        }
+        else {
           if (global.main->error.verbosity != f_console_verbosity_quiet) {
 
             // get the current line number within the settings item.
@@ -4387,7 +4290,9 @@ extern "C" {
 
             controller_print_lock(global.main->error.to, global.thread);
 
-            fl_print_format("%c%[%SRule setting requires exactly one Content.%]%c", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
+            fl_print_format("%c%[%SRule setting's first value has '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
+            fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[0], global.main->error.notable);
+            fl_print_format("%[' but only supports %s, %s, and %s.%]%c", global.main->error.to.stream, global.main->error.context, controller_string_kill_s, controller_string_start_s, controller_string_stop_s, global.main->error.context, f_string_eol_s[0]);
 
             controller_rule_error_print_cache(global.main->error, cache->action, F_false);
 
@@ -4401,12 +4306,97 @@ extern "C" {
           continue;
         }
 
-        if (type == controller_rule_setting_type_capability) {
-          cache->action.generic.used = 0;
+        f_number_unsigned_t number = 0;
 
-          status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &cache->action.generic);
+        status = fl_conversion_string_to_number_unsigned(cache->buffer_item.string, cache->content_actions.array[i].array[1], &number);
 
-          if (F_status_is_error(status)) {
+        if (F_status_set_fine(status) == F_number_positive) {
+          status = fl_conversion_string_to_number_unsigned(cache->buffer_item.string, controller_range_after_number_sign(cache->buffer_item, cache->content_actions.array[i].array[1]), &number);
+
+          // Restore error on parameter problem.
+          if (F_status_set_fine(status) == F_parameter) {
+            status = F_status_set_error(F_number_positive);
+          }
+        }
+
+        if (F_status_is_error(status)) {
+          status = F_status_set_fine(status);
+
+          if (status == F_number_overflow) {
+            controller_rule_setting_read_problem_print_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[1], ", the number is too large for this system", i, line_item, global.thread, cache);
+          }
+          else if (status == F_data_not || status == F_number || status == F_number_underflow || status == F_number_negative || status == F_number_positive || status == F_number_decimal) {
+            controller_rule_setting_read_problem_print_with_range(global.main->error, "has an invalid number", cache->content_actions.array[i].array[1], ", only positive whole numbers are allowed", i, line_item, global.thread, cache);
+          }
+          else {
+
+            // get the current line number within the settings item.
+            cache->action.line_item = line_item;
+            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
+
+            cache->action.line_action = ++cache->action.line_item;
+
+            controller_rule_error_print(global.main->error, cache->action, status, "fl_conversion_string_to_number_signed", F_true, F_false, global.thread);
+          }
+
+          if (F_status_is_error_not(status_return)) {
+            status_return = F_status_set_error(F_valid_not);
+          }
+        }
+        else {
+          if (timeout_code == controller_rule_timeout_code_kill) {
+            rule->timeout_kill = number;
+          }
+          else if (timeout_code == controller_rule_timeout_code_start) {
+            rule->timeout_start = number;
+          }
+          else {
+            rule->timeout_stop = number;
+          }
+
+          if (global.main->error.verbosity == f_console_verbosity_debug || (global.main->error.verbosity == f_console_verbosity_verbose && global.main->parameters[controller_parameter_simulate].result == f_console_result_found)) {
+            f_string_t name_sub = controller_string_stop_s;
+
+            if (timeout_code == controller_rule_timeout_code_kill) {
+              name_sub = controller_string_kill_s;
+            }
+            else if (timeout_code == controller_rule_timeout_code_start) {
+              name_sub = controller_string_start_s;
+            }
+
+            cache->action.generic.used = 0;
+
+            status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_item, cache->content_actions.array[i].array[1], &cache->action.generic);
+
+            if (F_status_is_error(status)) {
+              controller_error_print(global.main->error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true, global.thread);
+              break;
+            }
+
+            controller_rule_setting_read_print_value(global, controller_string_timeout_s, name_sub, cache->action.generic, 0);
+          }
+        }
+
+        continue;
+      }
+
+      if (type == controller_rule_setting_type_capability || type == controller_rule_setting_type_nice || type == controller_rule_setting_type_user) {
+        if (cache->content_actions.array[i].used != 1 || type == controller_rule_setting_type_capability && rule->capability || type == controller_rule_setting_type_group && (rule->has & controller_rule_has_group) || type == controller_rule_setting_type_nice && (rule->has & controller_rule_has_nice) || type == controller_rule_setting_type_user && (rule->has & controller_rule_has_user)) {
+          controller_rule_setting_read_problem_print(global.main->error, "requires exactly one Content", i, line_item, global.thread, cache);
+
+          if (F_status_is_error_not(status_return)) {
+            status_return = F_status_set_error(F_valid_not);
+          }
+
+          continue;
+        }
+
+        if (type == controller_rule_setting_type_capability) {
+          cache->action.generic.used = 0;
+
+          status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &cache->action.generic);
+
+          if (F_status_is_error(status)) {
 
             // get the current line number within the settings item.
             cache->action.line_item = line_item;
@@ -4483,22 +4473,7 @@ extern "C" {
               break;
             }
 
-            if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-              // get the current line number within the settings item.
-              cache->action.line_item = line_item;
-              f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-              cache->action.line_action = ++cache->action.line_item;
-
-              controller_print_lock(global.main->error.to, global.thread);
-
-              fl_print_format("%c%[%SRule setting failed to process the capabilities.%]%c", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
-
-              controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-              controller_print_unlock_flush(global.main->error.to, global.thread);
-            }
+            controller_rule_setting_read_problem_print(global.main->error, "failed to process the capabilities", i, line_item, global.thread, cache);
 
             if (F_status_is_error_not(status_return)) {
               status_return = F_status_set_error(F_valid_not);
@@ -4506,17 +4481,27 @@ extern "C" {
 
             continue;
           }
+
+          controller_rule_setting_read_print_value(global, controller_string_capability_s, 0, cache->action.generic, 0);
         }
         else if (type == controller_rule_setting_type_nice) {
           f_number_signed_t number = 0;
 
           status = fl_conversion_string_to_number_signed(cache->buffer_item.string, cache->content_actions.array[i].array[0], &number);
 
+          if (F_status_set_fine(status) == F_number_positive) {
+            status = fl_conversion_string_to_number_signed(cache->buffer_item.string, controller_range_after_number_sign(cache->buffer_item, cache->content_actions.array[i].array[0]), &number);
+
+            // Restore error on parameter problem.
+            if (F_status_set_fine(status) == F_parameter) {
+              status = F_status_set_error(F_number_positive);
+            }
+          }
+
           if (F_status_is_error(status) || number < -20 || number > 19) {
             status = F_status_set_fine(status);
 
-            if (number < -20 || number > 19 || status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow) {
-
+            if (number < -20 || number > 19 || status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow || status == F_number_decimal) {
               if (global.main->error.verbosity != f_console_verbosity_quiet) {
 
                 // get the current line number within the settings item.
@@ -4556,60 +4541,77 @@ extern "C" {
           else {
             rule->nice = number;
             rule->has |= controller_rule_has_nice;
-          }
-        }
-        else if (type == controller_rule_setting_type_user) {
-          uid_t number = 0;
 
-          status = controller_get_id_user(cache->buffer_item, cache->content_actions.array[i].array[0], cache, &number);
+            if (global.main->parameters[controller_parameter_simulate].result == f_console_result_found || global.main->error.verbosity == f_console_verbosity_verbose) {
+              cache->action.generic.used = 0;
 
-          if (F_status_is_error(status)) {
-            status = F_status_set_fine(status);
+              status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &cache->action.generic);
 
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
+              if (F_status_is_error_not(status)) {
+                status = f_string_dynamic_terminate_after(&cache->action.generic);
+              }
 
-            cache->action.line_action = ++cache->action.line_item;
+              if (F_status_is_error(status)) {
 
-            if (status == F_exist_not) {
-              if (global.main->error.verbosity != f_console_verbosity_quiet) {
-                controller_print_lock(global.main->error.to, global.thread);
+                // get the current line number within the settings item.
+                cache->action.line_item = line_item;
+                f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
 
-                fl_print_format("%c%[%SRule setting has an invalid user '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[0], global.main->error.notable);
-                fl_print_format("%[' because no user was found by that name.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
+                cache->action.line_action = ++cache->action.line_item;
 
-                controller_print_unlock_flush(global.main->error.to, global.thread);
-              }
-            }
-            else if (status == F_number_too_large) {
-              if (global.main->error.verbosity != f_console_verbosity_quiet) {
                 controller_print_lock(global.main->error.to, global.thread);
 
-                fl_print_format("%c%[%SRule setting has an invalid user '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[0], global.main->error.notable);
-                fl_print_format("%[' because the given ID is too large.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
+                controller_rule_error_print(global.main->error, cache->action, F_status_set_fine(status), cache->action.generic.used ? "f_string_dynamic_partial_append_nulless" : "f_string_dynamic_terminate_after", F_true, F_false, global.thread);
+
+                controller_rule_error_print_cache(global.main->error, cache->action, F_false);
 
                 controller_print_unlock_flush(global.main->error.to, global.thread);
+
+                if (F_status_set_fine(status) == F_memory_not) {
+                  status_return = status;
+                  break;
+                }
+
+                if (F_status_is_error_not(status_return)) {
+                  status_return = F_status_set_error(F_valid_not);
+                }
+              }
+
+              if (F_status_is_error_not(status)) {
+                controller_rule_setting_read_print_value(global, controller_string_nice_s, 0, cache->action.generic, 0);
               }
             }
-            else if (status == F_number) {
-              if (global.main->error.verbosity != f_console_verbosity_quiet) {
-                controller_print_lock(global.main->error.to, global.thread);
+          }
+        }
+        else if (type == controller_rule_setting_type_user) {
+          uid_t number = 0;
 
-                fl_print_format("%c%[%SRule setting has an invalid user '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[0], global.main->error.notable);
-                fl_print_format("%[' because the given ID is not a valid supported number.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
+          status = controller_get_id_user(cache->buffer_item, cache->content_actions.array[i].array[0], cache, &number);
 
-                controller_print_unlock_flush(global.main->error.to, global.thread);
-              }
+          if (F_status_is_error(status)) {
+            status = F_status_set_fine(status);
+
+            if (status == F_exist_not) {
+              controller_rule_setting_read_problem_print_with_range(global.main->error, "has an invalid user", cache->content_actions.array[i].array[0], ", because no user was found by that name", i, line_item, global.thread, cache);
+            }
+            else if (status == F_number_too_large) {
+              controller_rule_setting_read_problem_print_with_range(global.main->error, "has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is too large", i, line_item, global.thread, cache);
+            }
+            else if (status == F_number) {
+              controller_rule_setting_read_problem_print_with_range(global.main->error, "has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is not a valid supported number", i, line_item, global.thread, cache);
             }
             else {
+
+              // get the current line number within the settings item.
+              cache->action.line_item = line_item;
+              f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
+
+              cache->action.line_action = ++cache->action.line_item;
+
               controller_rule_error_print(global.main->error, cache->action, status, "f_account_id_user_by_name", F_true, F_false, global.thread);
-            }
 
-            controller_rule_item_error_print(global.main->error, cache->action, F_false, F_status_set_fine(status), global.thread);
+              controller_rule_item_error_print(global.main->error, cache->action, F_false, F_status_set_fine(status), global.thread);
+            }
 
             if (F_status_is_error_not(status_return)) {
               status_return = F_status_set_error(status);
@@ -4618,6 +4620,18 @@ extern "C" {
           else {
             rule->user = number;
             rule->has |= controller_rule_has_user;
+
+            if (global.main->error.verbosity == f_console_verbosity_debug || (global.main->error.verbosity == f_console_verbosity_verbose && global.main->parameters[controller_parameter_simulate].result == f_console_result_found)) {
+              cache->action.generic.used = 0;
+
+              status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &cache->action.generic);
+
+              if (F_status_is_error_not(status)) {
+                status = f_string_dynamic_terminate_after(&cache->action.generic);
+              }
+
+              controller_rule_setting_read_print_value(global, controller_string_user_s, 0, cache->action.generic, 0);
+            }
           }
         }
 
@@ -4626,22 +4640,7 @@ extern "C" {
 
       if (type == controller_rule_setting_type_group) {
         if (!cache->content_actions.array[i].used) {
-          if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-            cache->action.line_action = ++cache->action.line_item;
-
-            controller_print_lock(global.main->error.to, global.thread);
-
-            fl_print_format("%c%[%SRule setting requires one or more Content.%]%c", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
-
-            controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-            controller_print_unlock_flush(global.main->error.to, global.thread);
-          }
+          controller_rule_setting_read_problem_print(global.main->error, "requires one or more Content", i, line_item, global.thread, cache);
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -4687,49 +4686,26 @@ extern "C" {
             status = F_status_set_fine(status);
 
             if (status == F_exist_not) {
-              if (global.main->error.verbosity != f_console_verbosity_quiet) {
-                controller_print_lock(global.main->error.to, global.thread);
-
-                fl_print_format("%c%[%SRule setting has an invalid group '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[j], global.main->error.notable);
-                fl_print_format("%[' because no group was found by that name.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-
-                controller_print_unlock_flush(global.main->error.to, global.thread);
-              }
+              controller_rule_setting_read_problem_print_with_range(global.main->error, "has an invalid group", cache->content_actions.array[i].array[j], ", because no group was found by that name", i, line_item, global.thread, cache);
             }
             else if (status == F_number_too_large) {
-              if (global.main->error.verbosity != f_console_verbosity_quiet) {
-                controller_print_lock(global.main->error.to, global.thread);
-
-                fl_print_format("%c%[%SRule setting has an invalid group '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[j], global.main->error.notable);
-                fl_print_format("%[' because the given ID is too large.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-
-                controller_print_unlock_flush(global.main->error.to, global.thread);
-              }
+              controller_rule_setting_read_problem_print_with_range(global.main->error, "has an invalid group", cache->content_actions.array[i].array[j], ", because the given ID is too large", i, line_item, global.thread, cache);
             }
             else if (status == F_number) {
-              if (global.main->error.verbosity != f_console_verbosity_quiet) {
-                controller_print_lock(global.main->error.to, global.thread);
-
-                fl_print_format("%c%[%SRule setting has an invalid group '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
-                fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[j], global.main->error.notable);
-                fl_print_format("%[' because the given ID is not a valid supported number.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-
-                controller_print_unlock_flush(global.main->error.to, global.thread);
-              }
+              controller_rule_setting_read_problem_print_with_range(global.main->error, "has an invalid group", cache->content_actions.array[i].array[j], ", because the given ID is not a valid supported number", i, line_item, global.thread, cache);
             }
             else {
-              controller_rule_error_print(global.main->error, cache->action, status, "f_account_id_group_by_name", F_true, F_false, global.thread);
-            }
 
-            // get the current line number within the settings item.
-            cache->action.line_item = line_item;
-            f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
+              // get the current line number within the settings item.
+              cache->action.line_item = line_item;
+              f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
 
-            cache->action.line_action = ++cache->action.line_item;
+              cache->action.line_action = ++cache->action.line_item;
 
-            controller_rule_item_error_print(global.main->error, cache->action, F_false, F_status_set_fine(status), global.thread);
+              controller_rule_error_print(global.main->error, cache->action, status, "f_account_id_group_by_name", F_true, F_false, global.thread);
+
+              controller_rule_item_error_print(global.main->error, cache->action, F_false, F_status_set_fine(status), global.thread);
+            }
 
             if (F_status_is_error_not(status_return)) {
               status_return = F_status_set_error(status);
@@ -4746,6 +4722,8 @@ extern "C" {
           }
         } // for
 
+        controller_rule_setting_read_print_values(global, controller_string_group_s, i, cache);
+
         continue;
       }
 
@@ -4828,7 +4806,6 @@ extern "C" {
             cache->action.line_action = ++cache->action.line_item;
 
             if (status == F_false) {
-
               if (global.main->error.verbosity != f_console_verbosity_quiet) {
                 controller_print_lock(global.main->error.to, global.thread);
 
@@ -4867,28 +4844,25 @@ extern "C" {
 
         rule->has |= controller_rule_has_environment;
 
+        if (cache->content_actions.array[i].used) {
+          controller_rule_setting_read_print_values(global, controller_string_environment_s, i, cache);
+        }
+        else {
+          if (global.main->error.verbosity == f_console_verbosity_debug || (global.main->error.verbosity == f_console_verbosity_verbose && global.main->parameters[controller_parameter_simulate].result == f_console_result_found)) {
+            controller_print_lock(global.main->output, global.thread);
+
+            fl_print_format("%cProcessing rule item action '%[%s%]' setting value to an empty set.%c", global.main->output.stream, f_string_eol_s[0], global.main->context.set.title, controller_string_environment_s, global.main->context.set.title, f_string_eol_s[0]);
+
+            controller_print_unlock_flush(global.main->output, global.thread);
+          }
+        }
+
         continue;
       }
 
       // The "on" Rule Setting.
       if (cache->content_actions.array[i].used != 4) {
-
-        if (global.main->error.verbosity != f_console_verbosity_quiet) {
-
-          // get the current line number within the settings item.
-          cache->action.line_item = line_item;
-          f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
-
-          cache->action.line_action = ++cache->action.line_item;
-
-          controller_print_lock(global.main->error.to, global.thread);
-
-          fl_print_format("%c%[%SRule setting requires exactly four Content.%]%c", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context, f_string_eol_s[0]);
-
-          controller_rule_error_print_cache(global.main->error, cache->action, F_false);
-
-          controller_print_unlock_flush(global.main->error.to, global.thread);
-        }
+        controller_rule_setting_read_problem_print(global.main->error, "requires exactly four Content", i, line_item, global.thread, cache);
 
         if (F_status_is_error_not(status_return)) {
           status_return = F_status_set_error(F_valid_not);
@@ -4897,7 +4871,6 @@ extern "C" {
         continue;
       }
 
-
       if (fl_string_dynamic_partial_compare_string(controller_string_freeze_s, cache->buffer_item, controller_string_freeze_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
         action = controller_rule_action_type_freeze;
       }
@@ -4938,7 +4911,7 @@ extern "C" {
 
           controller_print_lock(global.main->error.to, global.thread);
 
-          fl_print_format("%c%[%SRule setting's first value has '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
+          fl_print_format("%c%[%SRule setting's second value has '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
           fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[1], global.main->error.notable);
           fl_print_format("%[' but only supports %s, %s, %s, %s, %s", global.main->error.to.stream, global.main->error.context, controller_string_freeze_s, controller_string_kill_s, controller_string_pause_s, controller_string_reload_s, controller_string_restart_s);
           fl_print_format("%s, %s, %s, and %s.%]%c", global.main->error.to.stream, controller_string_resume_s, controller_string_start_s, controller_string_stop_s, controller_string_thaw_s, global.main->error.context, f_string_eol_s[0]);
@@ -4989,7 +4962,7 @@ extern "C" {
 
             fl_print_format("%c%[%SRule setting's second value has '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, global.main->error.context);
             fl_print_format("%[%/Q%]", global.main->error.to.stream, global.main->error.notable, cache->buffer_item, cache->content_actions.array[i].array[1], global.main->error.notable);
-            fl_print_format("%[' but only supports %s, %s, and %s.%s.%]%c", global.main->error.to.stream, global.main->error.context, controller_string_need_s, controller_string_want_s, controller_string_wish_s, global.main->error.context, f_string_eol_s[0]);
+            fl_print_format("%[' but only supports %s, %s, and %s.%]%c", global.main->error.to.stream, global.main->error.context, controller_string_need_s, controller_string_want_s, controller_string_wish_s, global.main->error.context, f_string_eol_s[0]);
 
             controller_rule_error_print_cache(global.main->error, cache->action, F_false);
 
@@ -5103,6 +5076,17 @@ extern "C" {
       if (j == rule->ons.used) {
         ++rule->ons.used;
       }
+
+      if (global.main->error.verbosity == f_console_verbosity_debug || (global.main->error.verbosity == f_console_verbosity_verbose && global.main->parameters[controller_parameter_simulate].result == f_console_result_found)) {
+        controller_print_lock(global.main->output, global.thread);
+
+        fl_print_format("%cProcessing rule item action '%[%S%]', adding ", global.main->output.stream, f_string_eol_s[0], global.main->context.set.title, controller_string_on_s, global.main->context.set.title);
+        fl_print_format("'%[%/Q%]' of ", global.main->output.stream, global.main->context.set.notable, cache->buffer_item, cache->content_actions.array[i].array[1], global.main->context.set.notable);
+        fl_print_format("'%[%/Q%]/", global.main->output.stream, global.main->context.set.important, cache->buffer_item, cache->content_actions.array[i].array[2], global.main->context.set.important);
+        fl_print_format("%[%/Q%]'.%c", global.main->output.stream, global.main->context.set.important, cache->buffer_item, cache->content_actions.array[i].array[3], global.main->context.set.important, f_string_eol_s[0]);
+
+        controller_print_unlock_flush(global.main->output, global.thread);
+      }
     } // for
 
     // resore the current name item and line number, which there should already be enough allocated space for.
@@ -5117,6 +5101,108 @@ extern "C" {
   }
 #endif // _di_controller_rule_setting_read_
 
+#ifndef _di_controller_rule_setting_read_print_value_
+  void controller_rule_setting_read_print_value(const controller_global_t global, const f_string_t name, const f_string_t name_sub, const f_string_static_t value, const f_string_t suffix) {
+
+    if (global.main->error.verbosity != f_console_verbosity_debug && !(global.main->error.verbosity == f_console_verbosity_verbose && global.main->parameters[controller_parameter_simulate].result == f_console_result_found)) {
+      return;
+    }
+
+    controller_print_lock(global.main->output, global.thread);
+
+    fl_print_format("%cProcessing rule item action '%[%S%]' setting ", global.main->output.stream, f_string_eol_s[0], global.main->context.set.title, name, global.main->context.set.title);
+
+    if (name_sub) {
+      fl_print_format("'%[%S%]'", global.main->output.stream, global.main->context.set.notable, name_sub, global.main->context.set.notable);
+    }
+    else {
+      f_print_terminated("value", global.main->output.stream);
+    }
+
+    fl_print_format(" to '%[%Q%]'", global.main->output.stream, global.main->context.set.important, value, global.main->context.set.important);
+    fl_print_format("%S.%c", global.main->output.stream, suffix, f_string_eol_s[0]);
+
+    controller_print_unlock_flush(global.main->output, global.thread);
+  }
+#endif // _di_controller_rule_setting_read_print_value_
+
+#ifndef _di_controller_rule_setting_read_print_values_
+  void controller_rule_setting_read_print_values(const controller_global_t global, const f_string_t name, const f_array_length_t index, controller_cache_t *cache) {
+
+    if (global.main->error.verbosity != f_console_verbosity_debug && !(global.main->error.verbosity == f_console_verbosity_verbose && global.main->parameters[controller_parameter_simulate].result == f_console_result_found)) {
+      return;
+    }
+
+    controller_print_lock(global.main->output, global.thread);
+
+    fl_print_format("%cProcessing rule item action '%[%S%]' setting value to", global.main->output.stream, f_string_eol_s[0], global.main->context.set.title, name, global.main->context.set.title);
+
+    for (f_array_length_t j = 0; j < cache->content_actions.array[index].used; ++j) {
+
+      fl_print_format(" '%[%/Q%]'", global.main->output.stream, global.main->context.set.important, cache->buffer_item, cache->content_actions.array[index].array[j], global.main->context.set.important);
+
+      if (j + 2 == cache->content_actions.array[index].used) {
+        if (cache->content_actions.array[index].used > 2) {
+          f_print_terminated(",", global.main->output.stream);
+        }
+
+        f_print_terminated(" and", global.main->output.stream);
+      }
+      else if (j + 1 < cache->content_actions.array[index].used) {
+        f_print_terminated(",", global.main->output.stream);
+      }
+    } // for
+
+    fl_print_format(".%c", global.main->output.stream, f_string_eol_s[0]);
+
+    controller_print_unlock_flush(global.main->output, global.thread);
+  }
+#endif // _di_controller_rule_setting_read_print_value_
+
+#ifndef _di_controller_rule_setting_read_problem_print_
+  void controller_rule_setting_read_problem_print(const fll_error_print_t print, const f_string_t message, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t *thread, controller_cache_t *cache) {
+
+    if (print.verbosity == f_console_verbosity_quiet) return;
+
+    // get the current line number within the settings item.
+    cache->action.line_item = line_item;
+    f_fss_count_lines(cache->buffer_item, cache->object_actions.array[index].start, &cache->action.line_item);
+
+    cache->action.line_action = ++cache->action.line_item;
+
+    controller_print_lock(print.to, thread);
+
+    fl_print_format("%c%[%SRule setting %S.%]%c", print.to.stream, f_string_eol_s[0], print.context, print.prefix, message, print.context, f_string_eol_s[0]);
+
+    controller_rule_error_print_cache(print, cache->action, F_false);
+
+    controller_print_unlock_flush(print.to, thread);
+  }
+#endif // _di_controller_rule_setting_read_problem_print_
+
+#ifndef _di_controller_rule_setting_read_problem_print_with_range_
+  void controller_rule_setting_read_problem_print_with_range(const fll_error_print_t print, const f_string_t before, const f_string_range_t range, const f_string_t after, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t *thread, controller_cache_t *cache) {
+
+    if (print.verbosity == f_console_verbosity_quiet) return;
+
+    // get the current line number within the settings item.
+    cache->action.line_item = line_item;
+    f_fss_count_lines(cache->buffer_item, cache->object_actions.array[index].start, &cache->action.line_item);
+
+    cache->action.line_action = ++cache->action.line_item;
+
+    controller_print_lock(print.to, thread);
+
+    fl_print_format("%c%[%SRule setting %S '%]", print.to.stream, f_string_eol_s[0], print.context, print.prefix, before, print.context);
+    fl_print_format("%[%/Q%]", print.to.stream, print.notable, cache->buffer_item, range, print.notable);
+    fl_print_format("%['%S.%]%c", print.to.stream, print.context, after, print.context, f_string_eol_s[0]);
+
+    controller_rule_error_print_cache(print, cache->action, F_false);
+
+    controller_print_unlock_flush(print.to, thread);
+  }
+#endif // _di_controller_rule_setting_read_problem_print_with_range_
+
 #ifndef _di_controller_rule_validate_
   void controller_rule_validate(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_global_t global, controller_cache_t *cache) {
 
index b884da1de5da81b8ff272cfe92f41eb1d62c5309..0f8e793acc2bb845b1cfb4efc695bfe6e7c78409 100644 (file)
@@ -751,6 +751,8 @@ extern "C" {
  *   The global data.
  * @param cache
  *   A structure for containing and caching relevant data.
+ * @param entry
+ *   The entry containing the rule being read.
  * @param rule
  *   The processed rule.
  *   The rule status will be updated by this function.
@@ -770,7 +772,7 @@ extern "C" {
  * @see fll_fss_basic_list_read().
  */
 #ifndef _di_controller_rule_read_
-  extern f_status_t controller_rule_read(const bool is_normal, const f_string_static_t alias, controller_global_t global, controller_cache_t *cache, controller_rule_t *rule) f_attribute_visibility_internal;
+  extern f_status_t controller_rule_read(const bool is_normal, const f_string_static_t alias, controller_global_t global, controller_cache_t *cache, controller_entry_t *entry, controller_rule_t *rule) f_attribute_visibility_internal;
 #endif // _di_controller_rule_read_
 
 /**
@@ -816,6 +818,97 @@ extern "C" {
 #endif // _di_controller_rule_setting_read_
 
 /**
+ * Print message regarding the population of a setting when in simulation or verbose mode.
+ *
+ * @param global
+ *   The global data.
+ * @param name
+ *   The Object name of the setting being populated.
+ * @param name_sub
+ *   (optional) A sub-name associated with the setting being populated.
+ *   Set to NULL to disable.
+ * @param value
+ *   The value being set.
+ * @param suffix
+ *   An additional message to append at the end (before the final period).
+ */
+#ifndef _di_controller_rule_setting_read_print_value_
+  extern void controller_rule_setting_read_print_value(const controller_global_t global, const f_string_t name, const f_string_t name_sub, const f_string_static_t value, const f_string_t suffix) f_attribute_visibility_internal;
+#endif // _di_controller_rule_setting_read_print_value_
+
+/**
+ * Print message regarding the population of a setting when in simulation or verbose mode.
+ *
+ * This handles the case where there are multiple values stored in the buffer_item at a given content_actions position.
+ *
+ * @param global
+ *   The global data.
+ * @param name
+ *   The Object name of the setting being populated.
+ * @param index
+ *   Position within the content_actions range cache array.
+ * @param cache
+ *   A structure for containing and caching relevant data.
+ */
+#ifndef _di_controller_rule_setting_read_print_values_
+  extern void controller_rule_setting_read_print_values(const controller_global_t global, const f_string_t name, const f_array_length_t index, controller_cache_t *cache) f_attribute_visibility_internal;
+#endif // _di_controller_rule_setting_read_print_values_
+
+/**
+ * Print a message about a rule setting problem.
+ *
+ * This is intended to be explicitly called by controller_rule_setting_read().
+ * This is intended only to be used for simple messages.
+ *
+ * @param print
+ *   The error or warning output structure.
+ * @param message
+ *   The string to append to the message being printed.
+ * @param index
+ *   The position in the object actions cache representing the object.
+ * @param line_item
+ *   The current line number.
+ * @param thread
+ *   The thread data.
+ * @param cache
+ *   A structure for containing and caching relevant data.
+ *
+ * @see controller_rule_setting_read()
+ */
+#ifndef _di_controller_rule_setting_read_problem_print_
+  extern void controller_rule_setting_read_problem_print(const fll_error_print_t print, const f_string_t message, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t *thread, controller_cache_t *cache) f_attribute_visibility_internal;
+#endif // _di_controller_rule_setting_read_problem_print_
+
+/**
+ * Print a message about a rule setting problem, with additional messages about value.
+ *
+ * This is intended to be explicitly called by controller_rule_setting_read().
+ * This is intended only to be used for simple messages.
+ *
+ * @param print
+ *   The error or warning output structure.
+ * @param before
+ *   The string to append to the message being printed (before the value).
+ * @param range
+ *   The range within the cache item buffer representing the value.
+ * @param after
+ *   The string to append to the message being printed (after the value).
+ * @param index
+ *   The position in the object actions cache representing the object.
+ * @param line_item
+ *   The current line number.
+ * @param thread
+ *   The thread data.
+ * @param cache
+ *   A structure for containing and caching relevant data.
+ *
+ * @see controller_rule_setting_read()
+ */
+#ifndef _di_controller_rule_setting_read_problem_print_with_range_
+  extern void controller_rule_setting_read_problem_print_with_range(const fll_error_print_t print, const f_string_t before, const f_string_range_t range, const f_string_t after, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t *thread, controller_cache_t *cache) f_attribute_visibility_internal;
+#endif // _di_controller_rule_setting_read_problem_print_with_range_
+
+/**
  * Perform a simulated execution of the given rule.
  *
  * This simply prints information about the rule.
index e419b8697b68f3845c16903f31465b8694d22377..326e41dae7e36ef84e7dfe69e6613fe3f4183c54 100644 (file)
@@ -100,15 +100,15 @@ Entry Documentation:
   This is specific to Control Groups and is not yet fully implemented.
   Once implemented this documentation will need to be updated and clarified.
 
-  The "timeout" Item Action provides default global settings for each of the three special situations: "start", "stop", and "kill".
-  Each of these may only have a single one exist at a time (one "start", one "stop", and one "kill").
-  Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
-  Each of these accepts a single Action Parameter that is a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
-  For "start", this represents the number of MegaTime to wait after starting some rule before assuming something went wrong and the rule is returned as failed.
-  For "stop", this represents the number of MegaTime to wait after stopping some rule before assuming something went wrong and the rule is returned as failed.
-  For "kill", this represents the number of MegaTime to wait after stopping some rule and that rule has not yet stopped to forcefully stop the rule (aka kill the rule).
-  The timeouts are generally only valid for services such as daemon services.
-  A value of 0 disables this (prevents any action).
+  In the case of "timeout"\:
+    The "timeout" Item Action provides default global settings for each of the three special situations: "kill", "start", and "stop".
+    Each of these may only have a single one exist at a time (one "kill", one "start", one "stop", and one "wait").
+    Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
+    Each of these accepts a single Action Parameter that is a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+    For "kill", this represents the number of MegaTime to wait after stopping some rule and that rule has not yet stopped to forcefully stop the rule (aka kill the rule).
+    For "start", this represents the number of MegaTime to wait after starting some rule before assuming something went wrong and the rule is returned as failed.
+    For "stop", this represents the number of MegaTime to wait after stopping some rule before assuming something went wrong and the rule is returned as failed.
+    A value of 0 disables this (prevents the timeout action).
 
 Entry Rule Documentation:
   There are multiple Entry Actions that are considered "rule" Actions.
index d52db9447eb4004c7a6574501fb128735dcddefd..a12869d6d60d14d56f08b3d20c7363e0d317f2c2 100644 (file)
@@ -9,7 +9,7 @@ Rule Documentation:
   Multiple outer most list Objects may be specified and they are executed as provided, in a top-down manner.
 
   The "setting" Rule Type has the following FSS-0001 (Extended) Content\:
-    "affinity": Define one ore more processors to restrict this rule by with each number representing a specific processor by its id (starting at 0).
+    "affinity": Define one or more processors to restrict this rule by with each number representing a specific processor by its id (starting at 0).
     "capability": Define a set of capabilities in which to use, using the capability "text" format (such as "= cap_chown+ep").
     "control_group": Define a control group (cgroup) in which everything within this rule executes under.
     "define": Define a custom environment variable with a given variable, and automatically expose it to processes executed within this rule. @todo make sure this is implemented.
@@ -23,6 +23,7 @@ Rule Documentation:
     "path": A single Content used to set a custom PATH environment variable value.
     "script": An executable name of a script, such as "bash", to use for the "script" Rule Type (which likely defaults to "bash" if not specified).
     "scheduler": A valid name of a scheduler to use followed by an optional priority number.
+    "timeout": A set of timeouts to wait for in which to perform a set action or to consider failure.
     "user": A single user name or ID to execute as.
 
   In the case of "capability"\:
@@ -73,6 +74,16 @@ Rule Documentation:
     Supported non-real-time schedulers are: "batch", "idle", and "other" (aka: normal/default).
     Supported real-time schedulers are: "deadline", "fifo", "round_robin".
 
+  In the case of "timeout"\:
+    The "timeout" Item Action provides default global settings for each of the three special situations: "kill", "start", and "stop".
+    Each of these may only have a single one exist at a time (one "kill", one "start", one "stop", and one "wait").
+    Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
+    Each of these accepts a single Action Parameter that is a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+    For "kill", this represents the number of MegaTime to wait after stopping some rule and that rule has not yet stopped to forcefully stop the rule (aka kill the rule).
+    For "start", this represents the number of MegaTime to wait after starting some rule before assuming something went wrong and the rule is returned as failed.
+    For "stop", this represents the number of MegaTime to wait after stopping some rule before assuming something went wrong and the rule is returned as failed.
+    A value of 0 disables this (prevents the timeout action).
+
   There are four available Rule Types to choose from: "command", "service", "script", and "utility".
 
   The "command" Rule Type provides a simple command to run under the different circumstances: "start", "stop", "restart", and "reload".