]> Kevux Git Server - fll/commitdiff
Progress: controller program.
authorKevin Day <thekevinday@gmail.com>
Mon, 23 Nov 2020 03:56:11 +0000 (21:56 -0600)
committerKevin Day <thekevinday@gmail.com>
Mon, 23 Nov 2020 03:56:11 +0000 (21:56 -0600)
Wrap up some of the existing rules code.
Begin writing the entry code.

This seems like a good time to start using and referencing my unit of time called "Time".
Use MegaTime (aka: milliseconds) to handle the time, which will be stored in a 64bit unsigned integer as units of Time.

13 files changed:
level_3/controller/c/controller.c
level_3/controller/c/controller.h
level_3/controller/c/private-control.h
level_3/controller/c/private-controller.c
level_3/controller/c/private-controller.h
level_3/controller/c/private-entry.c
level_3/controller/c/private-entry.h
level_3/controller/c/private-rule.c
level_3/controller/c/private-rule.h
level_3/controller/documents/entry.txt
level_3/controller/documents/rule.txt
level_3/controller/specifications/entry.txt
level_3/controller/specifications/rule.txt

index a469219ed732c7175c6997cb895bb6ce080fcc0a..147127e86ea4fcdde700c687ef5ce01b35cb8e05 100644 (file)
@@ -1,7 +1,8 @@
 #include "controller.h"
-#include "private-controller.h"
+#include "private-control.h"
 #include "private-entry.h"
 #include "private-rule.h"
+#include "private-controller.h"
 
 #ifdef __cplusplus
 extern "C" {
index 0e9b15fb7a3f7c4a6eb7c4c25d2a721768453269..0bcbbb096b447082886be9808bdcf6c7a3c69011 100644 (file)
@@ -64,58 +64,6 @@ extern "C" {
 #endif // _di_controller_name_
 
 #ifndef _di_controller_defines_
-  #define controller_string_create      "create"
-  #define controller_string_command     "command"
-  #define controller_string_consider    "consider"
-  #define controller_string_define      "define"
-  #define controller_string_entry       "entry"
-  #define controller_string_entries     "entries"
-  #define controller_string_environment "environment"
-  #define controller_string_group       "group"
-  #define controller_string_name        "name"
-  #define controller_string_need        "need"
-  #define controller_string_path        "path"
-  #define controller_string_pid         "pid"
-  #define controller_string_restart     "restart"
-  #define controller_string_reload      "reload"
-  #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_use         "use"
-  #define controller_string_user        "user"
-  #define controller_string_want        "want"
-  #define controller_string_wish        "wish"
-
-  #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_entry_length       5
-  #define controller_string_entries_length     7
-  #define controller_string_environment_length 11
-  #define controller_string_group_length       5
-  #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_restart_length     7
-  #define controller_string_reload_length      6
-  #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_use_length         3
-  #define controller_string_user_length        4
-  #define controller_string_want_length        4
-  #define controller_string_wish_length        4
-
   #define controller_path_settings "/etc/controller"
 
   #define controller_path_settings_length 15
@@ -163,242 +111,6 @@ extern "C" {
   #define controller_total_parameters 12
 #endif // _di_controller_defines_
 
-#ifndef _di_controller_rule_action_t_
-  enum {
-    controller_rule_action_type_extended = 1,
-    controller_rule_action_type_extended_list,
-  };
-
-  enum {
-    controller_rule_action_intent_create = 1,
-    controller_rule_action_intent_group,
-    controller_rule_action_intent_restart,
-    controller_rule_action_intent_reload,
-    controller_rule_action_intent_start,
-    controller_rule_action_intent_stop,
-    controller_rule_action_intent_use,
-    controller_rule_action_intent_user,
-  };
-
-  typedef struct {
-    f_string_length_t line;
-    f_string_dynamics_t parameters;
-  } controller_rule_action_t;
-
-  #define controller_rule_action_t_initialize \
-    { \
-      0, \
-      f_string_dynamics_t_initialize, \
-    }
-
-  #define f_macro_controller_rule_action_t_delete_simple(action) \
-    f_macro_string_dynamics_t_delete_simple(action.parameters)
-#endif // _di_controller_rule_action_t_
-
-#ifndef _di_controller_rule_actions_t_
-  typedef struct {
-    uint8_t type;
-    uint8_t intent;
-
-    controller_rule_action_t *array;
-
-    f_array_length_t size;
-    f_array_length_t used;
-  } controller_rule_actions_t;
-
-  #define controller_rule_actions_t_initialize \
-    { \
-      0, \
-      0, \
-      0, \
-      0, \
-      0, \
-    }
-
-  #define f_macro_controller_rule_actions_t_delete_simple(actions) \
-    actions.used = actions.size; \
-    while (actions.used > 0) { \
-      actions.used--; \
-      f_macro_controller_rule_item_t_delete_simple(actions.array[actions.used]); \
-      if (!actions.used) { \
-        if (f_memory_delete((void **) & actions.array, sizeof(controller_rule_action_t), actions.size)) { \
-          actions.size = 0; \
-        } \
-      } \
-    }
-#endif // _di_controller_rule_actions_t_
-
-#ifndef _di_controller_rule_item_t_
-  enum {
-    controller_rule_item_type_command = 1,
-    controller_rule_item_type_script,
-    controller_rule_item_type_service,
-    controller_rule_item_type_settings,
-  };
-
-  typedef struct {
-    uint8_t type;
-    f_string_length_t line;
-
-    controller_rule_actions_t create;
-    controller_rule_actions_t group;
-    controller_rule_actions_t restart;
-    controller_rule_actions_t reload;
-    controller_rule_actions_t start;
-    controller_rule_actions_t stop;
-    controller_rule_actions_t use;
-    controller_rule_actions_t user;
-  } controller_rule_item_t;
-
-  #define controller_rule_item_t_initialize \
-    { \
-      0, \
-      0, \
-      controller_rule_actions_t_initialize, \
-      controller_rule_actions_t_initialize, \
-      controller_rule_actions_t_initialize, \
-      controller_rule_actions_t_initialize, \
-      controller_rule_actions_t_initialize, \
-      controller_rule_actions_t_initialize, \
-      controller_rule_actions_t_initialize, \
-      controller_rule_actions_t_initialize, \
-    }
-
-  #define f_macro_controller_rule_item_t_delete_simple(item) \
-    f_macro_controller_rule_actions_t_delete_simple(item.create) \
-    f_macro_controller_rule_actions_t_delete_simple(item.group) \
-    f_macro_controller_rule_actions_t_delete_simple(item.restart) \
-    f_macro_controller_rule_actions_t_delete_simple(item.reload) \
-    f_macro_controller_rule_actions_t_delete_simple(item.start) \
-    f_macro_controller_rule_actions_t_delete_simple(item.stop) \
-    f_macro_controller_rule_actions_t_delete_simple(item.use) \
-    f_macro_controller_rule_actions_t_delete_simple(item.user)
-#endif // _di_controller_rule_item_t_
-
-#ifndef _di_controller_rule_items_t_
-  typedef struct {
-    controller_rule_item_t *array;
-
-    f_array_length_t size;
-    f_array_length_t used;
-  } controller_rule_items_t;
-
-  #define controller_rule_items_initialize \
-    { \
-      0, \
-      0, \
-      0, \
-    }
-
-  #define f_macro_controller_rule_items_t_delete_simple(items) \
-    items.used = items.size; \
-    while (items.used > 0) { \
-      items.used--; \
-      f_macro_controller_rule_item_t_delete_simple(items.array[items.used]); \
-      if (!items.used) { \
-        if (f_memory_delete((void **) & items.array, sizeof(controller_rule_item_t), items.size)) { \
-          items.size = 0; \
-        } \
-      } \
-    }
-#endif // _di_controller_rule_items_t_
-
-#ifndef _di_controller_rule_t_
-  typedef struct {
-    f_status_t status;
-
-    f_string_dynamic_t id;
-    f_string_dynamic_t name;
-    f_string_dynamic_t path;
-    f_string_dynamic_t pid;
-
-    f_string_maps_t defines;
-
-    f_string_dynamics_t environment;
-    f_string_dynamics_t need;
-    f_string_dynamics_t want;
-    f_string_dynamics_t wish;
-
-    controller_rule_items_t items;
-  } controller_rule_t;
-
-  #define controller_rule_t_initialize \
-    { \
-      F_unknown, \
-      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_dynamics_t_initialize, \
-      f_string_dynamics_t_initialize, \
-      f_string_dynamics_t_initialize, \
-      f_string_dynamics_t_initialize, \
-      controller_rule_items_initialize, \
-    }
-
-  #define f_macro_controller_rule_t_delete_simple(setting) \
-    f_string_dynamic_t_delete_simple(setting.id) \
-    f_string_dynamic_t_delete_simple(setting.name) \
-    f_string_dynamic_t_delete_simple(setting.path) \
-    f_string_dynamic_t_delete_simple(setting.pid) \
-    f_string_maps_t_delete_simple(setting.defines) \
-    f_string_dynamics_t_delete_simple(setting.environments) \
-    f_string_dynamics_t_delete_simple(setting.need) \
-    f_string_dynamics_t_delete_simple(setting.want) \
-    f_string_dynamics_t_delete_simple(setting.wish) \
-    f_macro_controller_rule_item_t_delete_simple(setting.items)
-#endif // _di_controller_rule_t_
-
-#ifndef _di_controller_rules_t_
-  typedef struct {
-    controller_rule_t *array;
-
-    f_array_length_t size;
-    f_array_length_t used;
-  } controller_rules_t;
-
-  #define controller_rules_initialize \
-    { \
-      0, \
-      0, \
-      0, \
-    }
-
-  #define f_macro_controller_rules_t_delete_simple(rules) \
-    rules.used = rules.size; \
-    while (rules.used > 0) { \
-      rules.used--; \
-      f_macro_controller_rule_t_delete_simple(rules.array[rules.used]); \
-      if (!rules.used) { \
-        if (f_memory_delete((void **) & rules.array, sizeof(controller_rule_t), rules.size)) { \
-          rules.size = 0; \
-        } \
-      } \
-    }
-#endif // _di_controller_rules_t_
-
-#ifndef _di_controller_setting_t
-  typedef struct {
-    bool interruptable;
-
-    f_string_dynamic_t path_setting;
-
-    controller_rules_t rules;
-  } controller_setting_t;
-
-  #define controller_setting_t_initialize \
-    { \
-      F_false, \
-      f_string_dynamic_t_initialize, \
-      controller_rules_t_initialize, \
-    }
-
-  #define f_macro_controller_setting_t_delete_simple(setting) \
-    f_macro_string_dynamic_t_delete_simple(setting.path_setting) \
-    f_macro_string_dynamic_t_delete_simple(setting.rules)
-#endif // _di_controller_setting_t
-
 #ifndef _di_controller_data_t_
   typedef struct {
     f_console_parameter_t parameters[controller_total_parameters];
index 3bcc4e2f307ea6436e5baa89157722323cac2443..0326baac565f2fc062d5bb8011093694fd6bc761 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _PRIVATE_control_h
 #define _PRIVATE_control_h
 
+#include "private-controller.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
index 9a980358305a52626acc15a20def57f098bc3fe8..cc67912e03dd427fe748fe4ccf7bde6df5701bfd 100644 (file)
@@ -1,12 +1,60 @@
 #include "controller.h"
-#include "private-controller.h"
+#include "private-control.h"
 #include "private-entry.h"
 #include "private-rule.h"
+#include "private-controller.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#ifndef _di_controller_validate_define_name_
+  f_return_status controller_validate_environment_name(const f_string_static_t name) {
+
+    if (!name.used) return F_none;
+
+    f_status_t status = F_none;
+
+    if (name.string[0] != '_') {
+      status = f_utf_is_alpha(name.string, name.used);
+
+      if (F_status_is_error(status)) return status;
+      if (status == F_false) return F_false;
+    }
+
+    for (f_string_length_t i = f_macro_utf_byte_width(name.string[0]); i < name.used; i += f_macro_utf_byte_width(name.string[i])) {
+
+      if (name.string[i] == '_') continue;
+
+      status = f_utf_is_alpha_digit(name.string, name.used);
+
+      if (F_status_is_error(status)) return status;
+      if (status == F_false) return F_false;
+    } // for
+
+    return F_true;
+  }
+#endif // _di_controller_validate_define_name_
+
+#ifndef _di_controller_validate_has_graph_
+  f_return_status controller_validate_has_graph(const f_string_static_t name) {
+
+    if (!name.used) return F_none;
+
+    f_status_t status = F_none;
+
+    for (f_string_length_t i = 0; i < name.used; i += f_macro_utf_byte_width(name.string[i])) {
+
+      status = f_utf_is_graph(name.string, name.used);
+
+      if (F_status_is_error(status)) return status;
+      if (status == F_true) return F_true;
+    } // for
+
+    return F_false;
+  }
+#endif // _di_controller_validate_has_graph_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index c69c3a49cc5499494ebea8f3b410620a8c299d3c..245a56eaf3cfd2616d2de70fa731aeecf3728d14 100644 (file)
 extern "C" {
 #endif
 
+#ifndef _di_controller_string_
+  #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_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_restart     "restart"
+  #define controller_string_reload      "reload"
+  #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_want        "want"
+  #define controller_string_wish        "wish"
+
+  #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_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_restart_length     7
+  #define controller_string_reload_length      6
+  #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_want_length        4
+  #define controller_string_wish_length        4
+#endif // _di_controller_string_
+
+#ifndef _di_controller_rule_action_t_
+  enum {
+    controller_rule_action_type_extended = 1,
+    controller_rule_action_type_extended_list,
+  };
+
+  enum {
+    controller_rule_action_intent_create = 1,
+    controller_rule_action_intent_group,
+    controller_rule_action_intent_restart,
+    controller_rule_action_intent_reload,
+    controller_rule_action_intent_start,
+    controller_rule_action_intent_stop,
+    controller_rule_action_intent_use,
+    controller_rule_action_intent_user,
+  };
+
+  typedef struct {
+    f_string_length_t line;
+    f_string_dynamics_t parameters;
+  } controller_rule_action_t;
+
+  #define controller_rule_action_t_initialize \
+    { \
+      0, \
+      f_string_dynamics_t_initialize, \
+    }
+
+  #define macro_controller_rule_action_t_delete_simple(action) \
+    f_macro_string_dynamics_t_delete_simple(action.parameters)
+#endif // _di_controller_rule_action_t_
+
+#ifndef _di_controller_rule_actions_t_
+  typedef struct {
+    uint8_t type;
+    uint8_t intent;
+
+    controller_rule_action_t *array;
+
+    f_array_length_t size;
+    f_array_length_t used;
+  } controller_rule_actions_t;
+
+  #define controller_rule_actions_t_initialize \
+    { \
+      0, \
+      0, \
+      0, \
+      0, \
+      0, \
+    }
+
+  #define macro_controller_rule_actions_t_delete_simple(actions) \
+    actions.used = actions.size; \
+    while (actions.used > 0) { \
+      actions.used--; \
+      macro_controller_rule_item_t_delete_simple(actions.array[actions.used]); \
+      if (!actions.used) { \
+        if (f_memory_delete((void **) & actions.array, sizeof(controller_rule_action_t), actions.size)) { \
+          actions.size = 0; \
+        } \
+      } \
+    }
+#endif // _di_controller_rule_actions_t_
+
+#ifndef _di_controller_rule_item_t_
+  enum {
+    controller_rule_item_type_command = 1,
+    controller_rule_item_type_script,
+    controller_rule_item_type_service,
+    controller_rule_item_type_settings,
+  };
+
+  typedef struct {
+    uint8_t type;
+    f_string_length_t line;
+
+    controller_rule_actions_t create;
+    controller_rule_actions_t group;
+    controller_rule_actions_t restart;
+    controller_rule_actions_t reload;
+    controller_rule_actions_t start;
+    controller_rule_actions_t stop;
+    controller_rule_actions_t use;
+    controller_rule_actions_t user;
+  } controller_rule_item_t;
+
+  #define controller_rule_item_t_initialize \
+    { \
+      0, \
+      0, \
+      controller_rule_actions_t_initialize, \
+      controller_rule_actions_t_initialize, \
+      controller_rule_actions_t_initialize, \
+      controller_rule_actions_t_initialize, \
+      controller_rule_actions_t_initialize, \
+      controller_rule_actions_t_initialize, \
+      controller_rule_actions_t_initialize, \
+      controller_rule_actions_t_initialize, \
+    }
+
+  #define macro_controller_rule_item_t_delete_simple(item) \
+    macro_controller_rule_actions_t_delete_simple(item.create) \
+    macro_controller_rule_actions_t_delete_simple(item.group) \
+    macro_controller_rule_actions_t_delete_simple(item.restart) \
+    macro_controller_rule_actions_t_delete_simple(item.reload) \
+    macro_controller_rule_actions_t_delete_simple(item.start) \
+    macro_controller_rule_actions_t_delete_simple(item.stop) \
+    macro_controller_rule_actions_t_delete_simple(item.use) \
+    macro_controller_rule_actions_t_delete_simple(item.user)
+#endif // _di_controller_rule_item_t_
+
+#ifndef _di_controller_rule_items_t_
+  typedef struct {
+    controller_rule_item_t *array;
+
+    f_array_length_t size;
+    f_array_length_t used;
+  } controller_rule_items_t;
+
+  #define controller_rule_items_initialize \
+    { \
+      0, \
+      0, \
+      0, \
+    }
+
+  #define macro_controller_rule_items_t_delete_simple(items) \
+    items.used = items.size; \
+    while (items.used > 0) { \
+      items.used--; \
+      macro_controller_rule_item_t_delete_simple(items.array[items.used]); \
+      if (!items.used) { \
+        if (f_memory_delete((void **) & items.array, sizeof(controller_rule_item_t), items.size)) { \
+          items.size = 0; \
+        } \
+      } \
+    }
+#endif // _di_controller_rule_items_t_
+
+#ifndef _di_controller_rule_t_
+  typedef struct {
+    f_status_t status;
+
+    f_string_dynamic_t id;
+    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_dynamics_t environment;
+    f_string_dynamics_t need;
+    f_string_dynamics_t want;
+    f_string_dynamics_t wish;
+
+    controller_rule_items_t items;
+  } controller_rule_t;
+
+  #define controller_rule_t_initialize \
+    { \
+      F_unknown, \
+      f_string_dynamic_t_initialize, \
+      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_dynamics_t_initialize, \
+      f_string_dynamics_t_initialize, \
+      f_string_dynamics_t_initialize, \
+      f_string_dynamics_t_initialize, \
+      controller_rule_items_initialize, \
+    }
+
+  #define macro_controller_rule_t_delete_simple(setting) \
+    f_string_dynamic_t_delete_simple(setting.id) \
+    f_string_dynamic_t_delete_simple(setting.name) \
+    f_string_dynamic_t_delete_simple(setting.control_group) \
+    f_string_dynamic_t_delete_simple(setting.path) \
+    f_string_dynamic_t_delete_simple(setting.pid) \
+    f_string_maps_t_delete_simple(setting.defines) \
+    f_string_dynamics_t_delete_simple(setting.environments) \
+    f_string_dynamics_t_delete_simple(setting.need) \
+    f_string_dynamics_t_delete_simple(setting.want) \
+    f_string_dynamics_t_delete_simple(setting.wish) \
+    macro_controller_rule_item_t_delete_simple(setting.items)
+#endif // _di_controller_rule_t_
+
+#ifndef _di_controller_rules_t_
+  typedef struct {
+    controller_rule_t *array;
+
+    f_array_length_t size;
+    f_array_length_t used;
+  } controller_rules_t;
+
+  #define controller_rules_t_initialize \
+    { \
+      0, \
+      0, \
+      0, \
+    }
+
+  #define macro_controller_rules_t_delete_simple(rules) \
+    rules.used = rules.size; \
+    while (rules.used > 0) { \
+      rules.used--; \
+      macro_controller_rule_t_delete_simple(rules.array[rules.used]); \
+      if (!rules.used) { \
+        if (f_memory_delete((void **) & rules.array, sizeof(controller_rule_t), rules.size)) { \
+          rules.size = 0; \
+        } \
+      } \
+    }
+#endif // _di_controller_rules_t_
+
+#ifndef _di_controller_entry_item_t_
+  enum {
+    controller_entry_item_type_consider = 1,
+    controller_entry_item_type_failsafe,
+    controller_entry_item_type_group,
+    controller_entry_item_type_rule,
+    controller_entry_item_type_timeout,
+  };
+
+  #define controller_entry_rule_code_asynchronous 0x1
+  #define controller_entry_rule_code_require      0x2
+  #define controller_entry_rule_code_wait         0x4
+
+  #define controller_entry_timeout_code_kill  0x1
+  #define controller_entry_timeout_code_start 0x2
+  #define controller_entry_timeout_code_stop  0x4
+
+  typedef struct {
+    uint8_t type;
+    uint8_t code;
+
+    f_string_length_t line;
+    f_number_unsigned_t timeout;
+
+    f_string_dynamic_t id;
+  } controller_entry_item_t;
+
+  #define controller_entry_item_t_initialize \
+    { \
+      0, \
+      0, \
+      0, \
+      0, \
+      f_string_dynamic_t_initialize, \
+    }
+
+  #define macro_controller_entry_item_t_delete_simple(item) \
+    f_macro_string_dynamics_t_delete_simple(item.id)
+#endif // _di_controller_entry_item_t_
+
+#ifndef _di_controller_entry_items_t_
+  typedef struct {
+    controller_entry_item_t *array;
+
+    f_array_length_t size;
+    f_array_length_t used;
+  } controller_entry_items_t;
+
+  #define controller_entry_items_t_initialize \
+    { \
+      0, \
+      0, \
+      0, \
+    }
+
+  #define macro_controller_entry_items_t_delete_simple(items) \
+    items.used = items.size; \
+    while (items.used > 0) { \
+      items.used--; \
+      macro_controller_rule_t_delete_simple(items.array[items.used]); \
+      if (!items.used) { \
+        if (f_memory_delete((void **) & items.array, sizeof(controller_entry_item_t), items.size)) { \
+          items.size = 0; \
+        } \
+      } \
+    }
+#endif // _di_controller_entry_items_t_
+
+#ifndef _di_controller_entry_list_t_
+  typedef struct {
+    f_string_length_t line;
+    f_string_dynamic_t name;
+    controller_entry_items_t items;
+  } controller_entry_list_t;
+
+  #define controller_entry_list_t_initialize \
+    { \
+      0, \
+      f_string_dynamic_t_initialize, \
+      controller_entry_items_t_initialize, \
+    }
+
+  #define macro_controller_entry_list_t_delete_simple(list) \
+    f_macro_string_dynamic_t_delete_simple(list.name) \
+    macro_controller_entry_items_t_delete_simple(list.items)
+#endif // _di_controller_entry_list_t_
+
+#ifndef _di_controller_entry_lists_t_
+  typedef struct {
+    controller_entry_list_t *array;
+
+    f_array_length_t size;
+    f_array_length_t used;
+  } controller_entry_lists_t;
+
+  #define controller_entry_lists_t_initialize \
+    { \
+      0, \
+      0, \
+      0, \
+    }
+
+  #define macro_controller_entry_lists_t_delete_simple(lists) \
+    lists.used = lists.size; \
+    while (lists.used > 0) { \
+      lists.used--; \
+      macro_controller_rule_t_delete_simple(lists.array[lists.used]); \
+      if (!lists.used) { \
+        if (f_memory_delete((void **) & lists.array, sizeof(controller_entry_list_t), lists.size)) { \
+          lists.size = 0; \
+        } \
+      } \
+    }
+#endif // _di_controller_entry_lists_t_
+
+#ifndef _di_controller_setting_t
+  typedef struct {
+    bool interruptable;
+
+    f_string_dynamic_t path_setting;
+
+    controller_entry_lists_t entry_lists;
+    controller_rules_t rules;
+  } controller_setting_t;
+
+  #define controller_setting_t_initialize \
+    { \
+      F_false, \
+      f_string_dynamic_t_initialize, \
+      controller_rules_t_initialize, \
+    }
+
+  #define macro_controller_setting_t_delete_simple(setting) \
+    f_macro_string_dynamic_t_delete_simple(setting.path_setting) \
+    macro_controller_entry_lists_t_delete_simple(entry_lists) \
+    f_macro_string_dynamic_t_delete_simple(setting.rules)
+#endif // _di_controller_setting_t
+
+/**
+ * Validate that the given string is a valid environment variable name.
+ *
+ * A valid environment variable name must begin with an alpha-character or an underscore.
+ * Every character after that may be alphanumeric or underscore.
+ * All other characters, including Unicode characters, are invalid.
+ *
+ * @param name
+ *   The string to validate.
+ *
+ * @return
+ *   F_true on valid.
+ *   F_false on invalid.
+ *   F_none if there is no string to validate (used = 0).
+ *
+ *   Errors (with error bit) from: f_utf_is_alpha().
+ *   Errors (with error bit) from: f_utf_is_alpha_digit().
+ *
+ * @see f_utf_is_alpha()
+ * @see f_utf_is_alpha_digit()
+ */
+#ifndef _di_controller_validate_define_name_
+  extern f_return_status controller_validate_environment_name(const f_string_static_t name) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_validate_define_name_
+
+/**
+ * Validate that the given string has at least one graph character.
+ *
+ * @param name
+ *   The string to validate.
+ *
+ * @return
+ *   F_true on valid.
+ *   F_false on invalid.
+ *   F_none if there is no string to validate (used = 0).
+ *
+ *   Errors (with error bit) from: f_utf_is_graph().
+ *
+ * @see f_utf_is_graph()
+ */
+#ifndef _di_controller_validate_has_graph_
+  extern f_return_status controller_validate_has_graph(const f_string_static_t name) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_validate_has_graph_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 96460e0ffdeef7742cc5d61f2da2e5eeda010bcc..b93169c8e219fd3598b9e0e48c43f107920e1801 100644 (file)
@@ -5,6 +5,114 @@
 extern "C" {
 #endif
 
+#ifndef _di_controller_entry_lists_increase_by_
+  f_return_status controller_entry_lists_increase_by(const f_array_length_t amount, controller_entry_lists_t *lists) {
+    f_status_t status = F_none;
+    f_string_length_t size = lists->size + amount;
+
+    if (size > f_array_length_t_size) {
+      if (lists->size == f_array_length_t_size) {
+        return F_status_set_error(F_array_too_large);
+      }
+
+      size = lists->size;
+      status = F_array_too_large;
+    }
+
+    const f_status_t status_resize = f_memory_resize((void **) & lists->array, sizeof(controller_entry_lists_t), lists->size, size);
+    if (F_status_is_error(status_resize)) return status_resize;
+
+    lists->size = size;
+    return status;
+  }
+#endif // _di_controller_entry_lists_increase_by_
+
+#ifndef _di_controller_entry_list_read_
+  f_return_status controller_entry_list_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t entry_name, controller_entry_cache_t *cache, controller_entry_lists_t *lists) {
+    f_status_t status = F_none;
+
+    {
+      f_file_t file = f_file_t_initialize;
+
+      const f_string_length_t file_path_length = setting.path_setting.used + f_path_separator_length + controller_string_rules_length + f_path_separator_length + entry_name.used + f_path_separator_length;
+      char file_path[file_path_length + 1];
+
+      memcpy(file_path, setting.path_setting.string, setting.path_setting.used);
+      memcpy(file_path + setting.path_setting.used + f_path_separator_length, controller_string_rules, controller_string_rules_length);
+      memcpy(file_path + setting.path_setting.used + f_path_separator_length + controller_string_rules_length + f_path_separator_length, entry_name.string, entry_name.used);
+
+      file_path[setting.path_setting.used] = f_path_separator[0];
+      file_path[setting.path_setting.used + f_path_separator_length + controller_string_rules_length] = f_path_separator[0];
+      file_path[file_path_length - 1] = f_path_separator[0];
+      file_path[file_path_length] = 0;
+
+      status = f_file_stream_open(file_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, entry_name.string, "open", fll_error_file_type_file);
+      }
+      else {
+        status = f_file_stream_read(file, 1, &cache->buffer_entry);
+
+        if (F_status_is_error(status)) {
+          fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_read", F_true, entry_name.string, "read", fll_error_file_type_file);
+        }
+      }
+
+      f_file_stream_close(F_true, &file);
+
+      if (F_status_is_error(status)) return status;
+    }
+
+    if (cache->buffer_entry.used) {
+      f_string_range_t range = f_macro_string_range_t_initialize(cache->buffer_entry.used);
+
+      status = fll_fss_basic_list_read(cache->buffer_entry, &range, &cache->objects_list, &cache->contents_list, &cache->delimits, 0, &cache->comments);
+
+      if (F_status_is_error(status)) {
+        fll_error_print(data.error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true);
+      }
+      else {
+        status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_entry);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(data.error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
+        }
+      }
+
+      cache->delimits.used = 0;
+      cache->comments.used = 0;
+    }
+    else {
+      // @todo: error out that there is no list, because a valid entry is required.
+      return F_status_set_error(F_data_not);
+    }
+
+    if (F_status_is_error_not(status) && cache->objects_items.used) {
+      status = controller_entry_lists_increase_by(cache->objects_list.used, lists);
+
+      if (F_status_is_error(status)) {
+        fll_error_print(data.error, F_status_set_fine(status), "controller_entry_lists_increase_by", F_true);
+      }
+      else {
+        for (f_array_length_t i = 0; i < cache->objects_list.used; ++i) {
+          // @todo
+          // @todo reserve index 0 for "main", checking each list if a "main" exists then assigning it to index 0).
+          // @todo be sure to provide an error if "main" does not exist at all, this is a critical failure.
+        } // for
+      }
+    }
+
+    if (F_status_is_error(status)) {
+      //@todo someting like: controller_rule_error_print(data.error, *cache, for_item);
+
+      return status;
+    }
+
+    return F_none;
+  }
+#endif // _di_controller_entry_list_read_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 7e9eb6e4738c9be5739b616fefaf9683882c1b80..10d79933b9418c1cd8eb5de5ce0a0ce5a93002fa 100644 (file)
 #ifndef _PRIVATE_entry_h
 #define _PRIVATE_entry_h
 
+#include "private-controller.h"
+
+#ifndef _di_controller_entry_cache_t_
+  typedef struct {
+    f_string_length_t line_item;
+    f_string_length_t line_list;
+
+    f_string_range_t range_item;
+    f_string_range_t range_list;
+
+    f_fss_comments_t comments;
+    f_fss_delimits_t delimits;
+
+    f_fss_content_t content_item;
+    f_fss_contents_t contents_items;
+    f_fss_contents_t contents_list;
+    f_fss_objects_t objects_items;
+    f_fss_objects_t objects_list;
+
+    f_string_dynamic_t buffer_entry;
+
+    f_string_static_t name_entry;
+    f_string_dynamic_t name_item;
+    f_string_dynamic_t name_list;
+  } controller_entry_cache_t;
+
+  #define controller_entry_cache_t_initialize \
+    { \
+      0, \
+      0, \
+      f_string_range_t_initialize, \
+      f_string_range_t_initialize, \
+      f_fss_comments_t_initialize, \
+      f_fss_delimits_t_initialize, \
+      f_fss_content_t_initialize, \
+      f_fss_contents_t_initialize, \
+      f_fss_contents_t_initialize, \
+      f_fss_objects_t_initialize, \
+      f_fss_objects_t_initialize, \
+      f_string_dynamic_t_initialize, \
+      f_string_static_t_initialize, \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
+    }
+
+  #define macro_controller_entry_cache_t_delete_simple(cache) \
+    f_macro_fss_comments_t_delete_simple(cache.comments) \
+    f_macro_fss_delimits_t_delete_simple(cache.delimits) \
+    f_macro_fss_content_t_delete_simple(cache.content_action) \
+    f_macro_fss_contents_t_delete_simple(cache.contents_action) \
+    f_macro_fss_contents_t_delete_simple(cache.contents_items) \
+    f_macro_fss_objects_t_delete_simple(cache.objects_action) \
+    f_macro_fss_objects_t_delete_simple(cache.objects_items) \
+    f_macro_string_dynamic_t_delete_simple(cache.buffer_entry) \
+    f_macro_string_dynamic_t_delete_simple(cache.name_item) \
+    f_macro_string_dynamic_t_delete_simple(cache.name_list)
+#endif // _di_controller_entry_cache_t_
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/**
+ * Increase the size of the entry lists array by the specified amount, but only if necessary.
+ *
+ * This only increases size if the current used plus amount is greater than the currently allocated size.
+ *
+ * @param amount
+ *   A positive number representing how much to increase the size by.
+ * @param lists
+ *   The entry lists to resize.
+ *
+ * @return
+ *   F_none on success.
+ *   F_array_too_large on success, but requested size is too small (resize is smaller than requested length).
+ *
+ *   Errors (with error bit) from: f_memory_resize().
+ *
+ * @see f_memory_resize()
+ */
+#ifndef _di_controller_entry_lists_increase_by_
+  extern f_return_status controller_entry_lists_increase_by(const f_array_length_t amount, controller_entry_lists_t *lists) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_entry_lists_increase_by_
+
+/**
+ * Read the entry file, extracting all valid entry lists.
+ *
+ * @param data
+ *   The program data.
+ * @param setting
+ *   The controller settings data.
+ * @param entry_name
+ *   The string identifying the entry.
+ *   This is constructed from the path parts to the file without the file extension and without the settings directory prefix.
+ *   "/etc/controller/entries/my.entry" would have a entry name of "my".
+ * @param cache
+ *   A structure for containing and caching relevant data.
+ * @param lists
+ *   The processed list.
+ *
+ * @return
+ *   F_none on success.
+ *   @todo determine how the error management will be done for both entry and rule (ideally the "controller" should avoid failing if possible given that it is the defacto "init" program).
+ */
+#ifndef _di_controller_entry_list_read_
+  extern f_return_status controller_entry_list_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t entry_name, controller_entry_cache_t *cache, controller_entry_lists_t *lists) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_entry_list_read_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index ad3d45aa511eb7e8f794ba71f2dd279dfc24ecbc..e54c85ed1455ed37ad0401ba80a93100737c383d 100644 (file)
@@ -81,7 +81,7 @@ extern "C" {
 
     // "script" types use the entire content and can be directly passed through.
     if (item->type == controller_rule_item_type_script) {
-      status = controller_rule_actions_increase_by(1, actions);
+      status = controller_rule_actions_increase_by(f_memory_default_allocation_step, actions);
 
       if (F_status_is_error(status)) {
         fll_error_print(data.error, F_status_set_fine(status), "controller_rule_actions_increase_by", F_true);
@@ -185,7 +185,7 @@ extern "C" {
           fll_error_print(data.error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
         }
         else {
-          status = controller_rule_actions_increase_by(1, actions);
+          status = controller_rule_actions_increase_by(f_memory_default_allocation_step, actions);
 
           if (F_status_is_error(status)) {
             fll_error_print(data.error, F_status_set_fine(status), "controller_rule_actions_increase_by", F_true);
@@ -438,7 +438,7 @@ extern "C" {
 #endif // _di_controller_rule_items_increase_by_
 
 #ifndef _di_controller_rule_read_
-  f_return_status controller_rule_read(const controller_data_t data, const f_string_static_t rule_id, controller_rule_cache_t *cache, controller_rule_t *rule) {
+  f_return_status controller_rule_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id, controller_rule_cache_t *cache, controller_rule_t *rule) {
     f_status_t status = F_none;
 
     bool for_item = F_true;
@@ -473,10 +473,17 @@ extern "C" {
     else {
       f_file_t file = f_file_t_initialize;
 
-      const f_string_length_t file_path_length = rule->id.used;
+      const f_string_length_t file_path_length = setting.path_setting.used + f_path_separator_length + controller_string_rules_length + f_path_separator_length + rule->id.used + f_path_separator_length;
       char file_path[file_path_length + 1];
 
-      memcpy(file_path, rule->id.string, rule->id.used);
+      memcpy(file_path, setting.path_setting.string, setting.path_setting.used);
+      memcpy(file_path + setting.path_setting.used + f_path_separator_length, controller_string_rules, controller_string_rules_length);
+      memcpy(file_path + setting.path_setting.used + f_path_separator_length + controller_string_rules_length + f_path_separator_length, rule->id.string, rule->id.used);
+
+      file_path[setting.path_setting.used] = f_path_separator[0];
+      file_path[setting.path_setting.used + f_path_separator_length + controller_string_rules_length] = f_path_separator[0];
+      file_path[file_path_length - 1] = f_path_separator[0];
+      file_path[file_path_length] = 0;
 
       status = f_file_stream_open(file_path, 0, &file);
 
@@ -604,7 +611,13 @@ extern "C" {
           else {
             for_item = F_false;
 
-            controller_rule_setting_read(data, cache, rule);
+            status = controller_rule_setting_read(data, cache, rule);
+
+            if (F_status_is_error(status)) {
+              if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+                break;
+              }
+            }
           }
         } // for
       }
@@ -640,8 +653,9 @@ extern "C" {
 #endif // _di_controller_rule_read_
 
 #ifndef _di_controller_rule_setting_read_
-  void controller_rule_setting_read(const controller_data_t data, controller_rule_cache_t *cache, controller_rule_t *rule) {
+  f_return_status controller_rule_setting_read(const controller_data_t data, controller_rule_cache_t *cache, controller_rule_t *rule) {
     f_status_t status = F_none;
+    f_status_t status_return = F_none;
 
     f_string_range_t range = f_macro_string_range_t_initialize(cache->buffer_item.used);
     f_string_range_t range2 = f_string_range_t_initialize;
@@ -654,7 +668,7 @@ extern "C" {
       fll_error_print(data.error, F_status_set_fine(status), "fll_fss_extended_read", F_true);
       controller_rule_error_print(data.error, *cache, F_false);
 
-      return;
+      return status;
     }
 
     f_string_length_t path_original_length = 0;
@@ -673,6 +687,15 @@ 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);
+
+        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;
       }
@@ -734,6 +757,16 @@ 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);
         controller_rule_error_print(data.error, *cache, F_false);
+
+        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;
       }
 
@@ -743,6 +776,11 @@ extern "C" {
           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);
+          }
+
           continue;
         }
 
@@ -753,6 +791,15 @@ extern "C" {
 
         if (F_status_is_error(status)) {
           fll_error_print(data.error, F_status_set_fine(status), "fl_string_maps_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_is_error_not(status_return)) {
+            status_return = status;
+          }
+
           controller_rule_error_print(data.error, *cache, F_false);
           continue;
         }
@@ -761,6 +808,15 @@ 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);
+
+          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;
         }
@@ -769,6 +825,15 @@ 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);
+
+          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;
         }
@@ -793,6 +858,11 @@ extern "C" {
             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 (F_status_is_error_not(status_return)) {
+              status_return = F_status_set_error(F_invalid);
+            }
+
             continue;
           }
         }
@@ -802,6 +872,11 @@ extern "C" {
             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);
+
+            if (F_status_is_error_not(status_return)) {
+              status_return = F_status_set_error(F_invalid);
+            }
+
             continue;
           }
 
@@ -815,12 +890,50 @@ 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);
+
+          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;
         }
 
         if (type == 3) {
-          // @todo validate must have at least 1 non-whitespace printing character.
+          status = controller_validate_has_graph(setting_values->array[setting_values->used]);
+
+          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]);
+
+              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);
+              }
+            }
+            else {
+
+              // this function should only return F_incomplete_utf on error.
+              fll_error_print(data.error, F_incomplete_utf, "controller_validate_has_graph", F_true);
+
+              if (F_status_is_error_not(status_return)) {
+                status_return = status;
+              }
+            }
+
+            setting_values->array[setting_values->used].used = 0;
+
+            controller_rule_error_print(data.error, *cache, F_false);
+            continue;
+          }
         }
         else if (type == 6) {
           path_original_length = setting_value->used;
@@ -847,6 +960,15 @@ extern "C" {
 
           if (F_status_is_error(status)) {
             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) {
+              return status;
+            }
+
+            if (F_status_is_error_not(status_return)) {
+              status_return = status;
+            }
+
             controller_rule_error_print(data.error, *cache, F_false);
             continue;
           }
@@ -874,6 +996,15 @@ extern "C" {
 
         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_is_error_not(status_return)) {
+            status_return = status;
+          }
+
           controller_rule_error_print(data.error, *cache, F_false);
           continue;
         }
@@ -884,17 +1015,57 @@ 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);
+
+          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;
         }
 
         if (type == 2) {
-          // @todo validate that this is a valid environment variable name: case-sensitive alpha-numeric or underscore, but no leading digits.
+          status = controller_validate_environment_name(setting_values->array[setting_values->used]);
+
+          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 environment variable 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]);
+
+              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);
+              }
+            }
+            else {
+
+              // this function should only return F_incomplete_utf on error.
+              fll_error_print(data.error, F_incomplete_utf, "controller_validate_environment_name", F_true);
+
+              if (F_status_is_error_not(status_return)) {
+                status_return = status;
+              }
+            }
+
+            setting_values->array[setting_values->used].used = 0;
+
+            controller_rule_error_print(data.error, *cache, F_false);
+            continue;
+          }
         }
 
         setting_values->used++;
       } // for
     } // for
+
+    return status_return;
   }
 #endif // _di_controller_rule_setting_read_
 
index b7ac4b355f85c479fe1b7a140f79a29d43fbf0e5..203d73b5af65fd305248a95f1920e2c401a951b8 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _PRIVATE_rule_h
 #define _PRIVATE_rule_h
 
+#include "private-controller.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -41,8 +43,8 @@ extern "C" {
     { \
       0, \
       0, \
-      0, \
-      0, \
+      f_string_range_t_initialize, \
+      f_string_range_t_initialize, \
       f_fss_comments_t_initialize, \
       f_fss_delimits_t_initialize, \
       f_fss_content_t_initialize, \
@@ -57,7 +59,7 @@ extern "C" {
       f_string_dynamic_t_initialize, \
     }
 
-  #define f_macro_controller_rule_name_t_delete_simple(cache) \
+  #define macro_controller_rule_name_t_delete_simple(cache) \
     f_macro_fss_comments_t_delete_simple(cache.comments) \
     f_macro_fss_delimits_t_delete_simple(cache.delimits) \
     f_macro_fss_content_t_delete_simple(cache.content_action) \
@@ -226,14 +228,16 @@ extern "C" {
 #endif // _di_controller_rule_items_increase_by_
 
 /**
- * Read the content within the buffer, extracting all valid items.
+ * Read the rule file, extracting all valid items.
  *
  * @param data
  *   The program data.
+ * @param setting
+ *   The controller settings data.
  * @param rule_id
  *   The string identifying the rule.
  *   This is constructed from the path parts to the file without the file extension and without the settings directory prefix.
- *   "/etc/controller/setting/rules/boot/my.rule" would have a rule id of "boot/my".
+ *   "/etc/controller/rules/boot/my.rule" would have a rule id of "boot/my".
  * @param cache
  *   A structure for containing and caching relevant data.
  * @param rule
@@ -256,7 +260,7 @@ extern "C" {
  * @see fll_fss_basic_list_read().
  */
 #ifndef _di_controller_rule_read_
-  extern f_return_status controller_rule_read(const controller_data_t data, const f_string_static_t rule_id, controller_rule_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_return_status controller_rule_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id, controller_rule_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_read_
 
 /**
@@ -264,7 +268,8 @@ extern "C" {
  *
  * This will perform additional FSS read functions as appropriate.
  *
- * Errors from this are not considered fatal, therefore errors may be printed but nothing is returned.
+ * Errors from this are not considered fatal, but the first error code encountered is returned.
+ * Memory failure errors are always immediately returned.
  *
  * @param data
  *   The program data.
@@ -273,10 +278,24 @@ extern "C" {
  * @param rule
  *   The processed rule.
  *
- * @todo consider making memory failures still critical errors, in which case a status does need to be returned.
+ * @return
+ *    F_none on success.
+ *    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_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_dynamics_increase()
+ * @see fl_string_maps_increase()
+ * @see fll_fss_extended_read()
+ * @see fll_path_canonical()
  */
 #ifndef _di_controller_rule_setting_read_
-  extern void controller_rule_setting_read(const controller_data_t data, controller_rule_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_return_status controller_rule_setting_read(const controller_data_t data, controller_rule_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_setting_read_
 
 #ifdef __cplusplus
index e521648dbd2cb05fed9a7d0a54dadaad40b18cd1..8a75037c5c487031cda27d20c90f4092db40a2ad 100644 (file)
@@ -10,32 +10,32 @@ Entry Documentation:
   All other Basic List Objects are not executed unless either a "category" or a "failsafe" specifies the Object.
   Execution of all Basic List Objects is top-down.
 
-  Inside each list there are additional commands: "category", "failsafe", "rule", and "timeout".
-
-  The "category" command accepts only a valid Basic List Object in which will be immediately executed.
-
-  The "failsafe" command accepts only a valid Basic List Object in which will be executed when a failure is detected.
-  Only a single "failsafe" command may exist at a time so when specified multiple times.
-  Each time a "failsafe" command is specified, it replaces the previous "failsafe" command.
-
-  The "only" command represents a list of directory names that are allowed to be "controlled" by the "control" program from user-space.
-  To allow all rules in all directories, do not specify the "omit" command.
-  To disallow all rules in all directories, specify this command and provide no directoies.
-  Each directory is relative to the settings, such that if the controller rule settings are found in "/etc/controller/rules/", then for a directory called "[directory]" would have a resulting path of: "/etc/controller/rules/[directory]/".
+  Inside each list there are additional commands: "consider", "failsafe", "group", "rule", and "timeout".
 
   The "consider" command is a special case of a "rule" command.
   All available Content are identical.
   The difference is that this rule is only processed at this spot at this time if and when some "rule" command (or a "consider" command is determined to be executed) designates that this consideration is required (via "require"), wanted (via "want"), or wished (via "wish").
   If this is determined to be executed, then this is immediately executed in the designated position and applies all properties as appropriate (such as "asynchronous", for example).
 
+  The "failsafe" command accepts only a valid Basic List Object in which will be executed when a failure is detected.
+  Only a single "failsafe" command may exist at a time.
+  Each time a "failsafe" command is specified, it replaces the previous "failsafe" command.
+
+  The "group" command accepts only a valid Basic List Object in which will be immediately executed.
+  A "group" is another list within the entry file to execute in it entirety.
+  Any valid Object name, except for the reserved "main", may be called using this.
+
   The "rule" command immediately executes a given rule file.
-  The first Content represents the directory in which the rule is to be found (do not include leading or trailing slashes in the name).
+  The first Content represents the rule ID, which is a relative path the rule file is to be found, without the file extension.
+    - Do not include leading or trailing slashes in the name.
+    - This is relative to the settings rules directory.
+    - For example the rule ID "example/my" would be found in "/etc/controller/settings/rules/example/my.rule" (assuming the directory structure).
   The second Content represents the basename for the file representing the desired rule.
   The directory is relative to the settings, such that if the controller rule settings are found in "/etc/controller/rules/", then for a directory called "[directory]" and a rule basename of "[filename]", the resulting path would be: "/etc/controller/rules/[directory]/[filename].rule"
   The remaining Content may be specified in any order\:
-  - "asynchronous": Designates that execution will not block (wait).
-  - "require": Designates that this rule must succeed or trigger execution of failsafe.
-  - "wait": Designates that this rule will not execute until all other existing "asynchronous" executions complete.
+    - "asynchronous": Designates that execution will not block (wait).
+    - "require": Designates that this rule must succeed or trigger execution of failsafe.
+    - "wait": Designates that this rule will not execute until all other existing "asynchronous" executions complete.
 
   It is important to note that for any given rule, execution within that rule may be internally asynchronous.
   For example, a service that is often called a daemon will execute in the background.
@@ -45,9 +45,23 @@ Entry Documentation:
   The "timeout" command 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 of these will replace any previously specified setting.
-  Each of these accepts a single Content that is a 0 or greater whole number representing the number of milliseconds.
-  For "start", this represents the number of milliseconds 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 milliseconds 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 milliseconds to wait after stopping some rule and that rule has not yet stopped to forcefully stop the rule (aka kill the rule).
+  Each of these accepts a single Content 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).
+
+  This utilizes the unit of measurement called a "Time", represented with uppercase "T".
+  For comparison, a unit of Time is equivalent to a nanosecond, or 10^-9 seconds.
+  A MegaTime (MT) is therefore equivalent to a millisecond such that a millisecond is 10^-3 seconds.
+  A unit of Time is intended to represent some unit of Time such that a single 64-bit integer may hold all units of Time for a single calendar year.
+  This unit of Time does not and must not include Years (unlike Unixtime).
+  To convert from Time to Unixtime, one must have a year (which could be assumed to be the current year) and then calculate all of those calendar oddities.
+  A unit of Time by default is assumed to be in UTC.
+  1 (Earth) year ~= 31536000000000000 Time or 31536000 GT (GigaTime).
+  1 (Earth) day = 86400000000000 Time or 86400 GT (GigaTime).
+  1 (Earth) hour = 3600000000000 Time or 3600 GT (GigaTime).
+  1 (Earth) minute = 60000000000 Time or 60 GT (GigaTime).
+  1 (Earth) second = 1000000000 Time or 1 GT (GigaTime).
+  Consequentially, 1 day in units of Time is easily represented as 86.4 TT (TeraTime).
index 13a1c9281ec520f837c6ecf1a5bf47b41cc5c259..b31500f0b61b2130de646e569874c7044f148659 100644 (file)
@@ -8,7 +8,8 @@ Rule Documentation:
   The rule file is read top-down, except for the outer most list "settings", which is intended to store settings data for this rule.
   Multiple outer most list Objects may be specified and they are executed as provided, in a top-down manner.
 
-  The "settings" outer most list Object has the following FSS-0001 (Extended) Content:
+  The "settings" outer most list Object has the following FSS-0001 (Extended) Content\:
+    "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...
index bcac7916084d19dc385359cc3a81cc83a29f4833..e060a82099a2ed0371c054cf453735609423c978 100644 (file)
@@ -11,17 +11,15 @@ Entry Specification:
     The entry file may have any other valid Object, only the above have reserved uses.
 
     Inside each Basic List are essentially the following, FSS-0001 (Extended), Objects\:
-      "category": One Content that is a valid Object name, except for the reserved "main".
-      "controlled": One Content that is a valid Object name, except for the reserved "main".
-      "failsafe": One Content that is a valid relative rule file name without the ".rule" extension.
-      "only": Zero or more Content.
       "consider": One or more Content.
-        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The first Content that is the relative file path (without any leading/trailing slashes and without file extension).
         The second Content that is the basename for a rule file.
         The third and beyond may only be one of\:
           - asynchronous
           - require
           - wait
+      "failsafe": One Content that is a valid Object name, except for the reserved "main".
+      "group": One Content that is a valid Object name, except for the reserved "main".
       "rule": One or more Content.
         The first Content that is the relative directory path (without any leading/trailing slashes).
         The second Content that is the basename for a rule file.
index 471ce61d36cf0c54ad9cc4b818ce80bcb7571cb9..7ac263b3d8807f5c17cf482c71a3273c992b1201 100644 (file)
@@ -13,10 +13,11 @@ Rule Specification:
 
   For the above Basic List Objects, "main" may be specified only once whereas the others may be specifed multiple times.
 
-  The "settings" outer most list Object has the following FSS-0001 (Extended) Content:
+  The "settings" outer most list Object has the following FSS-0001 (Extended) Content\:
+    "control_group": Zero or One Content representing a valid control group (cgroup) name.
     "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 non-whitespace printing character.
+    "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").