]> Kevux Git Server - fll/commitdiff
Progress: controller.
authorKevin Day <thekevinday@gmail.com>
Tue, 17 Nov 2020 04:44:17 +0000 (22:44 -0600)
committerKevin Day <thekevinday@gmail.com>
Tue, 17 Nov 2020 04:44:17 +0000 (22:44 -0600)
level_3/controller/c/controller.c
level_3/controller/c/controller.h
level_3/controller/c/private-rule.c
level_3/controller/c/private-rule.h
level_3/controller/documents/rule.txt
level_3/controller/specifications/rule.txt

index 3e0fb2f4dd975b6a0302e9ec33cba0a155c7c262..f4c3a104b017e04ebce6e1a3be90a46e2987f27b 100644 (file)
@@ -44,6 +44,9 @@ extern "C" {
         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;
+
         if (F_status_is_error(status)) {
           if (data->error.verbosity != f_console_verbosity_quiet) {
             fll_error_print(data->error, F_status_set_fine(status), "fll_program_parameter_process", F_true);
@@ -70,15 +73,19 @@ extern "C" {
 
         if (choice == controller_parameter_verbosity_quiet) {
           data->error.verbosity = f_console_verbosity_quiet;
+          data->warning.verbosity = f_console_verbosity_quiet;
         }
         else if (choice == controller_parameter_verbosity_normal) {
           data->error.verbosity = f_console_verbosity_normal;
+          data->warning.verbosity = f_console_verbosity_normal;
         }
         else if (choice == controller_parameter_verbosity_verbose) {
           data->error.verbosity = f_console_verbosity_verbose;
+          data->warning.verbosity = f_console_verbosity_verbose;
         }
         else if (choice == controller_parameter_verbosity_debug) {
           data->error.verbosity = f_console_verbosity_debug;
+          data->warning.verbosity = f_console_verbosity_debug;
         }
       }
 
index 8ecf7e82cfd3b74c77fda7347dd56c49348c054e..a45a7c8065815474c3bb7f143e7d3b6785686000 100644 (file)
@@ -60,7 +60,6 @@ extern "C" {
   #define controller_string_group       "group"
   #define controller_string_name        "name"
   #define controller_string_pid         "pid"
-  #define controller_string_program     "program"
   #define controller_string_restart     "restart"
   #define controller_string_reload      "reload"
   #define controller_string_script      "script"
@@ -68,6 +67,7 @@ extern "C" {
   #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_create_length      6
@@ -77,7 +77,6 @@ extern "C" {
   #define controller_string_group_length       5
   #define controller_string_name_length        4
   #define controller_string_pid_length         3
-  #define controller_string_program_length     7
   #define controller_string_restart_length     7
   #define controller_string_reload_length      6
   #define controller_string_script_length      6
@@ -85,6 +84,7 @@ extern "C" {
   #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
 
   enum {
@@ -124,6 +124,7 @@ extern "C" {
 
     f_file_t output;
     fll_error_print_t error;
+    fll_error_print_t warning;
 
     f_color_context_t context;
   } controller_data_t;
@@ -135,57 +136,126 @@ extern "C" {
       F_false, \
       f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
       fll_error_print_t_initialize, \
+      fll_macro_error_print_t_initialize_warning(f_console_verbosity_debug) \
       f_color_context_t_initialize, \
     }
 #endif // _di_controller_data_t_
 
-#ifndef _di_controller_rule_item_t_
+#ifndef _di_controller_rule_action_t_
   enum {
-    controller_rule_item_type_single = 1,
-    controller_rule_item_type_multiple,
+    controller_rule_action_type_basic = 1,
+    controller_rule_action_type_extended,
+    controller_rule_action_type_extended_list,
   };
 
   enum {
-    controller_rule_item_intent_create = 1,
-    controller_rule_item_intent_program,
-    controller_rule_item_intent_group,
-    controller_rule_item_intent_restart,
-    controller_rule_item_intent_reload,
-    controller_rule_item_intent_start,
-    controller_rule_item_intent_stop,
-    controller_rule_item_intent_user,
+    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,
   };
 
-  // @fixme rule_item needs to contain a list of actions which is essentially what rule_item is currently acting as.
+  typedef struct {
+    f_string_length_t line;
+    f_string_dynamic_t content;
+  } controller_rule_action_t;
+
+  #define controller_rule_action_t_initialize \
+    { \
+      0, \
+      f_string_dynamic_t_initialize, \
+    }
+
+  #define f_macro_controller_rule_action_t_delete_simple(action) \
+    f_macro_string_dynamic_t_delete_simple(action.content)
+#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;
 
-    f_string_dynamic_t name;
-    f_string_dynamic_t content;
+    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, \
-      0, \
-      f_string_dynamic_t_initialize, \
-      f_string_dynamic_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, \
+      controller_rule_actions_t_initialize, \
     }
 
-  #define f_macro_controller_rule_item_t_delete_simple(rule_item) \
-    f_macro_string_dynamic_t_delete_simple(rule_item.name) \
-    f_macro_string_dynamic_t_delete_simple(rule_item.content)
+  #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 {
-    f_string_length_t line;
-    f_string_dynamic_t name;
-
     controller_rule_item_t *array;
 
     f_array_length_t size;
@@ -195,8 +265,6 @@ extern "C" {
   #define controller_rule_items_initialize \
     { \
       0, \
-      f_string_dynamic_t_initialize, \
-      0, \
       0, \
       0, \
     }
@@ -207,14 +275,37 @@ extern "C" {
       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(f_string_dynamic_t), items.size)) { \
+        if (f_memory_delete((void **) & items.array, sizeof(controller_rule_item_t), items.size)) { \
           items.size = 0; \
         } \
       } \
-    } \
-    f_macro_string_dynamic_t_delete_simple(items.name);
+    }
 #endif // _di_controller_rule_items_t_
 
+#ifndef _di_controller_rule_setting_t_
+  typedef struct {
+    f_string_dynamic_t name;
+    f_string_dynamic_t pid;
+
+    f_string_dynamics_t defines; // @todo this probably should a list of name and value pairs.
+    f_string_dynamics_t environment;
+  } controller_rule_setting_t;
+
+  #define controller_rule_setting_t_initialize \
+    { \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamics_t_initialize, \
+      f_string_dynamics_t_initialize, \
+    }
+
+  #define f_macro_controller_rule_setting_t_delete_simple(setting) \
+    f_string_dynamic_t_delete_simple(setting.name) \
+    f_string_dynamic_t_delete_simple(setting.pid) \
+    f_string_dynamics_t_delete_simple(setting.defines) \
+    f_string_dynamics_t_delete_simple(setting.environments)
+#endif // _di_controller_rule_setting_t_
+
 /**
  * Print help.
  *
index b738dd49c4fb9cde8d35f2d384a7d65848ba6551..828d2f231c2eb4ee7f333e369960d38f5b6195fe 100644 (file)
@@ -5,6 +5,281 @@
 extern "C" {
 #endif
 
+#ifndef _di_controller_rule_actions_read_
+  f_return_status controller_rule_actions_read(const controller_data_t data, const bool multiple, f_string_static_t *buffer, controller_rule_cache_t *cache, controller_rule_item_t *item, controller_rule_actions_t *actions) {
+    f_status_t status = F_none;
+
+    f_fss_objects_t objects = f_fss_objects_t_initialize;
+    f_fss_contents_t contents = f_fss_contents_t_initialize;
+
+    f_string_range_t range = cache->range_action;
+
+    if (multiple) {
+      // @todo
+      //fll_fss_extended_list_read();
+    }
+    else {
+      status = f_fss_seek_to_eol(*buffer, range);
+
+      if (F_status_is_error(status)) {
+        fll_error_print(data.error, F_status_set_fine(status), "f_fss_seek_to_eol", F_true);
+        controller_rule_error_print(data.error, *cache);
+      }
+
+      range.stop = range.start;
+      range.start = cache->range_action.start;
+
+      // @fixme I just noticed an inconsistency in the naming, should it be quoted_objects and delimit_objects or instead objects_quoted, and objects_delimit?
+      // @fixme also, I think that the buffer in the fll_fss read functions no longer need to be pointers (it should be possible to make them constants now).
+      status = fll_fss_extended_read(buffer, &range, &objects, &contents, &quoted_objects, &quoted_contents, &delimit_objects, &delimit_contents);
+      // @todo
+    }
+
+    if (!content.used) {
+      if (data.warning.verbosity == f_console_verbosity_debug) {
+        fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
+
+        if (actions) {
+          fprintf(data.warning.to.stream, "%s%sUnknown action, nothing to do.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
+        }
+        else {
+          fprintf(data.warning.to.stream, "%s%sAction is empty, nothing to do.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
+        }
+
+        controller_rule_error_print(data.error, *cache);
+      }
+
+      return F_data_not;
+    }
+
+    action->type = type;
+    action->line = line;
+    action->content.used = 0;
+
+    // @todo now that the type and intent are known, the content may be loaded.
+    // @todo a "script" type uses basic and a "service" type uses extended because the script is passed to bash whereas the service is directly called.
+    // @todo additional line-by-line processing needs to be performed for multi-line services OR services should not support multiple lines.
+        /*
+        comments.used = 0;
+        status = fl_fss_extended_list_content_read(content, &range, &child_content, &delimits, &comments);
+
+        if (F_status_is_error(status)) {
+          fll_error_file_print(data->error, F_status_set_fine(status), "fl_fss_extended_list_content_read", F_true, file_name.string, "process", fll_error_file_type_file);
+          controller_rule_error_print(data.error, *cache);
+          break;
+        }
+
+        if (status == FL_fss_found_content) {
+          type = controller_rule_item_type_multiple;
+        }
+        */
+          /*
+          status = fl_fss_basic_content_read(content, &range, &child_content, &delimits);
+
+          if (F_status_is_error(status)) {
+            fll_error_file_print(data->error, F_status_set_fine(status), "fl_fss_basic_content_read", F_true, file_name.string, "process", fll_error_file_type_file);
+            controller_rule_error_print(data.error, *cache);
+            break;
+          }
+
+          if (status == FL_fss_found_content) {
+            type = controller_rule_action_type_basic;
+          }*/
+
+    return status;
+  }
+#endif // _di_controller_rule_actions_read_
+
+#ifndef _di_controller_rule_error_print_
+  void controller_rule_error_print(const fll_error_print_t output, const controller_rule_cache_t cache) {
+
+    if (output.verbosity != f_console_verbosity_quiet) {
+      fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : "");
+
+      if (cache.name_action) {
+        fprintf(output.to.stream, "action '");
+        fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, cache.name_action.string, output.notable.after->string);
+        fprintf(output.to.stream, "%s' on line ", output.context.before->string);
+        fprintf(output.to.stream, "%s%s%llu%s", output.context.after->string, output.notable.before->string, cache.line_action, output.notable.after->string);
+        fprintf(output.to.stream, "%s for ", output.context.before->string);
+      }
+
+      if (cache.name_item) {
+        fprintf(output.to.stream, "item '");
+        fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, cache.name_item.string, output.notable.after->string);
+        fprintf(output.to.stream, "%s' on line ", output.context.before->string);
+        fprintf(output.to.stream, "%s%s%llu%s", output.context.after->string, output.notable.before->string, cache.line_item, output.notable.after->string);
+        fprintf(output.to.stream, "%s for ", output.context.before->string);
+      }
+
+      fprintf(output.to.stream, "file '");
+      fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, cache.name_file.string, output.notable.after->string);
+      fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol[0]);
+    }
+  }
+#endif // _di_controller_rule_error_print_
+
+#ifndef _di_controller_rule_item_read_
+  f_return_status controller_rule_item_read(const controller_data_t data, f_string_static_t *buffer, controller_rule_cache_t *cache, controller_rule_item_t *item) {
+    f_status_t status = F_none;
+
+    f_string_range_t range = f_macro_string_range_t_initialize(buffer->used);
+
+    f_fss_delimits_t delimits = f_fss_delimits_t_initialize;
+    f_fss_comments_t comments = f_fss_comments_t_initialize;
+    f_fss_quote_t quote = f_fss_quote_t_initialize;
+
+    controller_rule_actions_t *actions = 0;
+
+    bool multiple = f_false;
+
+    for (range.start = 0; range.start < buffer->used && range.start <= range.stop; delimits.used = 0, comments.used = 0) {
+
+      status = fl_fss_extended_list_object_read(buffer, &range, &cache->range_action, &delimits);
+
+      if (F_status_is_error(status)) {
+        fll_error_print(data->error, F_status_set_fine(status), "fl_fss_extended_list_object_read", F_true);
+        break;
+      }
+
+      if (range.start >= range.stop || range.start >= buffer->used) {
+        if (status == FL_fss_found_object || status == FL_fss_found_object_content_not) {
+          if (error.verbosity != f_console_verbosity_quiet) {
+            fprintf(data.error.to.stream, "%c", f_string_eol[0]);
+            fprintf(data.error.to.stream, "%s%sUnterminated FSS Extended List at end of rule file.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+          }
+
+          status = F_status_set_error(FL_fss_found_object_content_not);
+        }
+
+        break;
+      }
+
+      if (status == FL_fss_found_object) {
+        multiple = F_true;
+      }
+      else {
+        multiple = f_false;
+
+        // The current line is not an Extended List object, so the next possibility is a Basic List (and Extended List, both use the same Object structure).
+        status = fl_fss_basic_object_read(buffer, &range, &cache->range_action, &quote, &delimits);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(data->error, F_status_set_fine(status), "fl_fss_basic_object_read", F_true);
+          break;
+        }
+      }
+
+      if (status == FL_fss_found_object_content_not || range.start >= range.stop || range.start >= buffer->used) {
+        // object ended without any content.
+        break;
+      }
+
+      if (status == FL_fss_found_object) {
+        status = fl_fss_apply_delimit(delimits, &data_make->buffer);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
+          break;
+        }
+
+        status = f_fss_count_lines(buffer, cache->range_action.start, &cache->line_action);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true);
+          break;
+        }
+
+        cache->line_action += item->line;
+
+        action_name->used = 0;
+        status = fl_string_dynamic_rip_nulless(buffer, cache->range_action, action_name);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_rip_nulless", F_true);
+          break;
+        }
+
+        status = fl_string_dynamic_terminate_after(action_name);
+
+        if (F_status_is_error(status)) {
+          fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+          break;
+        }
+
+        actions = 0;
+
+        if (fl_string_dynamic_compare_string(controller_string_create, *action_name, controller_string_create_length) == f_equal_to) {
+          actions = &item->create;
+          actions->intent = controller_rule_action_intent_create;
+        }
+        else if (fl_string_dynamic_compare_string(controller_string_group, *action_name, controller_string_group_length) == f_equal_to) {
+          actions = &item->group;
+          actions->intent = controller_rule_action_intent_group;
+        }
+        else if (fl_string_dynamic_compare_string(controller_string_restart, *action_name, controller_string_restart_length) == f_equal_to) {
+          actions = &item->restart;
+          actions->intent = controller_rule_action_intent_restart;
+        }
+        else if (fl_string_dynamic_compare_string(controller_string_reload, *action_name, controller_string_reload_length) == f_equal_to) {
+          actions = &item->reload;
+          actions->intent = controller_rule_action_intent_reload;
+        }
+        else if (fl_string_dynamic_compare_string(controller_string_start, *action_name, controller_string_start_length) == f_equal_to) {
+          actions = &item->start;
+          actions->intent = controller_rule_action_intent_start;
+        }
+        else if (fl_string_dynamic_compare_string(controller_string_stop, *action_name, controller_string_stop_length) == f_equal_to) {
+          actions = &item->stop;
+          actions->intent = controller_rule_action_intent_stop;
+        }
+        else if (fl_string_dynamic_compare_string(controller_string_use, *action_name, controller_string_use_length) == f_equal_to) {
+          actions = &item->use;
+          actions->intent = controller_rule_action_intent_use;
+        }
+        else if (fl_string_dynamic_compare_string(controller_string_user, *action_name, controller_string_user_length) == f_equal_to) {
+          actions = &item->user;
+          actions->intent = controller_rule_action_intent_user;
+        }
+        else {
+          if (data.warning.verbosity == f_console_verbosity_debug) {
+            fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
+            fprintf(data.warning.to.stream, "%s%sUnknown action type.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
+
+            controller_rule_error_print(data.warning, *cache);
+          }
+
+          continue;
+        }
+
+        if (multiple) {
+          if (actions->intent == controller_rule_action_intent_create || actions->intent == controller_rule_action_intent_group || actions->intent == controller_rule_action_intent_use || actions->intent == controller_rule_action_intent_user) {
+            if (error.verbosity != f_console_verbosity_quiet) {
+              fprintf(data.error.to.stream, "%c", f_string_eol[0]);
+              fprintf(data.error.to.stream, "%s%sFSS Extended List is not allowed for this item action type.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : "", data.error.context.after->string, f_string_eol[0]);
+            }
+
+            status = F_status_set_error(F_unsupported);
+            break;
+          }
+        }
+
+        status = controller_rule_actions_read(data, multiple, buffer, cache, item, actions);
+        if (F_status_is_error(status)) break;
+      }
+    } // for
+
+    f_macro_fss_delimits_t_delete_simple(delimits);
+    f_macro_fss_comments_t_delete_simple(comments);
+
+    if (F_status_is_error(status)) {
+      controller_rule_error_print(data.error, *cache);
+    }
+
+    return status;
+  }
+#endif // _di_controller_rule_item_read_
+
 #ifndef _di_controller_rule_items_increase_by_
   f_return_status controller_rule_items_increase_by(const f_array_length_t amount, controller_rule_items_t *items) {
     f_status_t status = F_none;
@@ -28,7 +303,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 file_name, controller_rule_items_t *items) {
+  f_return_status controller_rule_read(const controller_data_t data, controller_rule_cache_t *cache, controller_rule_items_t *items) {
     f_status_t status = F_none;
     f_string_dynamic_t buffer = f_string_dynamic_t_initialize;
 
@@ -40,13 +315,13 @@ extern "C" {
       status = f_file_stream_open(arguments.argv[data->remaining.array[i]], 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, file_name.string, "open", fll_error_file_type_file);
+        fll_error_file_print(data->error, F_status_set_fine(status), "f_file_stream_open", F_true, cache->name_file.string, "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, file_name.string, "read", fll_error_file_type_file);
+          fll_error_file_print(data->error, F_status_set_fine(status), "f_file_stream_read", F_true, cache->name_file.string, "read", fll_error_file_type_file);
         }
       }
 
@@ -94,21 +369,33 @@ extern "C" {
 
         for (f_array_length_t i = 0; i < objects.used; ++i) {
 
-          status = f_fss_count_lines(buffer, objects.array[i], &items->array[items->used].line);
+          cache->name_file.used = 0;
+          cache->name_item.used = 0;
+          cache->name_action.used = 0;
+
+          cache->line_item = 0;
+          cache->line_action = 0;
+
+          cache->range_item = objects.array[i];
+          cache->range_action = 0;
+
+          status = f_fss_count_lines(buffer, cache->range_item.start, &cache->line_item);
 
           if (F_status_is_error(status)) {
             fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true);
             break;
           }
 
-          status = fl_string_dynamic_partial_append_nulless(buffer, objects.array[i], items->array[items->used].name);
+          items->array[items->used].line = cache->line_item;
+
+          status = fl_string_dynamic_rip_nulless(buffer, cache->range_item, &cache->name_item);
 
           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_rip_nulless", F_true);
             break;
           }
 
-          status = fl_string_dynamic_terminate_after(items->array[items->used].name);
+          status = fl_string_dynamic_terminate_after(&cache->name_item);
 
           if (F_status_is_error(status)) {
             fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
@@ -123,162 +410,51 @@ extern "C" {
             break;
           }
 
-          status = controller_rule_read_content(data, file_name, items->array[items->used].line, &content, items);
-          if (F_status_is_error(status)) break;
-
-          items->used++;
-        } // for
-
-        f_macro_fss_content_t_delete_simple(content);
-      }
-    }
-
-    f_macro_fss_objects_t_delete_simple(objects);
-    f_macro_fss_contents_t_delete_simple(contents);
-    f_macro_string_dynamic_t_delete_simple(buffer);
-
-    return status;
-  }
-#endif // _di_controller_rule_read_
-
-#ifndef _di_controller_rule_read_content_
-  f_return_status controller_rule_read_content(const controller_data_t data, const f_string_static_t file_name, const f_string_length_t line, f_string_static_t *content, controller_rule_items_t *items) {
-    f_status_t status = F_none;
-
-    f_string_range_t range = f_macro_string_range_t_initialize(content->used);
-    f_string_length_t last = 0;
-
-    f_fss_delimits_t delimits = f_fss_delimits_t_initialize;
-    f_fss_comments_t comments = f_fss_comments_t_initialize;
-    f_fss_object_t child_object = f_fss_object_t_initialize;
-    f_fss_content_t child_content = f_fss_content_t_initialize;
-    f_fss_quote_t quote = f_fss_quote_t_initialize;
-
-    uint8_t type = 0;
-
-    for (range.start = 0; range.start < content->used; last = range.start, type = 0) {
-
-      delimits.used = 0;
-      status = fl_fss_extended_list_object_read(content, &range, &child_object, &delimits);
-
-      if (F_status_is_error(status)) {
-        fll_error_file_print(data->error, F_status_set_fine(status), "fl_fss_extended_list_object_read", F_true, file_name.string, "read", fll_error_file_type_file);
-        break;
-      }
-
-      if (range.start >= range.stop || range.start >= content->used) {
-        if (status == FL_fss_found_object || status == FL_fss_found_object_content_not) {
-          if (error.verbosity != f_console_verbosity_quiet) {
-            fprintf(data.error.to.stream, "%c", f_string_eol[0]);
-            fprintf(data.error.to.stream, "%s%sUnterminated FSS Extended List at end of file '", 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, file_name.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]);
+          if (fl_string_dynamic_compare_string(controller_string_settings, cache->name_item, controller_string_settings_length) == f_equal_to) {
+            items->array[items->used].type = 0;
           }
-
-          status = F_status_set_error(FL_fss_found_object_content_not);
-        }
-
-        break;
-      }
-
-      if (status == FL_fss_found_object) {
-        // @fixme I just noticed that Extended List wasn't intended to be recursive, this will be updated.
-        comments.used = 0;
-        status = fl_fss_extended_list_content_read(content, &range, &child_content, &delimits, &comments);
-
-        if (F_status_is_error(status)) {
-          fll_error_file_print(data->error, F_status_set_fine(status), "fl_fss_extended_list_content_read", F_true, file_name.string, "read", fll_error_file_type_file);
-          break;
-        }
-
-        if (status == FL_fss_found_content) {
-          type = controller_rule_item_type_multiple;
-        }
-      }
-      else {
-        status = fl_fss_basic_object_read(content, &range, &child_object, &quote, &delimits);
-
-        if (F_status_is_error(status)) {
-          fll_error_file_print(data->error, F_status_set_fine(status), "fl_fss_basic_object_read", F_true, file_name.string, "read", fll_error_file_type_file);
-          break;
-        }
-
-        if (range.start >= range.stop || range.start >= content->used) {
-          // in this case, if status is FL_fss_found_object or FL_fss_found_object_content_not, there is no content so do not save this item.
-          break;
-        }
-
-        if (status == FL_fss_found_object) {
-          status = fl_fss_basic_content_read(content, &range, &child_content, &delimits);
-
-          if (F_status_is_error(status)) {
-            fll_error_file_print(data->error, F_status_set_fine(status), "fl_fss_basic_content_read", F_true, file_name.string, "read", fll_error_file_type_file);
-            break;
+          else if (fl_string_dynamic_compare_string(controller_string_command, cache->name_item, controller_string_command_length) == f_equal_to) {
+            items->array[items->used].type = controller_rule_item_type_command;
           }
-
-          if (status == FL_fss_found_content) {
-            type = controller_rule_item_type_single;
+          else if (fl_string_dynamic_compare_string(controller_string_script, cache->name_item, controller_string_script_length) == f_equal_to) {
+            items->array[items->used].type = controller_rule_item_type_script;
           }
-        }
-      }
+          else if (fl_string_dynamic_compare_string(controller_string_service, cache->name_item, controller_string_service_length) == f_equal_to) {
+            items->array[items->used].type = controller_rule_item_type_service;
+          }
+          else {
+            if (warning.verbosity == f_console_verbosity_debug) {
+              fprintf(data.warning.to.stream, "%c", f_string_eol[0]);
+              fprintf(data.warning.to.stream, "%s%sUnknown item type.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : "", data.warning.context.after->string, f_string_eol[0]);
 
-      if (type) {
-        status = fl_fss_apply_delimit(delimits, &data_make->buffer);
+              controller_rule_error_print(data.warning, *cache);
+            }
 
-        if (F_status_is_error(status)) {
-          fll_error_file_print(data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, file_name.string, "read", fll_error_file_type_file);
-          break;
-        }
+            continue;
+          }
 
-        status = f_fss_count_lines(buffer, contents.array[i], &items->array[items->used].line);
+          if (items->array[items->used].type) {
+            status = controller_rule_item_read(data, &content, cache, &items->array[items->used]);
+            if (F_status_is_error(status)) break;
 
-        if (F_status_is_error(status)) {
-          fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true);
-          break;
-        }
+            items->used++;
+          }
+          else {
+            // @todo handle rule settings population.
+          }
+        } // for
 
-        // @todo
-        //if (fl_string_dynamic_compare_string(x, items->array[i].name) == f_equal_to) {
-          //items->array[i].name
-          // @todo
-        //}
+        f_macro_string_dynamic_t_delete_simple(content);
       }
-    } // for
-
-    f_macro_fss_delimits_t_delete_simple(delimits);
-    f_macro_fss_comments_t_delete_simple(comments);
-    f_macro_fss_content_t_delete_simple(child_content);
-
-    if (F_status_is_error(status)) return status;
-
-    /*
-    uint8_t type;
-    uint8_t intent;
-
-    f_string_length_t line;
-
-    f_string_dynamic_t name;
-    f_string_dynamic_t content;
-    */
-    /*
-    status = fl_string_dynamic_partial_append_nulless(buffer, objects.array[i], items->array[i].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);
-      break;
-    }
-
-    status = fl_string_dynamic_terminate_after(items->array[i].name);
-
-    if (F_status_is_error(status)) {
-      fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
-      break;
     }
 
+    f_macro_fss_objects_t_delete_simple(objects);
+    f_macro_fss_contents_t_delete_simple(contents);
+    f_macro_string_dynamic_t_delete_simple(buffer);
 
-    */
+    return status;
   }
-#endif // _di_controller_rule_read_content_
+#endif // _di_controller_rule_read_
 
 #ifdef __cplusplus
 } // extern "C"
index 0ab28b0c48306ecf62318661370b1d1e6080603c..8783f2c55ccdc8afc80cfd96ab2d4ff831f482fa 100644 (file)
 extern "C" {
 #endif
 
+#ifndef _di_controller_rule_cache_t_
+  typedef struct {
+    f_string_length_t line_item;
+    f_string_length_t line_action;
+
+    f_string_range_t range_item;
+    f_string_range_t range_action;
+
+    f_string_dynamic_t name_file;
+    f_string_dynamic_t name_item;
+    f_string_dynamic_t name_action
+  } controller_rule_cache_t;
+
+  #define controller_rule_cache_t_initialize \
+    { \
+      0, \
+      0, \
+      0, \
+      0, \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
+    }
+
+  #define f_macro_controller_rule_name_t_delete_simple(cache) \
+    f_string_dynamic_t_delete_simple(cache.name_file) \
+    f_string_dynamic_t_delete_simple(cache.name_item) \
+    f_string_dynamic_t_delete_simple(cache.name_action)
+#endif // _di_controller_rule_cache_t_
+
+/**
+ * Read the content within the buffer, extracting all valid actions for the current processed item.
+ *
+ * @param data
+ *   The program data.
+ * @param multiple
+ *   If TRUE, then the Object expects multiple lines of Content (which ends up being an extended list).
+ *   If FALSE, then the Object expects only a single line of Content (which is either basic or extended).
+ * @param buffer
+ *   The buffer containing the content.
+ * @param cache
+ *   A structure for containing and caching the file name, item name, and action name.
+ * @param item
+ *   The processed item.
+ * @param actions
+ *   The processed actions.
+ *
+ * @return
+ *   F_none on success.
+ *   @todo add response codes.
+ *
+ *   Errors (with error bit) from: f_fss_count_lines().
+ */
+#ifndef _di_controller_rule_actions_read_
+  f_return_status controller_rule_actions_read(const controller_data_t data, const bool multiple, f_string_static_t *buffer, controller_rule_cache_t *cache, controller_rule_item_t *item, controller_rule_actions_t *actions) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_actions_read_
+
+/**
+ * Print additional error/warning information in addition to existing error.
+ *
+ * This is explicitly intended to be used in addition to the error message.
+ *
+ * @param output
+ *   The error or warning output structure.
+ * @param cache
+ *   A structure for containing and caching the file name, item name, and action name.
+ *
+ * @see controller_rule_actions_read()
+ * @see controller_rule_items_read()
+ * @see controller_rule_settings_read()
+ */
+#ifndef _di_controller_rule_error_print_
+  void controller_rule_error_print(const fll_error_print_t output, const controller_rule_cache_t cache) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_error_print_
+
+/**
+ * Read the content within the buffer, extracting all valid items after determining their type for some rule file.
+ *
+ * This will perform additional FSS read functions as appropriate.
+ *
+ * @param data
+ *   The program data.
+ * @param buffer
+ *   The buffer containing the content.
+ * @param cache
+ *   A structure for containing and caching the file name, item name, and action name.
+ * @param item
+ *   The processed item.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   Errors (with error bit) from: f_fss_count_lines().
+ *   Errors (with error bit) from: fl_string_dynamic_partial_append_nulless().
+ *   Errors (with error bit) from: fl_string_dynamic_terminate_after().
+ *
+ * @see controller_rule_actions_read()
+ */
+#ifndef _di_controller_rule_item_read_
+  extern f_return_status controller_rule_item_read(const controller_data_t data, f_string_static_t *buffer, controller_rule_cache_t *cache, controller_rule_item_t *item) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_item_read_
+
 /**
  * Increase the size of the rule items array by the specified amount, but only if necessary.
  *
@@ -37,16 +139,16 @@ extern "C" {
  *
  * @param data
  *   The program data.
- * @param file_name
- *   The file name string.
+ * @param cache
+ *   A structure for containing and caching the file name, item name, and action name.
  * @param items
- *   An array of items associated with the rule.
+ *   The processed array of items.
  *
  * @return
  *   F_none on success.
  *
  *   Errors (with error bit) from: controller_rule_items_increase_by().
- *   Errors (with error bit) from: controller_rule_read_content().
+ *   Errors (with error bit) from: controller_rule_item_read().
  *   Errors (with error bit) from: f_file_stream_open().
  *   Errors (with error bit) from: f_file_stream_read().
  *   Errors (with error bit) from: f_fss_count_lines().
@@ -55,38 +157,13 @@ extern "C" {
  *   Errors (with error bit) from: fl_string_dynamic_partial_append_nulless().
  *   Errors (with error bit) from: fl_string_dynamic_terminate_after().
  *   Errors (with error bit) from: fll_fss_basic_list_read().
+ *
+ * @see controller_rule_item_read()
  */
 #ifndef _di_controller_rule_read_
-  extern f_return_status controller_rule_read(const controller_data_t data, const f_string_static_t file_name, controller_rule_items_t *items) f_gcc_attribute_visibility_internal;
+  extern f_return_status controller_rule_read(const controller_data_t data, controller_rule_cache_t *cache, controller_rule_items_t *items) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_read_
 
-/**
- * Read the content within the buffer, extracting all valid items after determining their type for some rule file.
- *
- * This will perform additional FSS read functions as appropriate.
- *
- * @param data
- *   The program data.
- * @param file_name
- *   The file name string.
- * @param line
- *   The line number where the content begins.
- * @param content
- *   The buffer containing the content.
- * @param items
- *   An array of items associated with the rule.
- *
- * @return
- *   F_none on success.
- *
- *   Errors (with error bit) from: f_fss_count_lines().
- *   Errors (with error bit) from: fl_string_dynamic_partial_append_nulless().
- *   Errors (with error bit) from: fl_string_dynamic_terminate_after().
- */
-#ifndef _di_controller_rule_read_content_
-  extern f_return_status controller_rule_read_content(const controller_data_t data, const f_string_static_t file_name, const f_string_length_t line, f_string_static_t *content, controller_rule_items_t *items) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_rule_read_content_
-
 #ifdef __cplusplus
 } // extern "C"
 #endif
index ea3a9e54a4bc798de03abb9a04495b8f9deca62e..b7d55ded20fa167a3d66798fafc1caa09b4ba9d5 100644 (file)
@@ -41,5 +41,5 @@ Rule Documentation:
   The "group" and "user" can only be switched to if the user this controller program being operated under is allowed to switch to.
 
   The "create" Content designates that this controller program to create the PID file after successfully starting the service.
-  The "program" Content designates that the called program will provide the PID file after successfully starting the service.
+  The "use" Content designates that the called program will provide the PID file after successfully starting the service.
   For both "create" and "program" the PID file is expected to only exist on success or failure and the existence thereof designates the success or failure rate.
index d2518889e37246f3f674c9a9b58d1fb9afbf46ba..70a2e1dd0650e403410e4b0de34144a16cddffed 100644 (file)
@@ -9,7 +9,7 @@ Rule Specification:
     "settings": Required.
     "command": A Basic List of FSS-0001 (Extended) Object and Content, supporting the following Objects: "group", "restart", "reload", "start", "stop", and "user".
     "script": A Basic List of FSS-0003 (Extended List) Object and Content, supporting the following Objects: "restart", "reload", "start", and "stop" and A Basic List of FSS-0001 (Extended) Object and Content, supporting the following: "group" and "user".
-    "service": A Basic List of FSS-0001 (Extended) Object and Content, supporting the following Objects: ""create", "group", "program", "restart", "reload", "start", "stop", "timeout", and "user".
+    "service": A Basic List of FSS-0001 (Extended) Object and Content, supporting the following Objects: ""create", "group", "use", "restart", "reload", "start", "stop", "timeout", and "user".
 
   For the above Basic List Objects, "main" may be specified only once whereas the others may be specifed multiple times.
 
@@ -21,12 +21,12 @@ Rule Specification:
 
   For the inner parts, these are the Extended Objects\:
     "create": One Content representing the path to a PID file.
-    "program": One Content representing the path to a PID file.
     "group": One Content representing a group name or group id.
     "restart": One or more Content representing a program to and its arguments.
     "reload": One or more Content representing a program to and its arguments.
     "start": One or more Content representing a program to and its arguments.
     "stop": One or more Content representing a program to and its arguments.
+    "use": One Content representing the path to a PID file.
     "user": One Content representing a user name or user id.
 
   For the inner parts, these are the Extended List Objects\: