]> Kevux Git Server - fll/commitdiff
Progress: controller program.
authorKevin Day <thekevinday@gmail.com>
Mon, 30 Nov 2020 03:45:02 +0000 (21:45 -0600)
committerKevin Day <thekevinday@gmail.com>
Mon, 30 Nov 2020 03:45:02 +0000 (21:45 -0600)
level_3/control/c/control.c
level_3/controller/c/controller.c
level_3/controller/c/private-controller.c
level_3/controller/c/private-controller.h
level_3/controller/c/private-entry.c
level_3/controller/c/private-rule.c
level_3/controller/c/private-rule.h
level_3/controller/data/build/dependencies
level_3/controller/documents/rule.txt
level_3/controller/specifications/rule.txt
specifications/fss-000D.txt

index 1ece906e77a901f0b95e89982a644ca2b7cb7cae..ee12ecfda9aa369ab3cf3737c2fb406d07abe71d 100644 (file)
@@ -39,8 +39,24 @@ extern "C" {
 
         status = fll_program_parameter_process(arguments, parameters, choices, F_true, &data->remaining, &data->context);
 
-        data->error.context = data->context.set.error;
-        data->error.notable = data->context.set.notable;
+        if (data->context.set.error.before) {
+          data->error.context = data->context.set.error;
+          data->error.notable = data->context.set.notable;
+
+          data->warning.context = data->context.set.warning;
+          data->warning.notable = data->context.set.notable;
+        }
+        else {
+          data->error.context.before = &fll_error_string_null_s;
+          data->error.context.after = &fll_error_string_null_s;
+          data->error.notable.before = &fll_error_string_null_s;
+          data->error.notable.after = &fll_error_string_null_s;
+
+          data->warning.context.before = &fll_error_string_null_s;
+          data->warning.context.after = &fll_error_string_null_s;
+          data->warning.notable.before = &fll_error_string_null_s;
+          data->warning.notable.after = &fll_error_string_null_s;
+        }
 
         if (F_status_is_error(status)) {
           if (data->error.verbosity != f_console_verbosity_quiet) {
index b97923f002aec5e33e4f2423a2cf22fc464dee60..a26ab055e8852b25de6f7587f50b4f0c98f1ed61 100644 (file)
@@ -41,8 +41,6 @@ extern "C" {
   f_return_status controller_main(const f_console_arguments_t arguments, controller_data_t *data) {
     f_status_t status = F_none;
 
-    // @todo somewhere in here, check to see if the standard pid file exists before attempting to start (when in normal operation mode).
-
     {
       const f_console_parameters_t parameters = f_macro_console_parameters_t_initialize(data->parameters, controller_total_parameters);
 
@@ -52,11 +50,24 @@ extern "C" {
 
         status = fll_program_parameter_process(arguments, parameters, choices, F_true, &data->remaining, &data->context);
 
-        data->error.context = data->context.set.error;
-        data->error.notable = data->context.set.notable;
+        if (data->context.set.error.before) {
+          data->error.context = data->context.set.error;
+          data->error.notable = data->context.set.notable;
 
-        data->warning.context = data->context.set.warning;
-        data->warning.notable = data->context.set.notable;
+          data->warning.context = data->context.set.warning;
+          data->warning.notable = data->context.set.notable;
+        }
+        else {
+          data->error.context.before = &fll_error_string_null_s;
+          data->error.context.after = &fll_error_string_null_s;
+          data->error.notable.before = &fll_error_string_null_s;
+          data->error.notable.after = &fll_error_string_null_s;
+
+          data->warning.context.before = &fll_error_string_null_s;
+          data->warning.context.after = &fll_error_string_null_s;
+          data->warning.notable.before = &fll_error_string_null_s;
+          data->warning.notable.after = &fll_error_string_null_s;
+        }
 
         if (F_status_is_error(status)) {
           if (data->error.verbosity != f_console_verbosity_quiet) {
@@ -135,14 +146,102 @@ extern "C" {
       entry_name.size = entry_name.used;
     }
 
-    status = controller_entry_read(*data, setting, entry_name, &cache_entry, &setting.entry);
+    if (data->parameters[controller_parameter_settings].result == f_console_result_found) {
+      if (data->error.verbosity != f_console_verbosity_quiet) {
+        fprintf(data->error.to.stream, "%c", f_string_eol[0]);
+        fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : "");
+        fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_settings, data->error.notable.after->string);
+        fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol[0]);
+      }
+
+      status = F_status_set_error(F_parameter);
+    }
+    else if (data->parameters[controller_parameter_settings].locations.used) {
+      const f_array_length_t location = data->parameters[controller_parameter_settings].values.array[data->parameters[controller_parameter_settings].values.used - 1];
+
+      status = fll_path_canonical(arguments.argv[location], &setting.path_setting);
+
+      if (F_status_is_error(status)) {
+        if (data->error.verbosity != f_console_verbosity_quiet) {
+          fll_error_print(data->error, F_status_set_fine(status), "fll_path_canonical", F_true);
+        }
+      }
+    }
+    else {
+      status = fl_string_append(controller_path_settings, controller_path_settings_length, &setting.path_setting);
+
+      if (F_status_is_error(status)) {
+        if (data->error.verbosity != f_console_verbosity_quiet) {
+          fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true);
+        }
+      }
+    }
+
+    if (data->parameters[controller_parameter_pid].result == f_console_result_found) {
+      if (data->error.verbosity != f_console_verbosity_quiet) {
+        fprintf(data->error.to.stream, "%c", f_string_eol[0]);
+        fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : "");
+        fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_pid, data->error.notable.after->string);
+        fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol[0]);
+      }
 
-    // @fixme this is temporary for testing.
-    if (F_status_is_error(setting.entry.status)) {
-      status = setting.entry.status;
+      status = F_status_set_error(F_parameter);
     }
+    else if (data->parameters[controller_parameter_pid].locations.used) {
+      const f_array_length_t location = data->parameters[controller_parameter_pid].values.array[data->parameters[controller_parameter_pid].values.used - 1];
+
+      if (strnlen(arguments.argv[location], f_console_length_size)) {
+        status = fll_path_canonical(arguments.argv[location], &setting.path_pid);
 
-    // @todo
+        if (F_status_is_error(status)) {
+          if (data->error.verbosity != f_console_verbosity_quiet) {
+            fll_error_print(data->error, F_status_set_fine(status), "fll_path_canonical", F_true);
+          }
+        }
+      }
+      else {
+        if (data->warning.verbosity == f_console_verbosity_debug) {
+          fprintf(data->warning.to.stream, "%c", f_string_eol[0]);
+          fprintf(data->warning.to.stream, "%s%sThe parameter '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : "");
+          fprintf(data->warning.to.stream, "%s%s%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, f_console_symbol_long_enable, controller_long_pid, data->warning.notable.after->string);
+          fprintf(data->warning.to.stream, "%s' must be a file path but instead is an empty string, falling back to the default.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol[0]);
+        }
+      }
+    }
+
+    // the pid file is required.
+    if (!setting.path_pid.used) {
+      status = fl_string_append(controller_path_pid, controller_path_pid_length, &setting.path_pid);
+
+      if (F_status_is_error(status)) {
+        if (data->error.verbosity != f_console_verbosity_quiet) {
+          fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true);
+        }
+      }
+    }
+
+    if (F_status_is_error_not(status)) {
+      status = controller_entry_read(*data, setting, entry_name, &cache_entry, &setting.entry);
+
+      // @fixme this is temporary and may or may not be used when finished codestorming.
+      if (F_status_is_error(setting.entry.status)) {
+        status = setting.entry.status;
+      }
+    }
+
+    if (F_status_is_error_not(status)) {
+      if (data->parameters[controller_parameter_test].result == f_console_result_found || data->parameters[controller_parameter_validate].result == f_console_result_found) {
+        // @todo validate happens first, report and handle validation problems or success.
+
+        if (data->parameters[controller_parameter_test].result == f_console_result_found) {
+          // @todo after validation succeeds, perform test run.
+        }
+      }
+      else {
+        // @todo check to see if the standard pid file exists before attempting to start (when in normal operation mode).
+        // @todo real execution.
+      }
+    }
 
     // ensure a newline is always put at the end of the program execution, unless in quiet mode.
     if (data->error.verbosity != f_console_verbosity_quiet) {
index 27f975101e02f5dceb2103b5b548e7f47e96ca7e..61c30fa6e2f739eda2223c02fabfa8f53b866952 100644 (file)
@@ -49,25 +49,28 @@ extern "C" {
       return status;
     }
 
-    const f_string_length_t path_length = setting.path_setting.used + f_path_separator_length + path_file->used;
+    const f_string_length_t path_length = setting.path_setting.used ? setting.path_setting.used + f_path_separator_length + path_file->used : path_file->used;
     char path[path_length + 1];
 
-    memcpy(path, setting.path_setting.string, setting.path_setting.used);
-    memcpy(path + setting.path_setting.used + f_path_separator_length, path_file->string, path_file->used);
+    if (setting.path_setting.used) {
+      memcpy(path, setting.path_setting.string, setting.path_setting.used);
+      memcpy(path + setting.path_setting.used + f_path_separator_length, path_file->string, path_file->used);
+
+      path[setting.path_setting.used] = f_path_separator[0];
+    }
 
-    path[setting.path_setting.used] = f_path_separator[0];
     path[path_length] = 0;
 
     status = f_file_stream_open(path, 0, &file);
 
     if (F_status_is_error(status)) {
-      fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_open", F_true, path_file->string, "open", fll_error_file_type_file);
+      fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_open", F_true, path, "open", fll_error_file_type_file);
     }
     else {
       status = f_file_stream_read(file, 1, buffer);
 
       if (F_status_is_error(status)) {
-        fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_read", F_true, path_file->string, "read", fll_error_file_type_file);
+        fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_read", F_true, path, "read", fll_error_file_type_file);
       }
     }
 
index 34aeb742fcdab4f1821e07aa89f42f4cebf6d7fb..5374ad2fddf2cb3faa052a2d925c0ae1e2335fd3 100644 (file)
@@ -13,77 +13,81 @@ extern "C" {
 #endif
 
 #ifndef _di_controller_string_
-  #define controller_string_asynchronous "asynchronous"
-  #define controller_string_create       "create"
-  #define controller_string_command      "command"
-  #define controller_string_consider     "consider"
-  #define controller_string_default      "default"
-  #define controller_string_define       "define"
-  #define controller_string_entry        "entry"
-  #define controller_string_entries      "entries"
-  #define controller_string_environment  "environment"
-  #define controller_string_failsafe     "failsafe"
-  #define controller_string_group        "group"
-  #define controller_string_item         "item"
-  #define controller_string_kill         "kill"
-  #define controller_string_main         "main"
-  #define controller_string_name         "name"
-  #define controller_string_need         "need"
-  #define controller_string_path         "path"
-  #define controller_string_pid          "pid"
-  #define controller_string_ready        "ready"
-  #define controller_string_reload       "reload"
-  #define controller_string_require      "require"
-  #define controller_string_restart      "restart"
-  #define controller_string_rule         "rule"
-  #define controller_string_rules        "rules"
-  #define controller_string_script       "script"
-  #define controller_string_service      "service"
-  #define controller_string_settings     "settings"
-  #define controller_string_start        "start"
-  #define controller_string_stop         "stop"
-  #define controller_string_timeout      "timeout"
-  #define controller_string_use          "use"
-  #define controller_string_user         "user"
-  #define controller_string_wait         "wait"
-  #define controller_string_want         "want"
-  #define controller_string_wish         "wish"
-
-  #define controller_string_asynchronous_length 12
-  #define controller_string_create_length       6
-  #define controller_string_command_length      7
-  #define controller_string_consider_length     8
-  #define controller_string_define_length       6
-  #define controller_string_default_length      7
-  #define controller_string_entry_length        5
-  #define controller_string_entries_length      7
-  #define controller_string_environment_length  11
-  #define controller_string_failsafe_length     8
-  #define controller_string_group_length        5
-  #define controller_string_item_length         4
-  #define controller_string_kill_length         4
-  #define controller_string_main_length         4
-  #define controller_string_name_length         4
-  #define controller_string_need_length         4
-  #define controller_string_path_length         4
-  #define controller_string_pid_length          3
-  #define controller_string_ready_length        5
-  #define controller_string_reload_length       6
-  #define controller_string_require_length      7
-  #define controller_string_restart_length      7
-  #define controller_string_rule_length         4
-  #define controller_string_rules_length        5
-  #define controller_string_script_length       6
-  #define controller_string_service_length      7
-  #define controller_string_settings_length     8
-  #define controller_string_start_length        5
-  #define controller_string_stop_length         4
-  #define controller_string_timeout_length      7
-  #define controller_string_use_length          3
-  #define controller_string_user_length         4
-  #define controller_string_wait_length         4
-  #define controller_string_want_length         4
-  #define controller_string_wish_length         4
+  #define controller_string_asynchronous  "asynchronous"
+  #define controller_string_create        "create"
+  #define controller_string_command       "command"
+  #define controller_string_consider      "consider"
+  #define controller_string_control_group "control_group"
+  #define controller_string_default       "default"
+  #define controller_string_define        "define"
+  #define controller_string_entry         "entry"
+  #define controller_string_entries       "entries"
+  #define controller_string_environment   "environment"
+  #define controller_string_failsafe      "failsafe"
+  #define controller_string_group         "group"
+  #define controller_string_item          "item"
+  #define controller_string_kill          "kill"
+  #define controller_string_main          "main"
+  #define controller_string_name          "name"
+  #define controller_string_need          "need"
+  #define controller_string_parameter     "parameter"
+  #define controller_string_path          "path"
+  #define controller_string_pid           "pid"
+  #define controller_string_ready         "ready"
+  #define controller_string_reload        "reload"
+  #define controller_string_require       "require"
+  #define controller_string_restart       "restart"
+  #define controller_string_rule          "rule"
+  #define controller_string_rules         "rules"
+  #define controller_string_script        "script"
+  #define controller_string_service       "service"
+  #define controller_string_settings      "settings"
+  #define controller_string_start         "start"
+  #define controller_string_stop          "stop"
+  #define controller_string_timeout       "timeout"
+  #define controller_string_use           "use"
+  #define controller_string_user          "user"
+  #define controller_string_wait          "wait"
+  #define controller_string_want          "want"
+  #define controller_string_wish          "wish"
+
+  #define controller_string_asynchronous_length  12
+  #define controller_string_create_length        6
+  #define controller_string_command_length       7
+  #define controller_string_consider_length      8
+  #define controller_string_control_group_length 13
+  #define controller_string_define_length        6
+  #define controller_string_default_length       7
+  #define controller_string_entry_length         5
+  #define controller_string_entries_length       7
+  #define controller_string_environment_length   11
+  #define controller_string_failsafe_length      8
+  #define controller_string_group_length         5
+  #define controller_string_item_length          4
+  #define controller_string_kill_length          4
+  #define controller_string_main_length          4
+  #define controller_string_name_length          4
+  #define controller_string_need_length          4
+  #define controller_string_parameter_length     9
+  #define controller_string_path_length          4
+  #define controller_string_pid_length           3
+  #define controller_string_ready_length         5
+  #define controller_string_reload_length        6
+  #define controller_string_require_length       7
+  #define controller_string_restart_length       7
+  #define controller_string_rule_length          4
+  #define controller_string_rules_length         5
+  #define controller_string_script_length        6
+  #define controller_string_service_length       7
+  #define controller_string_settings_length      8
+  #define controller_string_start_length         5
+  #define controller_string_stop_length          4
+  #define controller_string_timeout_length       7
+  #define controller_string_use_length           3
+  #define controller_string_user_length          4
+  #define controller_string_wait_length          4
+  #define controller_string_want_length          4
+  #define controller_string_wish_length          4
 #endif // _di_controller_string_
 
 #ifndef _di_controller_rule_action_t_
@@ -211,6 +215,18 @@ extern "C" {
 #endif // _di_controller_rule_items_t_
 
 #ifndef _di_controller_rule_t_
+  enum {
+    controller_rule_setting_type_control_group = 1,
+    controller_rule_setting_type_define,
+    controller_rule_setting_type_environment,
+    controller_rule_setting_type_name,
+    controller_rule_setting_type_need,
+    controller_rule_setting_type_parameter,
+    controller_rule_setting_type_path,
+    controller_rule_setting_type_want,
+    controller_rule_setting_type_wish,
+  };
+
   typedef struct {
     f_status_t status;
 
@@ -218,9 +234,9 @@ extern "C" {
     f_string_dynamic_t name;
     f_string_dynamic_t control_group;
     f_string_dynamic_t path;
-    f_string_dynamic_t pid;
 
-    f_string_maps_t defines;
+    f_string_maps_t define;
+    f_string_maps_t parameter;
 
     f_string_dynamics_t environment;
     f_string_dynamics_t need;
@@ -237,7 +253,7 @@ extern "C" {
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
-      f_string_dynamic_t_initialize, \
+      f_string_maps_t_initialize, \
       f_string_maps_t_initialize, \
       f_string_dynamics_t_initialize, \
       f_string_dynamics_t_initialize, \
@@ -251,8 +267,8 @@ extern "C" {
     f_macro_string_dynamic_t_delete_simple(rule.name) \
     f_macro_string_dynamic_t_delete_simple(rule.control_group) \
     f_macro_string_dynamic_t_delete_simple(rule.path) \
-    f_macro_string_dynamic_t_delete_simple(rule.pid) \
-    f_macro_string_maps_t_delete_simple(rule.defines) \
+    f_macro_string_maps_t_delete_simple(rule.define) \
+    f_macro_string_maps_t_delete_simple(rule.parameter) \
     f_macro_string_dynamics_t_delete_simple(rule.environment) \
     f_macro_string_dynamics_t_delete_simple(rule.need) \
     f_macro_string_dynamics_t_delete_simple(rule.want) \
@@ -429,6 +445,7 @@ extern "C" {
     bool interruptable;
     bool ready;
 
+    f_string_dynamic_t path_pid;
     f_string_dynamic_t path_setting;
 
     controller_entry_t entry;
@@ -440,11 +457,13 @@ extern "C" {
       F_false, \
       F_false, \
       f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
       controller_entry_t_initialize, \
       controller_rules_t_initialize, \
     }
 
   #define macro_controller_setting_t_delete_simple(setting) \
+    f_macro_string_dynamic_t_delete_simple(setting.path_pid) \
     f_macro_string_dynamic_t_delete_simple(setting.path_setting) \
     macro_controller_entry_t_delete_simple(setting.entry) \
     macro_controller_rules_t_delete_simple(setting.rules)
index 3211646c2705212bcce3f90a605249d3af2a7210..2c3468e0ea5f78f18b3ef5b25b90b4e33a5806ae 100644 (file)
@@ -207,6 +207,8 @@ extern "C" {
         if (F_status_is_error(status)) {
           fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase_by", F_true);
 
+          action->status = status;
+
           if (F_status_is_error_not(status_action)) {
             status_action = status;
           }
@@ -223,6 +225,8 @@ extern "C" {
           if (F_status_is_error(status)) {
             fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
 
+            action->status = status;
+
             if (F_status_is_error_not(status_action)) {
               status_action = status;
             }
@@ -243,6 +247,8 @@ extern "C" {
               if (F_status_is_error(status)) {
                 fll_error_print(data.error, F_status_set_fine(status), "fll_path_canonical", F_true);
 
+                action->status = status;
+
                 if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
                   status_action = status;
                   break;
@@ -267,6 +273,59 @@ extern "C" {
             }
 
             if (action->parameters.array[1].used) {
+              cache->buffer_path.used = 0;
+
+              status = f_file_name_base(action->parameters.array[1].string, action->parameters.array[1].used, &cache->buffer_path);
+
+              if (F_status_is_error(status)) {
+                fll_error_print(data.error, F_status_set_fine(status), "f_file_name_base", F_true);
+
+                if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+                  status_action = status;
+                  break;
+                }
+
+                action->status = status;
+
+                if (F_status_is_error_not(status_action)) {
+                  status_action = status;
+                }
+              }
+              else {
+                if (fl_string_dynamic_compare(action->parameters.array[1], cache->buffer_path) == F_equal_to_not) {
+
+                  if (data.error.verbosity != f_console_verbosity_quiet) {
+                    status = fl_string_dynamic_terminate_after(&cache->buffer_path);
+
+                    if (F_status_is_error(status)) {
+                      fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+
+                      action->status = status;
+
+                      if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+                        status_action = status;
+                      }
+
+                      break;
+                    }
+
+                    fprintf(data.error.to.stream, "%c", f_string_eol[0]);
+                    fprintf(data.error.to.stream, "%s%sThe entry item action second parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+                    fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, action->parameters.array[1].string, data.error.notable.after->string);
+                    fprintf(data.error.to.stream, "%s' must be a base path name, such as '", data.error.context.before->string);
+                    fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->buffer_path.string, data.error.notable.after->string);
+                    fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+                  }
+
+                  action->status = F_status_set_error(F_parameter);
+
+                  if (F_status_is_error_not(status_action)) {
+                    status_action = action->status;
+                  }
+                }
+              }
+            }
+            else {
               action->status = F_status_set_error(F_parameter);
 
               if (F_status_is_error_not(status_action)) {
@@ -388,6 +447,7 @@ extern "C" {
   void controller_entry_error_print(const fll_error_print_t output, const controller_entry_cache_t cache) {
 
     if (output.verbosity != f_console_verbosity_quiet) {
+      fprintf(output.to.stream, "%c", f_string_eol[0]);
       fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : "");
 
       if (cache.name_action.used) {
@@ -637,7 +697,7 @@ extern "C" {
           if (code & 0x1) {
             if (data.error.verbosity != f_console_verbosity_quiet) {
               fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-              fprintf(data.error.to.stream, "The required entry item '");
+              fprintf(data.error.to.stream, "%s%sThe required entry item '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
               fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_string_main, data.error.notable.after->string);
               fprintf(data.error.to.stream, "%s' was not found.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
             }
index 12edb9cda0850817a7ae0e85bdb08dae09979caa..349eea0834679cd03b7d1dd2cc81fdbfcaedeef8 100644 (file)
@@ -239,6 +239,7 @@ extern "C" {
   void controller_rule_error_print(const fll_error_print_t output, const controller_rule_cache_t cache, const bool item) {
 
     if (output.verbosity != f_console_verbosity_quiet) {
+      fprintf(output.to.stream, "%c", f_string_eol[0]);
       fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : "");
 
       if (cache.name_action.used) {
@@ -447,9 +448,9 @@ extern "C" {
 
     rule->id.used = 0;
     rule->name.used = 0;
-    rule->pid.used = 0;
 
-    rule->defines.used = 0;
+    rule->define.used = 0;
+    rule->parameter.used = 0;
 
     rule->environment.used = 0;
     rule->need.used = 0;
@@ -469,6 +470,7 @@ extern "C" {
 
     cache->buffer_file.used = 0;
     cache->buffer_item.used = 0;
+    cache->buffer_path.used = 0;
 
     cache->content_items.used = 0;
 
@@ -528,6 +530,7 @@ extern "C" {
           cache->object_actions.used = 0;
 
           cache->buffer_item.used = 0;
+          cache->buffer_path.used = 0;
 
           cache->name_action.used = 0;
           cache->name_item.used = 0;
@@ -640,6 +643,7 @@ extern "C" {
     f_string_length_t path_original_length = 0;
     f_string_dynamic_t *setting_value = 0;
     f_string_dynamics_t *setting_values = 0;
+    f_string_maps_t *setting_maps = 0;
 
     f_array_length_t i = 0;
     f_array_length_t j = 0;
@@ -666,29 +670,32 @@ extern "C" {
         continue;
       }
 
-      if (fl_string_dynamic_compare_string(controller_string_define, cache->name_item, controller_string_define_length) == F_equal_to) {
-        type = 1;
+      if (fl_string_dynamic_compare_string(controller_string_control_group, cache->name_item, controller_string_control_group_length) == F_equal_to) {
+        type = controller_rule_setting_type_control_group;
+      }
+      else if (fl_string_dynamic_compare_string(controller_string_define, cache->name_item, controller_string_define_length) == F_equal_to) {
+        type = controller_rule_setting_type_define;
       }
       else if (fl_string_dynamic_compare_string(controller_string_environment, cache->name_item, controller_string_environment_length) == F_equal_to) {
-        type = 2;
+        type = controller_rule_setting_type_environment;
       }
       else if (fl_string_dynamic_compare_string(controller_string_name, cache->name_item, controller_string_name_length) == F_equal_to) {
-        type = 3;
+        type = controller_rule_setting_type_name;
       }
       else if (fl_string_dynamic_compare_string(controller_string_need, cache->name_item, controller_string_need_length) == F_equal_to) {
-        type = 4;
+        type = controller_rule_setting_type_need;
       }
-      else if (fl_string_dynamic_compare_string(controller_string_path, cache->name_item, controller_string_path_length) == F_equal_to) {
-        type = 5;
+      else if (fl_string_dynamic_compare_string(controller_string_parameter, cache->name_item, controller_string_parameter_length) == F_equal_to) {
+        type = controller_rule_setting_type_parameter;
       }
-      else if (fl_string_dynamic_compare_string(controller_string_pid, cache->name_item, controller_string_pid_length) == F_equal_to) {
-        type = 6;
+      else if (fl_string_dynamic_compare_string(controller_string_path, cache->name_item, controller_string_path_length) == F_equal_to) {
+        type = controller_rule_setting_type_path;
       }
       else if (fl_string_dynamic_compare_string(controller_string_want, cache->name_item, controller_string_want_length) == F_equal_to) {
-        type = 7;
+        type = controller_rule_setting_type_want;
       }
       else if (fl_string_dynamic_compare_string(controller_string_wish, cache->name_item, controller_string_wish_length) == F_equal_to) {
-        type = 8;
+        type = controller_rule_setting_type_wish;
       }
       else {
         if (data.warning.verbosity == f_console_verbosity_debug) {
@@ -736,7 +743,8 @@ extern "C" {
         continue;
       }
 
-      if (type == 1) {
+      if (type == controller_rule_setting_type_define || type == controller_rule_setting_type_parameter) {
+
         if (cache->content_actions.array[i].used != 2) {
           fprintf(data.error.to.stream, "%c", f_string_eol[0]);
           fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
@@ -750,10 +758,17 @@ extern "C" {
           continue;
         }
 
-        rule->defines.array[rule->defines.used].name.used = 0;
-        rule->defines.array[rule->defines.used].value.used = 0;
+        if (type == controller_rule_setting_type_define) {
+          setting_maps = &rule->define;
+        }
+        else if (type == controller_rule_setting_type_parameter) {
+          setting_maps = &rule->parameter;
+        }
 
-        status = fl_string_maps_increase(&rule->defines);
+        setting_maps->array[setting_maps->used].name.used = 0;
+        setting_maps->array[setting_maps->used].value.used = 0;
+
+        status = fl_string_maps_increase(setting_maps);
 
         if (F_status_is_error(status)) {
           fll_error_print(data.error, F_status_set_fine(status), "fl_string_maps_increase", F_true);
@@ -770,7 +785,7 @@ extern "C" {
           continue;
         }
 
-        status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &rule->defines.array[rule->defines.used].name);
+        status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &setting_maps->array[setting_maps->used].name);
 
         if (F_status_is_error(status)) {
           fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
@@ -787,7 +802,7 @@ extern "C" {
           continue;
         }
 
-        status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[1], &rule->defines.array[rule->defines.used].value);
+        status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[1], &setting_maps->array[setting_maps->used].value);
 
         if (F_status_is_error(status)) {
           fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
@@ -804,80 +819,64 @@ extern "C" {
           continue;
         }
 
-        rule->defines.used++;
+        setting_maps->used++;
+        continue;
       }
 
-      if (type == 3 || type == 5 || type == 6) {
-        if (type == 3) {
+      if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path) {
+        if (type == controller_rule_setting_type_control_group) {
+          setting_value = &rule->control_group;
+        }
+        else if (type == controller_rule_setting_type_name) {
           setting_value = &rule->name;
         }
-        else if (type == 5) {
+        else if (type == controller_rule_setting_type_path) {
           setting_value = &rule->path;
         }
-        else {
-          setting_value = &rule->pid;
-        }
-
-        if (type == 6) {
-          if (setting_value->used || cache->content_actions.array[i].used != 1) {
-            fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-            fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
 
-            controller_rule_error_print(data.error, *cache, F_false);
+        if (setting_value->used || cache->content_actions.array[i].used != 1) {
+          fprintf(data.error.to.stream, "%c", f_string_eol[0]);
+          fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
 
-            if (F_status_is_error_not(status_return)) {
-              status_return = F_status_set_error(F_invalid);
-            }
+          controller_rule_error_print(data.error, *cache, F_false);
 
-            continue;
+          if (F_status_is_error_not(status_return)) {
+            status_return = F_status_set_error(F_invalid);
           }
-        }
-        else {
-          if (setting_value->used || cache->content_actions.array[i].used > 1) {
-            fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-            fprintf(data.error.to.stream, "%s%sRule setting requires no Content or exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
 
-            controller_rule_error_print(data.error, *cache, F_false);
+          continue;
+        }
 
-            if (F_status_is_error_not(status_return)) {
-              status_return = F_status_set_error(F_invalid);
-            }
+        setting_value->used = 0;
 
-            continue;
-          }
+        if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name) {
+          status = fl_string_dynamic_rip_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value);
 
-          if (!cache->content_actions.array[i].used) {
+          if (F_status_is_error(status)) {
             setting_value->used = 0;
-            continue;
-          }
-        }
 
-        status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value);
+            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_rip_nulless", F_true);
 
-        if (F_status_is_error(status)) {
-          fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
+            if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+              return status;
+            }
 
-          if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
-            return status;
-          }
+            if (F_status_is_error_not(status_return)) {
+              status_return = status;
+            }
 
-          if (F_status_is_error_not(status_return)) {
-            status_return = status;
+            controller_rule_error_print(data.error, *cache, F_false);
+            continue;
           }
 
-          controller_rule_error_print(data.error, *cache, F_false);
-          continue;
-        }
-
-        if (type == 3) {
-          status = controller_validate_has_graph(setting_values->array[setting_values->used]);
+          status = controller_validate_has_graph(*setting_value);
 
           if (status == F_false || F_status_set_fine(status) == F_incomplete_utf) {
             if (status == F_false) {
               fprintf(data.error.to.stream, "%c", f_string_eol[0]);
               fprintf(data.error.to.stream, "%s%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
-              fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used].string, data.error.notable.after->string);
-              fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+              fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_value->string, data.error.notable.after->string);
+              fprintf(data.error.to.stream, "%s', there must be at least 1 graph character.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
 
               controller_rule_error_print(data.error, *cache, F_false);
 
@@ -895,37 +894,17 @@ extern "C" {
               }
             }
 
-            setting_values->array[setting_values->used].used = 0;
+            setting_value->used = 0;
 
             controller_rule_error_print(data.error, *cache, F_false);
             continue;
           }
         }
-        else if (type == 6) {
-          path_original_length = setting_value->used;
-
-          // guarantee that path begins at the root.
-          if (!setting_value->used || setting_value->string[0] != f_path_separator[0]) {
-            path_original_length++;
-          }
-
-          char path_original[path_original_length + 1];
-
-          if (path_original_length == setting_value->used) {
-            memcpy(path_original, setting_value->string, setting_value->used);
-          }
-          else {
-            memcpy(path_original + 1, setting_value->string, setting_value->used - 1);
-            path_original[0] = f_path_separator[0];
-          }
-
-          path_original[path_original_length] = 0;
-
-          // force the path to be canonical (removing all '../' parts).
-          status = fll_path_canonical(path_original, setting_value);
+        else if (type == controller_rule_setting_type_path) {
+          status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value);
 
           if (F_status_is_error(status)) {
-            fll_error_print(data.error, F_status_set_fine(status), "fll_path_canonical", F_true);
+            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
 
             if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
               return status;
@@ -935,6 +914,8 @@ extern "C" {
               status_return = status;
             }
 
+            setting_value->used = 0;
+
             controller_rule_error_print(data.error, *cache, F_false);
             continue;
           }
@@ -943,58 +924,49 @@ extern "C" {
         continue;
       }
 
-      if (type == 2) {
+      if (type == controller_rule_setting_type_environment) {
         setting_values = &rule->environment;
-      }
-      else if (type == 4) {
-        setting_values = &rule->need;
-      }
-      else if (type == 7) {
-        setting_values = &rule->want;
-      }
-      else {
-        setting_values = &rule->wish;
-      }
 
-      for (j = 0; j < cache->content_actions.array[i].used; ++j) {
+        for (j = 0; j < cache->content_actions.array[i].used; ++j) {
 
-        status = fl_string_dynamics_increase(setting_values);
+          status = fl_string_dynamics_increase(setting_values);
 
-        if (F_status_is_error(status)) {
-          fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase", F_true);
+          if (F_status_is_error(status)) {
+            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase", F_true);
 
-          if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
-            return status;
-          }
+            if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+              return status;
+            }
 
-          if (F_status_is_error_not(status_return)) {
-            status_return = status;
+            if (F_status_is_error_not(status_return)) {
+              status_return = status;
+            }
+
+            controller_rule_error_print(data.error, *cache, F_false);
+            continue;
           }
 
-          controller_rule_error_print(data.error, *cache, F_false);
-          continue;
-        }
+          setting_values->array[setting_values->used].used = 0;
 
-        setting_values->array[setting_values->used].used = 0;
+          status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[j], &setting_values->array[setting_values->used]);
 
-        status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[j], &setting_values->array[setting_values->used]);
+          if (F_status_is_error(status)) {
+            setting_values->array[setting_values->used].used = 0;
 
-        if (F_status_is_error(status)) {
-          fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
+            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
 
-          if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
-            return status;
-          }
+            if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+              return status;
+            }
 
-          if (F_status_is_error_not(status_return)) {
-            status_return = status;
-          }
+            if (F_status_is_error_not(status_return)) {
+              status_return = status;
+            }
 
-          controller_rule_error_print(data.error, *cache, F_false);
-          continue;
-        }
+            controller_rule_error_print(data.error, *cache, F_false);
+            continue;
+          }
 
-        if (type == 2) {
           status = controller_validate_environment_name(setting_values->array[setting_values->used]);
 
           if (status == F_false || F_status_set_fine(status) == F_incomplete_utf) {
@@ -1025,10 +997,177 @@ extern "C" {
             controller_rule_error_print(data.error, *cache, F_false);
             continue;
           }
+
+          setting_values->used++;
+        } // for
+
+        continue;
+      }
+
+      if (cache->content_actions.array[i].used != 2) {
+        fprintf(data.error.to.stream, "%c", f_string_eol[0]);
+        fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+
+        controller_rule_error_print(data.error, *cache, F_false);
+
+        if (F_status_is_error_not(status_return)) {
+          status_return = F_status_set_error(F_invalid);
         }
 
-        setting_values->used++;
-      } // for
+        continue;
+      }
+
+      if (type == controller_rule_setting_type_need) {
+        setting_values = &rule->need;
+      }
+      else if (type == controller_rule_setting_type_want) {
+        setting_values = &rule->want;
+      }
+      else if (type == controller_rule_setting_type_wish) {
+        setting_values = &rule->wish;
+      }
+
+      status = fl_string_dynamics_increase_by(2, setting_values);
+
+      if (F_status_is_error(status)) {
+        fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase_by", F_true);
+
+        if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+          return status;
+        }
+
+        if (F_status_is_error_not(status_return)) {
+          status_return = status;
+        }
+
+        controller_rule_error_print(data.error, *cache, F_false);
+        continue;
+      }
+
+      setting_values->array[setting_values->used].used = 0;
+      setting_values->array[setting_values->used + 1].used = 0;
+
+      status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &setting_values->array[setting_values->used]);
+
+      if (F_status_is_error(status)) {
+        setting_values->array[setting_values->used].used = 0;
+
+        fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
+
+        if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+          return status;
+        }
+
+        if (F_status_is_error_not(status_return)) {
+          status_return = status;
+        }
+
+        controller_rule_error_print(data.error, *cache, F_false);
+        continue;
+      }
+
+      status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[1], &setting_values->array[setting_values->used + 1]);
+
+      if (F_status_is_error(status)) {
+        setting_values->array[setting_values->used].used = 0;
+        setting_values->array[setting_values->used + 1].used = 0;
+
+        fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
+
+        if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+          return status;
+        }
+
+        if (F_status_is_error_not(status_return)) {
+          status_return = status;
+        }
+
+        controller_rule_error_print(data.error, *cache, F_false);
+        continue;
+      }
+
+      // force the path to be canonical (removing all '../' parts).
+      status = fll_path_canonical(setting_values->array[setting_values->used].string, &setting_values->array[setting_values->used]);
+
+      if (F_status_is_error(status)) {
+        setting_values->array[setting_values->used].used = 0;
+        setting_values->array[setting_values->used + 1].used = 0;
+
+        fll_error_print(data.error, F_status_set_fine(status), "fll_path_canonical", F_true);
+
+        if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+          status_return = status;
+          break;
+        }
+
+        if (F_status_is_error_not(status_return)) {
+          status_return = status;
+        }
+
+        continue;
+      }
+
+      cache->buffer_path.used = 0;
+
+      status = f_file_name_base(setting_values->array[setting_values->used + 1].string, setting_values->array[setting_values->used + 1].used, &cache->buffer_path);
+
+      if (F_status_is_error(status)) {
+        setting_values->array[setting_values->used].used = 0;
+        setting_values->array[setting_values->used + 1].used = 0;
+
+        fll_error_print(data.error, F_status_set_fine(status), "f_file_name_base", F_true);
+
+        if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+          status_return = status;
+          break;
+        }
+
+        if (F_status_is_error_not(status_return)) {
+          status_return = status;
+        }
+
+        continue;
+      }
+      else {
+        if (fl_string_dynamic_compare(setting_values->array[setting_values->used + 1], cache->buffer_path) == F_equal_to_not) {
+
+          if (data.error.verbosity != f_console_verbosity_quiet) {
+            status = fl_string_dynamic_terminate_after(&cache->buffer_item);
+
+            if (F_status_is_error(status)) {
+              setting_values->array[setting_values->used].used = 0;
+              setting_values->array[setting_values->used + 1].used = 0;
+
+              fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+
+              if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+                return status;
+              }
+
+              if (F_status_is_error_not(status_return)) {
+                status_return = status;
+              }
+
+              controller_rule_error_print(data.error, *cache, F_false);
+              continue;
+            }
+
+            fprintf(data.error.to.stream, "%c", f_string_eol[0]);
+            fprintf(data.error.to.stream, "%s%sThe rule item action second parameter '", data.error.context.before->string, data.error.prefix ? data.error.prefix : "");
+            fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used + 1].string, data.error.notable.after->string);
+            fprintf(data.error.to.stream, "%s' must be a base path name, such as '", data.error.context.before->string);
+            fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->buffer_path.string, data.error.notable.after->string);
+            fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol[0]);
+          }
+
+          setting_values->array[setting_values->used].used = 0;
+          setting_values->array[setting_values->used + 1].used = 0;
+
+          continue;
+        }
+      }
+
+      setting_values->used += 2;
     } // for
 
     return status_return;
index 8e776a53e7c0d0fda6839f832824875691e2565d..8007bb48394c2bf798125944d006c1a7645df037 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 
     f_string_dynamic_t buffer_file;
     f_string_dynamic_t buffer_item;
+    f_string_dynamic_t buffer_path;
 
     f_string_dynamic_t name_action;
     f_string_dynamic_t name_file;
@@ -55,6 +56,7 @@ extern "C" {
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
     }
 
   #define macro_controller_rule_cache_t_delete_simple(cache) \
@@ -284,12 +286,14 @@ extern "C" {
  *    F_invalid (with error bit) on success but there were one or more invalid settings encountered.
  *
  *   Errors (with error bit) from: fl_string_dynamic_partial_append_nulless().
+ *   Errors (with error bit) from: fl_string_dynamic_rip_nulless().
  *   Errors (with error bit) from: fl_string_dynamics_increase().
  *   Errors (with error bit) from: fl_string_maps_increase().
  *   Errors (with error bit) from: fll_fss_extended_read().
  *   Errors (with error bit) from: fll_path_canonical().
  *
  * @see fl_string_dynamic_partial_append_nulless()
+ * @see fl_string_dynamic_rip_nulless()
  * @see fl_string_dynamics_increase()
  * @see fl_string_maps_increase()
  * @see fll_fss_extended_read()
index 8b4a9f5ab3bbaaf79c3ab31f3ba903e33b83bb9b..3dba6bd7721215d31443033e535f855aa574bc8c 100644 (file)
@@ -10,6 +10,7 @@ f_console
 f_conversion
 f_file
 f_fss
+f_iki
 f_path
 f_pipe
 f_print
@@ -17,6 +18,7 @@ fl_color
 fl_console
 fl_conversion
 fl_fss
+fl_iki
 fl_string
 fll_error
 fll_fss
index c63d1fec3e2a4660f1ff40af21b12ca0955616e9..c1defe0682a0a553645d0ebf47c52287fc067df7 100644 (file)
@@ -12,17 +12,23 @@ Rule Documentation:
     "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.
     "environment": A set of environment variables to expose to the processes executed within this rule (PATH is always exposed).
-    "name": A name used to represent this rule, which is printing to the user, screen, logs, etc...
-    "need": A list of relative rule path names that represent any given rule required to be executed (must exist and must succeed) before this rule starts.
+    "name": A name used to represent this rule, which is printed to the user, screen, logs, etc...
+    "need": A single rule required to be executed (must exist and must succeed) before this rule starts.
+    "parameter": A statically defined IKI name and its associated value for use in this rule file.
     "path": A single Content used to set a custom PATH environment variable value.
-    "pid": A path to a directory where the PID file is expected to be stored in.
-    "want": A list of relative rule path names that represent any given rule desired to be executed (may exist and must succeed) before this rule starts.
-    "wish": A list of relative rule path names that represent any given rule desired to be executed (may exist and not required to succeed) before this rule starts.
+    "want": A single rule desired to be executed (may exist and must succeed) before this rule starts.
+    "wish": A single rule desired to be executed (may exist and is not required to succeed) before this rule starts.
 
   In the case of "want" and "wish", if the desired rule is either not found or is otherwise disabled, then this will not fail or otherwise block the wanting or wishing rule.
 
   In the case of "path", when specified, the PATH environment variable is automatically added to the "environment" setting.
 
+  In the case of "parameter", IKI variables are expanded in a pre-process manner and will be removed prior to any execution.
+  Any IKI variables referencing an undefined parameter will be fully removed.
+  These parameters are only exposed in the specific rule file in which they are defined and cannot be shared between rules.
+  A "parameter" variable and an "environment" variable are mutually exclusive but an environment variable, in theory, can have an IKI variable assigned to it inside of a "script".
+  These IKI variables are only substituted within a Rule Item's Content (and not within a Rule Setting nor within a Rule Item's Object).
+
   The "command" outer most part provides a simple command to run under the different circumstances: "start", "stop", "restart", and "reload".
   A "command" always operates in the foreground.
 
@@ -33,6 +39,8 @@ Rule Documentation:
   This "script" operates in the foreground, but individual things done within the script may operate in foreground or background.
   The last return state is treated as an error, so be sure to finish the script with a return code of 0 to designate no error and any other whole number, such a 1, to designate an error.
   Therefore passing "exit 1" would return as an error and passing "exit 0" would return as a success.
+  A "script" is assumed to be in GNU Bash, which is the default expected behavior, but the specification does not explicitly require this.
+  Another scripting language can be used but changing this incurs the responsibility to ensure all rules are updated to the appropriate scripting language.
 
   There are five primary inner Content to perform: "kill", "restart", "reload", "start", and "stop".
 
@@ -44,6 +52,7 @@ Rule Documentation:
 
   When "restart" Content is not provided, then "start" and "stop" is called when the rule is executed using the restart action, if both "start" and "stop" are provided.
   When "reload", "start", or "stop" Content are not provided, then no respective action is performed.
+  Commands are conditionally available depending on the presence of these, such as if "stop" is not provided then "stop" (and "restart") will not be available for the "control" program(s) to use.
 
   The "group" inner Content, an associated "command", "service", or "script" are executed with that group ID or group name.
   The "user" inner Content, an associated "command", "service", or "script" are executed with that user ID or user name.
index 59140185c4161f5fcd813796d31318ddea02c43e..769c70603095c1ccaf90cce6e9d06ad5d9edbf0d 100644 (file)
@@ -1,7 +1,7 @@
 # fss-0002
 
 Rule Specification:
-  The Rule files follow the FSS-000D (Basic Rule) format.
+  The Rule files follow the FSS-000D (Basic Rule) format with IKI-0000 (Unrestricted IKI).
 
   A Rule file name is expected to have the file extension ".rule".
 
@@ -28,15 +28,15 @@ Rule Specification:
   The other Rule Types are processed top-down.
 
   The "settings" Rule Type has the following FSS-0001 (Extended)\:
-    "control_group": Zero or One Content representing a valid control group (cgroup) name.
+    "control_group": One Content representing a valid control group (cgroup) name, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off).
     "define": Two Content, the first Content must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits).
     "environment": Zero or more Content, each must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits).
-    "name": Zero or One Content, must have at least 1 graph character (non-whitespace printing character).
-    "need": Zero or more Content, each being a partial path and the rule file name without extension (such as "boot/modules").
-    "path": Zero or One Content representing a valid PATH environment string (such as "/bin:/sbin:/usr/bin").
-    "pid": One Content representing the full path to a PID file directory (such as "/var/run/service/ssh.pid").
-    "want": Zero or more Content, each being a partial path and the rule file name without extension (such as "boot/modules").
-    "wish": Zero or more Content, each being a partial path and the rule file name without extension (such as "boot/modules").
+    "name": One Content, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off).
+    "need": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").
+    "parameter": Two Content, the first Content must be a case-sensitive valid IKI name and the second being an IKI value.
+    "path": One Content representing a valid PATH environment string (such as "/bin:/sbin:/usr/bin").
+    "want": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").
+    "wish": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").
 
   The "service" Rule Type allows the following the FSS-0001 (Extended)\:
     "create": One Content representing the path to a PID file.
index 63f71903eb409876b34e07913109dd28f902d6ca..4fa6d99aadad1a596bfc4af77d6131ae98193903 100644 (file)
@@ -11,6 +11,11 @@ Featureless Settings Specification: 000D - Basic Rule:
   The FSS Basic and FSS Extended Objects have the same format for Object names but the FSS Extended List Object is slightly different.
   Anything that would match an FSS Extended List Object must therefore be an FSS Extended List Object.
 
+  This supports the use of IKI-0000 (Unrestricted) but only within the Content of the outermost Basic List.
+  Furthermore, should there be a Basic List that defines IKI names and values, then that Basic List must not support IKI substitution.
+  Additional restrictions on the use of IKI syntax is allowed if explicitly defined in the implementing specification.
+  This additional restriction may also include using a more restrictive IKI syntax, such as "IKI-0001 (Basic IKI)".
+
   Anything implementing this specification may impose its own restrictions on when to determine if the Inner Content is what FSS format, based on Object names.
 
   See the appropriate specifications for the Key/Structure/Example documentation for the respective FSS-0000 (Basic), FSS-0001 (Extended), and FSS-0003 (Extended List).
@@ -18,7 +23,7 @@ Featureless Settings Specification: 000D - Basic Rule:
   Example\:
 
     main:
-      name boot-devices
+      name "Boot Devices"
 
     script:
       start {
@@ -40,7 +45,7 @@ Featureless Settings Specification: 000D - Basic Rule:
     3) command
 
   Outer List Contents would be\:
-    1.1) name boot-devices
+    1.1) name "Boot Devices"
 
     2.1) start {
            ip addr add 127.0.0.1/8 label lo dev lo;
@@ -61,8 +66,8 @@ Featureless Settings Specification: 000D - Basic Rule:
     3.1.1) begin
     3.1.2) end
 
-  Inner Content Contents would be\:
-    1.1.1) boot-devices
+  Inner Content Contents would be (without breaking Content into its individual parts)\:
+    1.1.1) Boot Devices
     2.1.1) ip addr add 127.0.0.1/8 label lo dev lo;
            ip link set lo up;
     2.1.2) ip link set lo down;