]> Kevux Git Server - fll/commitdiff
Progress: Continue working on control and controller.
authorKevin Day <thekevinday@gmail.com>
Wed, 16 Mar 2022 04:34:00 +0000 (23:34 -0500)
committerKevin Day <thekevinday@gmail.com>
Wed, 16 Mar 2022 04:34:00 +0000 (23:34 -0500)
This focuses on the control end of things.
This pulls in several dependencies that are needed to process the packet.

14 files changed:
level_3/control/c/control.c
level_3/control/c/control.h
level_3/control/c/private-common.c
level_3/control/c/private-common.h
level_3/control/c/private-control.c
level_3/control/c/private-control.h
level_3/control/c/private-print.c
level_3/control/c/private-print.h
level_3/control/data/build/dependencies
level_3/control/data/build/settings
level_3/controller/c/controller.h
level_3/controller/c/lock/private-lock.h
level_3/controller/data/build/dependencies
level_3/controller/data/build/settings

index dc49685d1fc8b8e467eccf45049a4e1f0aaebddc..bc1ae5368a63d83d43298faa6f12cf5940b7889d 100644 (file)
@@ -30,7 +30,7 @@ extern "C" {
     fll_program_print_help_option(main->output.to, main->context, control_short_settings_s, control_long_settings_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "Specify a directory path or a full path to the control settings file.");
     fll_program_print_help_option(main->output.to, main->context, control_short_socket_s, control_long_socket_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, "  Specify a directory path or a full path to the controller socket file.");
 
-    fll_program_print_help_usage(main->output.to, main->context, control_program_name_s, control_command_s);
+    fll_program_print_help_usage(main->output.to, main->context, control_program_name_s, control_action_s);
 
     fl_print_format("  When the %[%r%r%] parameter represents a directory path then the file name is generated from either the", main->output.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, control_long_socket_s, main->context.set.notable);
     fl_print_format(" %[%r%r%] parameter or from the control settings file.%r%r", main->output.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, control_long_name_s, main->context.set.notable, f_string_eol_s, f_string_eol_s);
@@ -191,12 +191,13 @@ extern "C" {
         control_data_t data = control_data_t_initialize;
         data.argv = main->parameters.arguments.array;
 
-        // Verify commands before attempting to connect to the socket.
-        if (control_command_identify(main, &data, data.argv[main->parameters.remaining.array[0]]) == F_found) {
-          status = control_command_verify(main, &data);
+        data.action = control_action_identify(main, &data, data.argv[main->parameters.remaining.array[0]]);
+
+        if (data.action) {
+          status = control_action_verify(main, &data);
         }
         else {
-          control_print_error_parameter_command_not(main, data.argv[main->parameters.remaining.array[0]]);
+          control_print_error_parameter_action_not(main, data.argv[main->parameters.remaining.array[0]]);
 
           status = F_status_set_error(F_parameter);
         }
@@ -238,7 +239,9 @@ extern "C" {
           }
 
           if (F_status_is_error_not(status)) {
-            status = control_packet_receive(main, &data);
+            control_payload_header_t header = control_payload_header_t_initialize;
+
+            status = control_packet_receive(main, &data, &header);
 
             if (F_status_is_error(status)) {
               if (F_status_set_fine(status) == F_too_large) {
@@ -260,7 +263,7 @@ extern "C" {
         control_data_delete(&data);
       }
       else {
-        control_print_error_parameter_commands_none(main);
+        control_print_error_parameter_actions_none(main);
 
         status = F_status_set_error(F_data_not);
       }
index b82714af6ed46401035764894791ddf3b2f348a7..71807da8c86a54c275e6a97423a0136a521d78b9 100644 (file)
@@ -24,6 +24,7 @@
 #include <fll/level_0/utf.h>
 #include <fll/level_0/color.h>
 #include <fll/level_0/console.h>
+#include <fll/level_0/conversion.h>
 #include <fll/level_0/directory.h>
 #include <fll/level_0/file.h>
 #include <fll/level_0/fss.h>
 #include <fll/level_0/print.h>
 #include <fll/level_0/signal.h>
 #include <fll/level_0/socket.h>
+#include <fll/level_0/status_string.h>
 
 // FLL-1 includes.
+#include <fll/level_1/conversion.h>
 #include <fll/level_1/fss.h>
 #include <fll/level_1/print.h>
 #include <fll/level_1/string.h>
@@ -44,6 +47,7 @@
 #include <fll/level_2/fss/extended.h>
 #include <fll/level_2/print.h>
 #include <fll/level_2/program.h>
+#include <fll/level_2/status_string.h>
 
 // Control includes.
 #include <program/control/common.h>
index 2e82422a44081d23bea472e2f01172a561ca62d9..1dffbfb749229ebbf977c869fda9f83227d3c65a 100644 (file)
@@ -17,8 +17,9 @@ extern "C" {
   const f_string_static_t control_path_settings_s = macro_f_string_static_t_initialize(CONTROL_path_settings_s, 0, CONTROL_path_settings_s_length);
 
   const f_string_static_t control_action_s = macro_f_string_static_t_initialize(CONTROL_action_s, 0, CONTROL_action_s_length);
-  const f_string_static_t control_command_s = macro_f_string_static_t_initialize(CONTROL_command_s, 0, CONTROL_command_s_length);
+  const f_string_static_t control_controller_s = macro_f_string_static_t_initialize(CONTROL_controller_s, 0, CONTROL_controller_s_length);
   const f_string_static_t control_default_s = macro_f_string_static_t_initialize(CONTROL_default_s, 0, CONTROL_default_s_length);
+  const f_string_static_t control_error_s = macro_f_string_static_t_initialize(CONTROL_error_s, 0, CONTROL_error_s_length);
   const f_string_static_t control_length_s = macro_f_string_static_t_initialize(CONTROL_length_s, 0, CONTROL_length_s_length);
   const f_string_static_t control_name_socket_s = macro_f_string_static_t_initialize(CONTROL_name_socket_s, 0, CONTROL_name_socket_s_length);
   const f_string_static_t control_path_socket_s = macro_f_string_static_t_initialize(CONTROL_path_socket_s, 0, CONTROL_path_socket_s_length);
@@ -27,7 +28,6 @@ extern "C" {
   const f_string_static_t control_status_s = macro_f_string_static_t_initialize(CONTROL_status_s, 0, CONTROL_status_s_length);
   const f_string_static_t control_type_s = macro_f_string_static_t_initialize(CONTROL_type_s, 0, CONTROL_type_s_length);
 
-  const f_string_static_t control_error_s = macro_f_string_static_t_initialize(CONTROL_error_s, 0, CONTROL_error_s_length);
   const f_string_static_t control_freeze_s = macro_f_string_static_t_initialize(CONTROL_freeze_s, 0, CONTROL_freeze_s_length);
   const f_string_static_t control_kill_s = macro_f_string_static_t_initialize(CONTROL_kill_s, 0, CONTROL_kill_s_length);
   const f_string_static_t control_pause_s = macro_f_string_static_t_initialize(CONTROL_pause_s, 0, CONTROL_pause_s_length);
@@ -52,15 +52,10 @@ extern "C" {
     f_string_ranges_resize(0, &data->cache.packet_objects);
     f_string_rangess_resize(0, &data->cache.packet_contents);
 
-    f_string_ranges_resize(0, &data->cache.payload_objects);
-    f_string_rangess_resize(0, &data->cache.payload_contents);
+    f_string_ranges_resize(0, &data->cache.header_objects);
+    f_string_rangess_resize(0, &data->cache.header_contents);
 
     f_array_lengths_resize(0, &data->cache.delimits);
-
-    f_string_ranges_resize(0, &data->cache.range_actions);
-    f_string_ranges_resize(0, &data->cache.range_statuss);
-
-    f_uint8s_resize(0, &data->cache.types);
   }
 #endif // _di_control_data_delete_
 
index 36fd0ead7aaf1c075d62efdbc7ff06d1ed6a643b..b8214a284427fd3ec71cca6b1590a511fba04c7e 100644 (file)
@@ -128,8 +128,9 @@ extern "C" {
   #endif // defined(_override_control_path_settings_) && defined(_override_control_path_settings_length_)
 
   #define CONTROL_action_s             "action"
-  #define CONTROL_command_s            "command"
+  #define CONTROL_controller_s         "controller"
   #define CONTROL_default_s            "default"
+  #define CONTROL_error_s              "error"
   #define CONTROL_length_s             "length"
   #define CONTROL_name_socket_s        "name_socket"
   #define CONTROL_path_socket_s        "path_socket"
@@ -138,7 +139,6 @@ extern "C" {
   #define CONTROL_status_s             "status"
   #define CONTROL_type_s               "type"
 
-  #define CONTROL_error_s    "error"
   #define CONTROL_freeze_s   "freeze"
   #define CONTROL_kill_s     "kill"
   #define CONTROL_pause_s    "pause"
@@ -152,18 +152,18 @@ extern "C" {
   #define CONTROL_stop_s     "stop"
   #define CONTROL_thaw_s     "thaw"
 
-  #define CONTROL_command_s_length            7
+  #define CONTROL_action_s_length             6
+  #define CONTROL_controller_s_length         10
   #define CONTROL_default_s_length            7
+  #define CONTROL_error_s_length              5
+  #define CONTROL_length_s_length             6
   #define CONTROL_name_socket_s_length        11
   #define CONTROL_path_socket_s_length        11
   #define CONTROL_path_socket_prefix_s_length 18
   #define CONTROL_path_socket_suffix_s_length 18
-  #define CONTROL_type_s_length               4
   #define CONTROL_status_s_length             6
-  #define CONTROL_length_s_length             6
-  #define CONTROL_action_s_length             6
+  #define CONTROL_type_s_length               4
 
-  #define CONTROL_error_s_length    5
   #define CONTROL_freeze_s_length   6
   #define CONTROL_kill_s_length     4
   #define CONTROL_pause_s_length    5
@@ -180,8 +180,9 @@ extern "C" {
   extern const f_string_static_t control_path_settings_s;
 
   extern const f_string_static_t control_action_s;
-  extern const f_string_static_t control_command_s;
+  extern const f_string_static_t control_controller_s;
   extern const f_string_static_t control_default_s;
+  extern const f_string_static_t control_error_s;
   extern const f_string_static_t control_length_s;
   extern const f_string_static_t control_name_socket_s;
   extern const f_string_static_t control_path_socket_s;
@@ -190,7 +191,6 @@ extern "C" {
   extern const f_string_static_t control_status_s;
   extern const f_string_static_t control_type_s;
 
-  extern const f_string_static_t control_error_s;
   extern const f_string_static_t control_freeze_s;
   extern const f_string_static_t control_kill_s;
   extern const f_string_static_t control_pause_s;
@@ -206,7 +206,7 @@ extern "C" {
 #endif // _di_control_strings_s_
 
 /**
- * Codes representing supported commands.
+ * Codes representing supported actions.
  *
  * freeze:   Perform the freeze controller operation.
  * kill:     Perform the kill controller operation.
@@ -221,22 +221,22 @@ extern "C" {
  * stop:     Perform the stop controller operation.
  * thaw:     Perform the thaw controller operation.
  */
-#ifndef _di_control_command_types_
+#ifndef _di_control_action_types_
   enum {
-    control_command_type_freeze_e = 1,
-    control_command_type_kill_e,
-    control_command_type_pause_e,
-    control_command_type_reboot_e,
-    control_command_type_reload_e,
-    control_command_type_rerun_e,
-    control_command_type_restart_e,
-    control_command_type_resume_e,
-    control_command_type_shutdown_e,
-    control_command_type_start_e,
-    control_command_type_stop_e,
-    control_command_type_thaw_e,
+    control_action_type_freeze_e = 1,
+    control_action_type_kill_e,
+    control_action_type_pause_e,
+    control_action_type_reboot_e,
+    control_action_type_reload_e,
+    control_action_type_rerun_e,
+    control_action_type_restart_e,
+    control_action_type_resume_e,
+    control_action_type_shutdown_e,
+    control_action_type_start_e,
+    control_action_type_stop_e,
+    control_action_type_thaw_e,
   };
-#endif // _di_control_command_types_
+#endif // _di_control_action_types_
 
 /**
  * The control cache.
@@ -248,8 +248,8 @@ extern "C" {
  * packet_objects:  The FSS Objects for a packet.
  * packet_contents: The FSS Contents for a packet.
  *
- * payload_objects:  The FSS Objects for a payload.
- * payload_contents: The FSS Contents for a payload.
+ * header_objects:  The FSS Objects for a packet payload header.
+ * header_contents: The FSS Contents for a packet payload header.
  *
  * delimits: The delimits cache.
  */
@@ -262,15 +262,10 @@ extern "C" {
     f_fss_objects_t packet_objects;
     f_fss_contents_t packet_contents;
 
-    f_fss_objects_t payload_objects;
-    f_fss_contents_t payload_contents;
+    f_fss_objects_t header_objects;
+    f_fss_contents_t header_contents;
 
     f_fss_delimits_t delimits;
-
-    f_string_ranges_t range_actions;
-    f_string_ranges_t range_statuss;
-
-    f_uint8s_t types;
   } control_cache_t;
 
   #define control_cache_initialize \
@@ -283,23 +278,20 @@ extern "C" {
       f_fss_objects_t_initialize, \
       f_fss_contents_t_initialize, \
       f_fss_delimits_t_initialize, \
-      f_string_ranges_t_initialize, \
-      f_string_ranges_t_initialize, \
-      f_uint8s_t_initialize, \
     }
 #endif // _di_control_cache_t_
 
 /**
  * The control data.
  *
- * argv:    The argument structure in the progam data parameters for simplifying syntax.
- * command: The command type code.
- * cache:   A cache.
- * socket:  A socket used to connect to the controller.
+ * argv:   The argument structure in the progam data parameters for simplifying syntax.
+ * action: The action type code.
+ * cache:  A cache.
+ * socket: A socket used to connect to the controller.
  */
 #ifndef _di_control_data_t_
   typedef struct {
-    uint8_t command;
+    uint8_t action;
 
     control_cache_t cache;
 
@@ -319,6 +311,46 @@ extern "C" {
 #endif // _di_control_data_t_
 
 /**
+ * Supported payload types.
+ *
+ * error:      The payload is an error payload.
+ * controller: The payload is a controller payload.
+ */
+#ifndef _di_control_payload_types_
+  enum {
+    control_payload_type_error_e = 1,
+    control_payload_type_controller_e,
+  };
+#endif // _di_control_payload_types_
+
+/**
+ * The packet payload header data.
+ *
+ * The FSS-000E (Payload) supports multiple objects, but the Control packet does not support this, yet.
+ *
+ * action: The action type code, for any valid action (see: control_action_types enumeration).
+ * type:   The packet type represented by the payload packet.
+ * status: The status code represented by the payload packet.
+ * length: The length of the payload content within the payload packet.
+ */
+#ifndef _di_control_payload_header_t_
+  typedef struct {
+    uint8_t action;
+    uint8_t type;
+    f_status_t status;
+    uint16_t length;
+  } control_payload_header_t;
+
+  #define control_payload_header_t_initialize \
+    { \
+      0, \
+      0, \
+      f_status_t_initialize, \
+      f_array_length_t_initialize, \
+    }
+#endif // _di_control_payload_header_t_
+
+/**
  * Deallocate the control data.
  *
  * @param data
index 4b8016e70960857707a212c74285ec58c65ec6dc..533265f4f124774689b2db506b0a9875b990550d 100644 (file)
 extern "C" {
 #endif
 
-#ifndef _di_control_command_identify_
-  f_status_t control_command_identify(fll_program_data_t * const main, control_data_t * const data, const f_string_static_t command) {
+#ifndef _di_control_action_identify_
+  uint8_t control_action_identify(fll_program_data_t * const main, control_data_t * const data, const f_string_static_t action) {
 
-    if (fl_string_dynamic_compare(command, control_freeze_s) == F_equal_to) {
-      data->command = control_command_type_freeze_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_freeze_s) == F_equal_to) {
+      return control_action_type_freeze_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_kill_s) == F_equal_to) {
-      data->command = control_command_type_kill_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_kill_s) == F_equal_to) {
+      return control_action_type_kill_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_pause_s) == F_equal_to) {
-      data->command = control_command_type_pause_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_pause_s) == F_equal_to) {
+      return control_action_type_pause_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_reboot_s) == F_equal_to) {
-      data->command = control_command_type_reboot_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_reboot_s) == F_equal_to) {
+      return control_action_type_reboot_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_reload_s) == F_equal_to) {
-      data->command = control_command_type_reload_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_reload_s) == F_equal_to) {
+      return control_action_type_reload_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_rerun_s) == F_equal_to) {
-      data->command = control_command_type_rerun_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_rerun_s) == F_equal_to) {
+      return control_action_type_rerun_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_restart_s) == F_equal_to) {
-      data->command = control_command_type_restart_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_restart_s) == F_equal_to) {
+      return control_action_type_restart_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_resume_s) == F_equal_to) {
-      data->command = control_command_type_resume_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_resume_s) == F_equal_to) {
+      return control_action_type_resume_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_shutdown_s) == F_equal_to) {
-      data->command = control_command_type_shutdown_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_shutdown_s) == F_equal_to) {
+      return control_action_type_shutdown_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_start_s) == F_equal_to) {
-      data->command = control_command_type_start_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_start_s) == F_equal_to) {
+      return control_action_type_start_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_stop_s) == F_equal_to) {
-      data->command = control_command_type_stop_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_stop_s) == F_equal_to) {
+      return control_action_type_stop_e;
     }
 
-    if (fl_string_dynamic_compare(command, control_thaw_s) == F_equal_to) {
-      data->command = control_command_type_thaw_e;
-
-      return F_found;
+    if (fl_string_dynamic_compare(action, control_thaw_s) == F_equal_to) {
+      return control_action_type_thaw_e;
     }
 
-    return F_found_not;
+    return 0;
   }
-#endif // _di_control_command_identify_
-
-#ifndef _di_control_command_verify_
-  f_status_t control_command_verify(fll_program_data_t * const main, control_data_t * const data) {
-
-    switch (data->command) {
-      case control_command_type_freeze_e:
-      case control_command_type_kill_e:
-      case control_command_type_pause_e:
-      case control_command_type_reload_e:
-      case control_command_type_rerun_e:
-      case control_command_type_restart_e:
-      case control_command_type_resume_e:
-      case control_command_type_start_e:
-      case control_command_type_stop_e:
-      case control_command_type_thaw_e:
+#endif // _di_control_action_identify_
+
+#ifndef _di_control_action_verify_
+  f_status_t control_action_verify(fll_program_data_t * const main, control_data_t * const data) {
+
+    switch (data->action) {
+      case control_action_type_freeze_e:
+      case control_action_type_kill_e:
+      case control_action_type_pause_e:
+      case control_action_type_reload_e:
+      case control_action_type_rerun_e:
+      case control_action_type_restart_e:
+      case control_action_type_resume_e:
+      case control_action_type_start_e:
+      case control_action_type_stop_e:
+      case control_action_type_thaw_e:
         if (main->parameters.remaining.used < 2) {
-          control_print_error_parameter_command_rule_not(main, data->argv[main->parameters.remaining.array[0]]);
+          control_print_error_parameter_action_rule_not(main, data->argv[main->parameters.remaining.array[0]]);
 
           return F_status_set_error(F_parameter);
         }
         else if (main->parameters.remaining.used > 3) {
-          control_print_error_parameter_command_rule_too_many(main, data->argv[main->parameters.remaining.array[0]]);
+          control_print_error_parameter_action_rule_too_many(main, data->argv[main->parameters.remaining.array[0]]);
 
           return F_status_set_error(F_parameter);
         }
 
         if (!data->argv[main->parameters.remaining.array[1]].used) {
           if (main->parameters.remaining.used == 2) {
-            control_print_error_parameter_command_rule_empty(main, data->argv[main->parameters.remaining.array[0]]);
+            control_print_error_parameter_action_rule_empty(main, data->argv[main->parameters.remaining.array[0]]);
           }
           else {
-            control_print_error_parameter_command_rule_directory_empty(main, data->argv[main->parameters.remaining.array[0]]);
+            control_print_error_parameter_action_rule_directory_empty(main, data->argv[main->parameters.remaining.array[0]]);
           }
 
           return F_status_set_error(F_parameter);
@@ -124,7 +100,7 @@ extern "C" {
 
         if (main->parameters.remaining.used == 3) {
           if (!data->argv[main->parameters.remaining.array[2]].used) {
-            control_print_error_parameter_command_rule_basename_empty(main, data->argv[main->parameters.remaining.array[0]]);
+            control_print_error_parameter_action_rule_basename_empty(main, data->argv[main->parameters.remaining.array[0]]);
 
             return F_status_set_error(F_parameter);
           }
@@ -133,18 +109,18 @@ extern "C" {
         return F_none;
     }
 
-    // @todo the reboot and shutdown need to support date and time commands: "now", "in (a time)", and "at (a time)".
-    if (data->command == control_command_type_reboot_e) {
-      // @todo (also needs to support kexec calls or kexec needs its own command, which will likely be in the controller program.)
+    // @todo the reboot and shutdown need to support date and time actions: "now", "in (a time)", and "at (a time)".
+    if (data->action == control_action_type_reboot_e) {
+      // @todo (also needs to support kexec calls or kexec needs its own action, which will likely be in the controller program.)
     }
 
-    if (data->command == control_command_type_shutdown_e) {
+    if (data->action == control_action_type_shutdown_e) {
       // @todo
     }
 
     return F_none;
   }
-#endif // _di_control_command_verify_
+#endif // _di_control_action_verify_
 
 #ifndef _di_control_packet_build_
   f_status_t control_packet_build(fll_program_data_t * const main, control_data_t * const data) {
@@ -256,23 +232,28 @@ extern "C" {
 #endif // _di_control_packet_build_
 
 #ifndef _di_control_packet_receive_
-  f_status_t control_packet_receive(fll_program_data_t * const main, control_data_t * const data) {
+  f_status_t control_packet_receive(fll_program_data_t * const main, control_data_t * const data, control_payload_header_t * const header) {
 
     data->cache.large.used = 0;
     data->cache.small.used = 0;
     data->cache.packet_objects.used = 0;
     data->cache.packet_contents.used = 0;
-    data->cache.payload_objects.used = 0;
-    data->cache.payload_contents.used = 0;
+    data->cache.header_objects.used = 0;
+    data->cache.header_contents.used = 0;
     data->cache.delimits.used = 0;
-    data->cache.range_actions.used = 0;
-    data->cache.range_statuss.used = 0;
-    data->cache.types.used = 0;
+
+    header->action = 0;
+    header->type = 0;
+    header->status = F_none;
+    header->length = 0;
 
     f_status_t status = F_none;
-    f_array_length_t length = 5;
+    f_array_length_t i = 0;
+    f_string_range_t range_header = f_string_range_t_initialize;
+    f_string_range_t range_payload = f_string_range_t_initialize;
 
     {
+      f_array_length_t length = 5;
       uint8_t head[length];
 
       memset(head, 0, sizeof(uint8_t) * length);
@@ -341,43 +322,174 @@ extern "C" {
 
       data->cache.delimits.used = 0;
 
-      f_string_range_t *range_header_object = 0;
-      f_string_ranges_t *range_header_content = 0;
-      f_string_range_t *range_payload_object = 0;
-      f_string_ranges_t *range_payload_content = 0;
+      {
+        f_string_ranges_t *content_header = 0;
+        f_string_ranges_t *content_payload = 0;
+
+        for (; i < data->cache.packet_objects.used; ++i) {
 
-      for (f_array_length_t i = 0; i < data->cache.packet_objects.used; ++i) {
+          if (fl_string_dynamic_partial_compare_string(f_fss_string_header_s.string, data->cache.large, f_fss_string_header_s.used, data->cache.packet_objects.array[i]) == F_equal_to) {
 
-        if (fl_string_dynamic_partial_compare_string(f_fss_string_header_s.string, data->cache.large, f_fss_string_header_s.used, data->cache.packet_objects.array[i]) == F_equal_to) {
+            // The FSS-000E (Payload) standard does not prohibit multiple "header", but such cases are not supported by the controller and the control programs.
+            if (content_header) {
+              return F_status_set_error(F_packet_not);
+            }
 
-          // The FSS-000E (Payload) standard does not prohibit multiple "header", but such cases are not supported by the controller and the control programs.
-          if (range_header_object) {
-            return F_status_set_error(F_packet_not);
+            content_header = &data->cache.packet_contents.array[i];
           }
+          else if (fl_string_dynamic_partial_compare_string(f_fss_string_payload_s.string, data->cache.large, f_fss_string_payload_s.used, data->cache.packet_objects.array[i]) == F_equal_to) {
 
-          range_header_object = &data->cache.packet_objects.array[i];
-          range_header_content = &data->cache.packet_contents.array[i];
-        }
-        else if (fl_string_dynamic_partial_compare_string(f_fss_string_payload_s.string, data->cache.large, f_fss_string_payload_s.used, data->cache.packet_objects.array[i]) == F_equal_to) {
+            // Only a single "payload" is supported by the FSS-000E (Payload) standard.
+            if (content_payload) {
+              return F_status_set_error(F_packet_not);
+            }
 
-          // Only a single "payload" is supported by the FSS-000E (Payload) standard.
-          if (range_payload_object) {
-            return F_status_set_error(F_packet_not);
+            content_payload = &data->cache.packet_contents.array[i];
           }
+        } // for
 
-          range_payload_object = &data->cache.packet_objects.array[i];
-          range_payload_content = &data->cache.packet_contents.array[i];
+        if (!content_header || !content_payload) {
+          return F_status_set_error(F_packet_not);
         }
-      } // for
 
-      if (!range_header_object || !range_payload_object) {
-        return F_status_set_error(F_packet_not);
+        range_header = content_header->array[0];
+        range_payload = content_payload->array[0];
       }
 
-      // @todo load the "action"s, "length", "status"s, "type"s, and finally the "payload" (if lenth is > 0).
+      {
+        // 0x1 = found action, 0x2 = found length, 0x4 = found status, 0x8 = found_type.
+        uint8_t found = 0;
+        f_number_unsigned_t number = 0;
+        f_string_range_t range = range_header;
+
+        status = fll_fss_basic_list_read(data->cache.large, state, &range, &data->cache.header_objects, &data->cache.header_contents, &data->cache.delimits, 0, 0);
+        if (F_status_is_error(status)) return F_status_set_error(status);
+
+        status = fl_fss_apply_delimit(data->cache.delimits, &data->cache.large);
+        if (F_status_is_error(status)) return status;
+
+        if (!data->cache.header_contents.used) {
+          // @todo if debug print the reason for the failure.
+          return F_status_set_error(F_header);
+        }
+
+        // @todo walk through each range in header_objects, match the first "header" object, get the range from header_contents.array[0], reset the header_objects and header_contents and then pass the retrieved range to the fll_fss_extended_read() function below.
+
+        //status = fll_fss_extended_read(data->cache.large, state, &range, &data->cache.header_objects, &data->cache.header_contents, &data->cache.delimits, 0, 0);
+        if (F_status_is_error(status)) return F_status_set_error(status);
+
+        for (i = 0; i < data->cache.header_objects.used; ++i) {
+
+          if (fl_string_dynamic_partial_compare_string(control_action_s.string, data->cache.large, control_action_s.used, data->cache.header_objects.array[i]) == F_equal_to) {
+            if (!(found & 0x1)) {
+              const f_array_length_t action_length = (data->cache.header_contents.array[i].array[0].stop - data->cache.header_contents.array[i].array[0].start) + 1;
+              char action_string[action_length + 1];
+              const f_string_static_t action = macro_f_string_static_t_initialize(action_string, 0, action_length);
+
+              memcpy(action_string, data->cache.large.string + data->cache.header_contents.array[i].array[0].start, action_length);
+              action_string[action_length] = 0;
+
+              found |= 0x1;
+
+              control_print_debug_packet_header_object_and_content(main, control_action_s, data->cache.large, data->cache.header_contents.array[i].array[0]);
+
+              header->action = control_action_identify(main, data, action);
+
+              if (!header->action) {
+                // @todo if debug print the reason for the failure.
+                return F_status_set_error(F_header);
+              }
+            }
+            else {
+              control_print_warning_packet_header_duplicate_object(main, control_action_s);
+            }
+          }
+          else if (fl_string_dynamic_partial_compare_string(control_length_s.string, data->cache.large, control_length_s.used, data->cache.header_objects.array[i]) == F_equal_to) {
+            if (!(found & 0x2)) {
+              found |= 0x2;
+              number = 0;
+
+              control_print_debug_packet_header_object_and_content(main, control_length_s, data->cache.large, data->cache.header_contents.array[i].array[0]);
+
+              // First attempt to get status as a number.
+              status = fl_conversion_dynamic_partial_to_number_unsigned(data->cache.large, data->cache.header_contents.array[i].array[0], &number);
+
+              if (F_status_is_error(status)) {
+                // @todo if debug print the reason for the failure.
+                return F_status_set_error(F_status);
+              }
+
+              if (number > F_status_size_max_with_bits_d) {
+                // @todo if debug print the reason for the failure.
+                return F_status_set_error(F_status);
+              }
+
+              header->length = (uint16_t) number;
+            }
+            else {
+              control_print_warning_packet_header_duplicate_object(main, control_length_s);
+            }
+          }
+          else if (fl_string_dynamic_partial_compare_string(control_status_s.string, data->cache.large, control_status_s.used, data->cache.header_objects.array[i]) == F_equal_to) {
+            if (!(found & 0x4)) {
+              found |= 0x4;
+              number = 0;
+
+              control_print_debug_packet_header_object_and_content(main, control_status_s, data->cache.large, data->cache.header_contents.array[i].array[0]);
+
+              // First attempt to get status as a number.
+              status = fl_conversion_dynamic_partial_to_number_unsigned(data->cache.large, data->cache.header_contents.array[i].array[0], &number);
+
+              if (F_status_set_fine(status) == F_number) {
+                const f_array_length_t name_length = (data->cache.header_contents.array[i].array[0].stop - data->cache.header_contents.array[i].array[0].start) + 1;
+                char name_string[name_length + 1];
+                const f_string_static_t name = macro_f_string_static_t_initialize(name_string, 0, name_length);
+
+                memcpy(name_string, data->cache.large.string + data->cache.header_contents.array[i].array[0].start, name_length);
+                name_string[name_length] = 0;
+
+                status = fll_status_string_from(name, &header->status);
+
+                if (F_status_is_error(status)) {
+                  // @todo if debug print the reason for the failure.
+                  return status;
+                }
+              }
+              else if (F_status_is_error(status)) {
+                // @todo if debug print the reason for the failure.
+                return F_status_set_error(F_status);
+              }
+            }
+            else {
+              control_print_warning_packet_header_duplicate_object(main, control_length_s);
+            }
+          }
+          else if (fl_string_dynamic_partial_compare_string(control_type_s.string, data->cache.large, control_type_s.used, data->cache.header_objects.array[i]) == F_equal_to) {
+            if (!(found & 0x8)) {
+              found |= 0x8;
+
+              control_print_debug_packet_header_object_and_content(main, control_type_s, data->cache.large, data->cache.header_contents.array[i].array[0]);
+
+              if (fl_string_dynamic_partial_compare_string(control_controller_s.string, data->cache.large, control_controller_s.used, data->cache.header_contents.array[i].array[0]) == F_equal_to) {
+                header->type = control_payload_type_controller_e;
+              }
+              else if (fl_string_dynamic_partial_compare_string(control_error_s.string, data->cache.large, control_error_s.used, data->cache.header_contents.array[i].array[0]) == F_equal_to) {
+                header->type = control_payload_type_error_e;
+              }
+              else {
+                // @todo if debug print the reason for the failure.
+                return F_status_set_error(F_header);
+              }
+            }
+            else {
+              control_print_warning_packet_header_duplicate_object(main, control_type_s);
+            }
+          }
+        }
+      }
 
-      //status = fll_fss_extended_read(data->cache.payload, state, range_payload_content, &data->cache.payload_objects, &data->cache.payload_contents, &data->cache.delimits, 0, 0);
-      //if (F_status_is_error(status)) return status;
+      // @todo based on header->type, handle the data. if type is control_payload_type_error_e, then check the header->length and conditionally get the message from the payload content.
+      // @todo this handling may likely be moved outside of this function.
     }
 
     // @todo
index a628109cc06889c62b01196f536f71a6ec49e5ba..89b7bf3e68e33d014367edc099b1059fa29e96bd 100644 (file)
@@ -14,34 +14,34 @@ extern "C" {
 
 
 /**
- * Identify the command code the given name represents.
+ * Identify the action code the given name represents.
  *
  * @param main
  *   The main program data.
  * @param data
  *   The control data.
- * @param command
- *   The parameter representing a command.
+ * @param action
+ *   The parameter representing a action.
  *
  * @return
- *   F_found on success.
- *   F_found_not if name is unknown.
+ *   action type code on success.
+ *   0 if name is unknown.
  */
-#ifndef _di_control_command_identify_
-  extern f_status_t control_command_identify(fll_program_data_t * const main, control_data_t * const data, const f_string_static_t command) F_attribute_visibility_internal_d;
-#endif // _di_control_command_identify_
+#ifndef _di_control_action_identify_
+  extern uint8_t control_action_identify(fll_program_data_t * const main, control_data_t * const data, const f_string_static_t action) F_attribute_visibility_internal_d;
+#endif // _di_control_action_identify_
 
 /**
- * Verify that the additional parameters are reasonably correct for the identified command.
+ * Verify that the additional parameters are reasonably correct for the identified action.
  *
  * @param main
  *   The main program data.
  * @param data
  *   The control data.
  */
-#ifndef _di_control_command_verify_
-  extern f_status_t control_command_verify(fll_program_data_t * const main, control_data_t * const data) F_attribute_visibility_internal_d;
-#endif // _di_control_command_verify_
+#ifndef _di_control_action_verify_
+  extern f_status_t control_action_verify(fll_program_data_t * const main, control_data_t * const data) F_attribute_visibility_internal_d;
+#endif // _di_control_action_verify_
 
 /**
  * Build the payload, storing it in the large cache.
@@ -71,14 +71,19 @@ extern "C" {
 /**
  * Receive the response from the remote socket, storing it in the large cache.
  *
+ * @todo consider returning F_header (with error bit) fo most header processing errors rather than individual status codes.
+ *
  * @param main
  *   The main program data.
  * @param data
  *   The control data.
+ * @param header
+ *   The control payload packet header data.
  *
  * @return
  *   F_none on success.
  *
+ *   F_header (with error bit) If there is a problem processing the packet header.
  *   F_packet_not (with error bit) If the received packet is not a valid packet or not a supported packet structure.
  *   F_too_large (with error bit) If the received packet specifies a size that is too large or the actual size is larger than the specified size.
  *   F_too_small (with error bit) If the received packet actual size is smaller than the specified size.
@@ -100,7 +105,7 @@ extern "C" {
  * @see fll_fss_extended_read()
  */
 #ifndef _di_control_packet_receive_
-  extern f_status_t control_packet_receive(fll_program_data_t * const main, control_data_t * const data) F_attribute_visibility_internal_d;
+  extern f_status_t control_packet_receive(fll_program_data_t * const main, control_data_t * const data, control_payload_header_t * const header) F_attribute_visibility_internal_d;
 #endif // _di_control_packet_receive_
 
 /**
index e5fa830e2f7eb314f7f73547854694f83c4da3bd..e218a7fe728e0d0aff6ba4d1546e93fbbbca77d2 100644 (file)
 extern "C" {
 #endif
 
-#ifndef _di_control_print_error_parameter_commands_none_
-  void control_print_error_parameter_commands_none(fll_program_data_t * const main) {
+#ifndef _di_control_print_debug_packet_header_object_and_content_
+  void control_print_debug_packet_header_object_and_content(fll_program_data_t * const main, const f_string_static_t object, const f_string_static_t content, const f_string_range_t range_content) {
+
+    if (main->output.verbosity == f_console_verbosity_debug_e) return;
+
+    flockfile(main->error.to.stream);
+
+    fl_print_format("%rPacket header Object '%[%Q%]", main->output.to.stream, f_string_eol_s, main->context.set.notable, object, main->context.set.notable);
+    fl_print_format("' has value '%[%/Q%]'.%r", main->output.to.stream, main->context.set.notable, content, range_content, main->context.set.notable, f_string_eol_s);
+
+    funlockfile(main->error.to.stream);
+  }
+#endif // _di_control_print_debug_packet_header_object_and_content_
+
+#ifndef _di_control_print_error_parameter_actions_none_
+  void control_print_error_parameter_actions_none(fll_program_data_t * const main) {
 
     if (main->error.verbosity == f_console_verbosity_quiet_e) return;
 
-    fll_print_format("%r%[%QNo commands provided.%]%r", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error, f_string_eol_s);
+    fll_print_format("%r%[%QNo actions provided.%]%r", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error, f_string_eol_s);
   }
-#endif // _di_control_print_error_parameter_commands_none_
+#endif // _di_control_print_error_parameter_actions_none_
 
-#ifndef _di_control_print_error_parameter_command_not_
-  void control_print_error_parameter_command_not(fll_program_data_t * const main, const f_string_static_t command) {
+#ifndef _di_control_print_error_parameter_action_not_
+  void control_print_error_parameter_action_not(fll_program_data_t * const main, const f_string_static_t action) {
 
     if (main->error.verbosity == f_console_verbosity_quiet_e) return;
 
     flockfile(main->error.to.stream);
 
     fl_print_format("%r%[%QThe parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
-    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable);
-    fl_print_format("%[' is not a known controller command.%]%r", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s);
+    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, action, main->context.set.notable);
+    fl_print_format("%[' is not a known controller action.%]%r", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s);
 
     funlockfile(main->error.to.stream);
   }
-#endif // _di_control_print_error_parameter_command_not_
+#endif // _di_control_print_error_parameter_action_not_
 
-#ifndef _di_control_print_error_parameter_command_rule_basename_empty_
-  void control_print_error_parameter_command_rule_basename_empty(fll_program_data_t * const main, const f_string_static_t command) {
+#ifndef _di_control_print_error_parameter_action_rule_basename_empty_
+  void control_print_error_parameter_action_rule_basename_empty(fll_program_data_t * const main, const f_string_static_t action) {
 
     if (main->error.verbosity == f_console_verbosity_quiet_e) return;
 
     flockfile(main->error.to.stream);
 
-    fl_print_format("%r%[%QThe command parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
-    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable);
+    fl_print_format("%r%[%QThe action parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
+    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, action, main->context.set.notable);
     fl_print_format("%[' a rule base name cannot be an empty string.%]%r", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s);
 
     funlockfile(main->error.to.stream);
   }
-#endif // _di_control_print_error_parameter_command_rule_basename_empty_
+#endif // _di_control_print_error_parameter_action_rule_basename_empty_
 
-#ifndef _di_control_print_error_parameter_command_rule_directory_empty_
-  void control_print_error_parameter_command_rule_directory_empty(fll_program_data_t * const main, const f_string_static_t command) {
+#ifndef _di_control_print_error_parameter_action_rule_directory_empty_
+  void control_print_error_parameter_action_rule_directory_empty(fll_program_data_t * const main, const f_string_static_t action) {
 
     if (main->error.verbosity == f_console_verbosity_quiet_e) return;
 
     flockfile(main->error.to.stream);
 
-    fl_print_format("%r%[%QThe command parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
-    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable);
+    fl_print_format("%r%[%QThe action parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
+    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, action, main->context.set.notable);
     fl_print_format("%[' a rule directory path cannot be an empty string.%]%r", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s);
 
     funlockfile(main->error.to.stream);
   }
-#endif // _di_control_print_error_parameter_command_rule_directory_empty_
+#endif // _di_control_print_error_parameter_action_rule_directory_empty_
 
-#ifndef _di_control_print_error_parameter_command_rule_empty_
-  void control_print_error_parameter_command_rule_empty(fll_program_data_t * const main, const f_string_static_t command) {
+#ifndef _di_control_print_error_parameter_action_rule_empty_
+  void control_print_error_parameter_action_rule_empty(fll_program_data_t * const main, const f_string_static_t action) {
 
     if (main->error.verbosity == f_console_verbosity_quiet_e) return;
 
     flockfile(main->error.to.stream);
 
-    fl_print_format("%r%[%QThe command parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
-    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable);
+    fl_print_format("%r%[%QThe action parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
+    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, action, main->context.set.notable);
     fl_print_format("%[' a rule name cannot be an empty string.%]%r", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s);
 
     funlockfile(main->error.to.stream);
   }
-#endif // _di_control_print_error_parameter_command_rule_empty_
+#endif // _di_control_print_error_parameter_action_rule_empty_
 
-#ifndef _di_control_print_error_parameter_command_rule_not_
-  void control_print_error_parameter_command_rule_not(fll_program_data_t * const main, const f_string_static_t command) {
+#ifndef _di_control_print_error_parameter_action_rule_not_
+  void control_print_error_parameter_action_rule_not(fll_program_data_t * const main, const f_string_static_t action) {
 
     if (main->error.verbosity == f_console_verbosity_quiet_e) return;
 
     flockfile(main->error.to.stream);
 
-    fl_print_format("%r%[%QThe command parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
-    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable);
+    fl_print_format("%r%[%QThe action parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
+    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, action, main->context.set.notable);
     fl_print_format("%[' requires either a full rule name or a rule directory path along with the rule base name.%]%r", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s);
 
     funlockfile(main->error.to.stream);
   }
-#endif // _di_control_print_error_parameter_command_rule_not_
+#endif // _di_control_print_error_parameter_action_rule_not_
 
-#ifndef _di_control_print_error_parameter_command_rule_too_many_
-  void control_print_error_parameter_command_rule_too_many(fll_program_data_t * const main, const f_string_static_t command) {
+#ifndef _di_control_print_error_parameter_action_rule_too_many_
+  void control_print_error_parameter_action_rule_too_many(fll_program_data_t * const main, const f_string_static_t action) {
 
     if (main->error.verbosity == f_console_verbosity_quiet_e) return;
 
     flockfile(main->error.to.stream);
 
-    fl_print_format("%r%[%QThe command parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
-    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, command, main->context.set.notable);
+    fl_print_format("%r%[%QThe action parameter '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error);
+    fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, action, main->context.set.notable);
     fl_print_format("%[' has too many arguments.%]%r", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s);
 
     funlockfile(main->error.to.stream);
   }
-#endif // _di_control_print_error_parameter_command_rule_too_many_
+#endif // _di_control_print_error_parameter_action_rule_too_many_
 
 #ifndef _di_control_print_error_parameter_value_empty_
   void control_print_error_parameter_value_empty(fll_program_data_t * const main, const f_string_static_t parameter) {
@@ -225,6 +239,21 @@ extern "C" {
   }
 #endif // _di_control_print_signal_received_
 
+#ifndef _di_control_print_warning_packet_header_duplicate_object_
+  void control_print_warning_packet_header_duplicate_object(fll_program_data_t * const main, const f_string_static_t response_header) {
+
+    if (main->warning.verbosity == f_console_verbosity_debug_e) return;
+
+    flockfile(main->warning.to.stream);
+
+    fl_print_format("%r%[%QThe received response header '%]", main->warning.to.stream, f_string_eol_s, main->context.set.warning, main->warning.prefix, main->context.set.warning);
+    fl_print_format("%[%Q%]", main->warning.to.stream, main->context.set.notable, response_header, main->context.set.notable);
+    fl_print_format("%[' is repeated.%]%r", main->warning.to.stream, main->context.set.warning, main->context.set.warning, f_string_eol_s);
+
+    funlockfile(main->warning.to.stream);
+  }
+#endif // _di_control_print_warning_packet_header_duplicate_object_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 1d98b8f1aaa1465c7527faad0e1edff4b7757add..78396b825e401c6d144587d9a42d34e54ef5471d 100644 (file)
@@ -13,86 +13,102 @@ extern "C" {
 #endif
 
 /**
- * Print an error message about no commands being provided.
+ * Print a message displaying the object and content for some packet header.
  *
  * @param main
  *   The main program data.
+ * @param object
+ *   The object string.
+ * @param content
+ *   The content string.
+ * @param range_content
+ *   The range representing the content where the content is found within the content string.
  */
-#ifndef _di_control_print_error_parameter_commands_none_
-  extern void control_print_error_parameter_commands_none(fll_program_data_t * const main) F_attribute_visibility_internal_d;
-#endif // _di_control_print_error_parameter_commands_none_
+#ifndef _di_control_print_debug_packet_header_object_and_content_
+  extern void control_print_debug_packet_header_object_and_content(fll_program_data_t * const main, const f_string_static_t object, const f_string_static_t content, const f_string_range_t range_content) F_attribute_visibility_internal_d;
+#endif // _di_control_print_debug_packet_header_object_and_content_
 
 /**
- * Print an error message about the given parameter not matching the known set of controller commands.
+ * Print an error message about no actions being provided.
  *
  * @param main
  *   The main program data.
- * @param command
- *   The parameter representing a command.
  */
-#ifndef _di_control_print_error_parameter_command_not_
-  extern void control_print_error_parameter_command_not(fll_program_data_t * const main, const f_string_static_t command) F_attribute_visibility_internal_d;
-#endif // _di_control_print_error_parameter_command_not_
+#ifndef _di_control_print_error_parameter_actions_none_
+  extern void control_print_error_parameter_actions_none(fll_program_data_t * const main) F_attribute_visibility_internal_d;
+#endif // _di_control_print_error_parameter_actions_none_
 
 /**
- * Print an error message about the given parameter being a rule command having an empty rule basename.
+ * Print an error message about the given parameter not matching the known set of controller actions.
  *
  * @param main
  *   The main program data.
- * @param command
- *   The parameter representing a command.
+ * @param action
+ *   The parameter representing a action.
  */
-#ifndef _di_control_print_error_parameter_command_rule_basename_empty_
-  extern void control_print_error_parameter_command_rule_basename_empty(fll_program_data_t * const main, const f_string_static_t command) F_attribute_visibility_internal_d;
-#endif // _di_control_print_error_parameter_command_rule_basename_empty_
+#ifndef _di_control_print_error_parameter_action_not_
+  extern void control_print_error_parameter_action_not(fll_program_data_t * const main, const f_string_static_t action) F_attribute_visibility_internal_d;
+#endif // _di_control_print_error_parameter_action_not_
 
 /**
- * Print an error message about the given parameter being a rule command having an empty rule directory path.
+ * Print an error message about the given parameter being a rule action having an empty rule basename.
  *
  * @param main
  *   The main program data.
- * @param command
- *   The parameter representing a command.
+ * @param action
+ *   The parameter representing a action.
  */
-#ifndef _di_control_print_error_parameter_command_rule_directory_empty_
-  extern void control_print_error_parameter_command_rule_directory_empty(fll_program_data_t * const main, const f_string_static_t command) F_attribute_visibility_internal_d;
-#endif // _di_control_print_error_parameter_command_rule_directory_empty_
+#ifndef _di_control_print_error_parameter_action_rule_basename_empty_
+  extern void control_print_error_parameter_action_rule_basename_empty(fll_program_data_t * const main, const f_string_static_t action) F_attribute_visibility_internal_d;
+#endif // _di_control_print_error_parameter_action_rule_basename_empty_
 
 /**
- * Print an error message about the given parameter being a rule command having an empty rule name.
+ * Print an error message about the given parameter being a rule action having an empty rule directory path.
  *
  * @param main
  *   The main program data.
- * @param command
- *   The parameter representing a command.
+ * @param action
+ *   The parameter representing a action.
  */
-#ifndef _di_control_print_error_parameter_command_rule_empty_
-  extern void control_print_error_parameter_command_rule_empty(fll_program_data_t * const main, const f_string_static_t command) F_attribute_visibility_internal_d;
-#endif // _di_control_print_error_parameter_command_rule_empty_
+#ifndef _di_control_print_error_parameter_action_rule_directory_empty_
+  extern void control_print_error_parameter_action_rule_directory_empty(fll_program_data_t * const main, const f_string_static_t action) F_attribute_visibility_internal_d;
+#endif // _di_control_print_error_parameter_action_rule_directory_empty_
 
 /**
- * Print an error message about the given parameter being a rule command but no rule name is specified.
+ * Print an error message about the given parameter being a rule action having an empty rule name.
  *
  * @param main
  *   The main program data.
- * @param command
- *   The parameter representing a command.
+ * @param action
+ *   The parameter representing a action.
  */
-#ifndef _di_control_print_error_parameter_command_rule_not_
-  extern void control_print_error_parameter_command_rule_not(fll_program_data_t * const main, const f_string_static_t command) F_attribute_visibility_internal_d;
-#endif // _di_control_print_error_parameter_command_rule_not_
+#ifndef _di_control_print_error_parameter_action_rule_empty_
+  extern void control_print_error_parameter_action_rule_empty(fll_program_data_t * const main, const f_string_static_t action) F_attribute_visibility_internal_d;
+#endif // _di_control_print_error_parameter_action_rule_empty_
 
 /**
- * Print an error message about the given parameter being a rule command having too many arguments passed.
+ * Print an error message about the given parameter being a rule action but no rule name is specified.
  *
  * @param main
  *   The main program data.
- * @param command
- *   The parameter representing a command.
+ * @param action
+ *   The parameter representing a action.
  */
-#ifndef _di_control_print_error_parameter_command_rule_too_many_
-  extern void control_print_error_parameter_command_rule_too_many(fll_program_data_t * const main, const f_string_static_t command) F_attribute_visibility_internal_d;
-#endif // _di_control_print_error_parameter_command_rule_too_many_
+#ifndef _di_control_print_error_parameter_action_rule_not_
+  extern void control_print_error_parameter_action_rule_not(fll_program_data_t * const main, const f_string_static_t action) F_attribute_visibility_internal_d;
+#endif // _di_control_print_error_parameter_action_rule_not_
+
+/**
+ * Print an error message about the given parameter being a rule action having too many arguments passed.
+ *
+ * @param main
+ *   The main program data.
+ * @param action
+ *   The parameter representing a action.
+ */
+#ifndef _di_control_print_error_parameter_action_rule_too_many_
+  extern void control_print_error_parameter_action_rule_too_many(fll_program_data_t * const main, const f_string_static_t action) F_attribute_visibility_internal_d;
+#endif // _di_control_print_error_parameter_action_rule_too_many_
 
 /**
  * Print an error message about the parameter's associated value being an empty string.
@@ -196,6 +212,20 @@ extern "C" {
   extern void control_print_signal_received(fll_program_data_t * const main, const f_status_t signal) F_attribute_visibility_internal_d;
 #endif // _di_control_print_signal_received_
 
+/**
+ * Print a warning message about a response header being repeated (when debugging).
+ *
+ * This program currently does not support multiple headers for any given valid header Object.
+ *
+ * @param main
+ *   The main program data.
+ * @param response_header
+ *   The repeated response header.
+ */
+#ifndef _di_control_print_warning_packet_header_duplicate_object_
+  extern void control_print_warning_packet_header_duplicate_object(fll_program_data_t * const main, const f_string_static_t response_header) F_attribute_visibility_internal_d;
+#endif // _di_control_print_warning_packet_header_duplicate_object_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 7af7025df8796f4b40392b336b19666414ddd2f1..8dc698b8b909db273bf3e22704087e3d4a66b172 100644 (file)
@@ -14,6 +14,7 @@ f_pipe
 f_print
 f_signal
 f_socket
+f_status_string
 fl_fss
 fl_print
 fl_string
@@ -21,3 +22,4 @@ fll_error
 fll_fss
 fll_print
 fll_program
+fll_status_string
index ceddc443be39aaf795bba207f8a9a4675d788b23..9be56e02aecf36009f2b719f4f42423c82fea2d4 100644 (file)
@@ -22,7 +22,7 @@ build_indexer ar
 build_indexer_arguments rcs
 build_language c
 build_libraries -lc
-build_libraries-individual -lfll_error -lfll_fss -lfll_print -lfll_program -lfl_conversion -lfl_fss -lfl_print -lfl_string -lf_color -lf_console -lf_conversion -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_socket -lf_status_string -lf_string -lf_type_array -lf_utf
+build_libraries-individual -lfll_error -lfll_fss -lfll_print -lfll_program -lfll_status_string -lfl_conversion -lfl_fss -lfl_print -lfl_string -lf_color -lf_console -lf_conversion -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_socket -lf_status_string -lf_string -lf_type_array -lf_utf
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 build_libraries_shared
index 5d45af82bc208b28407ae012e712b2b689687c14..c8aa7c9963e012fce80a1e4b14face85ccfa30b5 100644 (file)
@@ -50,6 +50,7 @@
 #include <fll/level_0/print.h>
 #include <fll/level_0/signal.h>
 #include <fll/level_0/socket.h>
+#include <fll/level_0/status_string.h>
 
 // FLL-1 includes.
 #include <fll/level_1/control_group.h>
@@ -71,6 +72,7 @@
 #include <fll/level_2/path.h>
 #include <fll/level_2/print.h>
 #include <fll/level_2/program.h>
+#include <fll/level_2/status_string.h>
 
 // Controller includes.
 #include <program/controller/common.h>
index 5c78ddf437449f8792ba5c75a63cd87aef37a1c9..2f31832890fc0ebdae3dda50a31acd8d01880a24 100644 (file)
@@ -46,7 +46,6 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_status if main thread is disabled and write lock was never achieved.
  *
  *   F_interrupt (with error bit set) on (exit) signal received, lock will not be set when this is returned.
  *
@@ -123,7 +122,6 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_status if main thread is disabled and write lock was never achieved.
  *
  *   F_interrupt (with error bit set) on (exit) signal received, lock will not be set when this is returned.
  *
index ddf1abe52f44b0e219f9b99d4e9c1e36d92c3036..cc047e03bf8196e31ab4078efeab782297a2638e 100644 (file)
@@ -23,6 +23,7 @@ f_pipe
 f_print
 f_signal
 f_socket
+f_status_string
 f_thread
 fl_control_group
 fl_conversion
@@ -38,3 +39,4 @@ fll_fss
 fll_path
 fll_print
 fll_program
+fll_status_string
index 67b7a5b674ee91192ef2324fc636120558f48609..ea1adf9842aa9f089a47e75779a7c5c7696c7522 100644 (file)
@@ -22,7 +22,7 @@ build_indexer ar
 build_indexer_arguments rcs
 build_language c
 build_libraries -lc -lcap
-build_libraries-individual -lfll_control_group -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_print -lfll_program
+build_libraries-individual -lfll_control_group -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_print -lfll_program -lfll_status_string
 build_libraries-individual -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_print -lfl_string
 build_libraries-individual -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_socket -lf_status_string -lf_string -lf_thread -lf_type_array -lf_utf
 build_libraries-level -lfll_2 -lfll_1 -lfll_0