]> Kevux Git Server - controller/commitdiff
Progress: Continue implementing controlfile and initfile support.
authorKevin Day <Kevin@kevux.org>
Fri, 21 Nov 2025 04:48:26 +0000 (22:48 -0600)
committerKevin Day <Kevin@kevux.org>
Fri, 21 Nov 2025 04:48:26 +0000 (22:48 -0600)
I've decided that the separator should be `/` instead of `_`.

This makes the translation to/from a flat control file to the hierarcal directory structure more straight forward.

Add the initial file load and wrap up most of the processing code.

The Rules still need to be processed.
The handling of the collapsed name needs to be implemented.

I've noticed that I don't have any string match functions in FLL.
I have string comparison functions, but these are not really match functions.
Or more precisely, the string comparison functions are exact matches for both strings.

18 files changed:
data/data/controller/example/controlfile/controlfile
data/data/controller/example/controlfile/initfile
documents/controlfile.txt
sources/c/program/controller/controller/main.c
sources/c/program/controller/init/main.c
sources/c/program/controller/main/common/define.h
sources/c/program/controller/main/common/string.h
sources/c/program/controller/main/entry.c
sources/c/program/controller/main/entry/preprocess.c
sources/c/program/controller/main/entry/preprocess.h
sources/c/program/controller/main/entry/process.c
sources/c/program/controller/main/entry/process.h
sources/c/program/controller/main/print/message/entry/item.c
sources/c/program/controller/main/process.c
sources/c/program/controller/main/rule/instance.c
sources/c/program/controller/main/rule/read.c
sources/c/program/controller/main/thread/entry.c
specifications/controlfile.txt

index bdec963a20ec861474f3f76490d4cfdeaeabd5ad..68fa31a30445a94be85fa4d74b076e9b520cadc2 100644 (file)
@@ -11,7 +11,7 @@
 #   - miscellaneous/rules/serial/s_6.rule
 #
 
-entry_main:
+entry/main:
   consider serial s_1
   consider serial s_2
   consider serial s_3
@@ -22,7 +22,7 @@ entry_main:
 
   ready
 
-exit_main:
+exit/main:
   consider serial s_1
   consider serial s_2
   consider serial s_3
@@ -34,11 +34,11 @@ exit_main:
 
   ready
 
-rule_serial_s_1_settings:
+rule/serial/s_1/settings:
   name "Serial 1"
   on stop need serial s_2
 
-rule_serial_s_1_script:
+rule/serial/s_1/script:
   start {
     main() {
       local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
@@ -62,3 +62,152 @@ rule_serial_s_1_script:
 
     main ${*}
   }
+
+rule/serial/s_2/settings:
+  name "Serial 2"
+  on start need serial s_1
+  on stop need serial s_3
+
+rule/serial/s_2/script:
+  start {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 2: sleeping $(date -u)"
+      sleep 1
+      echo "Serial 2: slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
+
+  stop {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 2: stopping, sleeping $(date -u)"
+      sleep 1
+      echo "Serial 2: stopping, slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
+
+rule/serial/s_3/settings:
+  name "Serial 3"
+  on start need serial s_2
+  on stop need serial s_4
+
+rule/serial/s_3/script:
+  start {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 3: sleeping $(date -u)"
+      sleep 1
+      echo "Serial 3: slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
+
+  stop {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 3: stopping, sleeping $(date -u)"
+      sleep 1
+      echo "Serial 3: stopping, slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
+
+rule/serial/s_4/settings:
+  name "Serial 4"
+  on start need serial s_3
+  on stop need serial s_5
+
+rule/serial/s_4/script:
+  start {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 4: sleeping $(date -u)"
+      sleep 1
+      echo "Serial 4: slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
+
+  stop {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 4: stopping, sleeping $(date -u)"
+      sleep 1
+      echo "Serial 4: stopping, slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
+
+rule/serial/s_5/settings:
+  name "Serial 5"
+  on start need serial s_4
+  on stop need serial s_6
+
+rule/serial/s_5/script:
+  start {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 5: sleeping $(date -u)"
+      sleep 1
+      echo "Serial 5: slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
+
+  stop {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 5: stopping, sleeping $(date -u)"
+      sleep 1
+      echo "Serial 5: stopping, slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
+
+rule/serial/s_6/settings:
+  name "Serial 6"
+  on start need serial s_5
+
+rule/serial/s_6/script:
+  start {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 6: sleeping $(date -u)"
+      sleep 1
+      echo "Serial 6: slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
+
+  stop {
+    main() {
+      local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
+
+      echo "Serial 6: stopping, sleeping $(date -u)"
+      sleep 1
+      echo "Serial 6: stopping, slept    $(date -u)"
+    \}
+
+    main ${*}
+  }
index 465d4295bfba806f391e21b677eedd41b3072916..4e07a8a0ef1ffe18892ee2e87242d373c5c44079 100644 (file)
@@ -3,7 +3,7 @@
 # Example initfile based on the init/entries/default.entry and many of its related files.
 #
 
-entry_settings:
+entry/settings:
   pid ready
   show init
 
@@ -12,7 +12,7 @@ entry_settings:
   control_group 0
   control_mode ug+rwx,o-rwx
 
-entry_main:
+entry/main:
   timeout start 7
   timeout stop 7
   timeout kill 3
@@ -22,7 +22,7 @@ entry_main:
   item boot
   item console
 
-entry_boot:
+entry/boot:
   start boot root require
   start boot proc asynchronous require
   start boot devices asynchronous require
@@ -31,7 +31,7 @@ entry_boot:
 
   ready
 
-entry_console:
+entry/console:
   start service mouse asynchronous
 
   start terminal two asynchronous
@@ -39,17 +39,17 @@ entry_console:
   start terminal four asynchronous
   start terminal one require wait
 
-entry_maintenance:
+entry/maintenance:
   # TODO: Support IKI variables for certain env data, such as an architecture path (thus '/bin[environment:"architecture_path"]/bash'). with some compilation built ins, or maybe have settings support calling programs to populate variables, like '/bin[variable:"architecture_path"]/bash'.
   # TODO: There could even be settings, entries, and exits to support for calling and processing custom, named, functions built into the source code.
   execute /bin/bash --login
 
-rule_boot_devices_settings:
+rule/boot/devices/settings:
   name "Setup /dev file system"
 
   on start need boot root
 
-rule_boot_devices_script:
+rule/boot/devices/script:
   start {
     main() {
       local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
@@ -68,11 +68,11 @@ rule_boot_devices_script:
     main ${*}
   }
 
-rule_boot_devices_command:
+rule/boot/devices/command:
   start mount /dev/pts
   stop umount -l /dev/pts
 
-rule_boot_devices_command:
+rule/boot/devices/command:
   start mount /dev/shm
   stop umount -l /dev/shm
 
@@ -86,15 +86,15 @@ rule_boot_file_system_settings:
   on stop need boot proc
   on stop need boot devices
 
-rule_boot_file_system_command:
+rule/boot/file_system/command:
   start mount -n -a -O no_netdev
   stop umount -n -arf -O no_netdev
 
-rule_boot_file_system_command:
+rule/boot/file_system/command:
   start swapon -a
   stop swapoff -a
 
-rule_boot_file_system_script:
+rule/boot/file_system/script:
   start {
     main() {
       local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
@@ -107,14 +107,14 @@ rule_boot_file_system_script:
     main ${*}
   }
 
-rule_boot_modules_settings:
+rule/boot/modules/settings:
   name "Setup Kernel Modules"
 
   on start need boot root
   on start need boot proc
   on start want boot filesystem
 
-rule_boot_modules_script:
+rule/boot/modules/script:
   start {
     main() {
       local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
@@ -137,15 +137,15 @@ rule_boot_modules_script:
     main ${*}
   }
 
-rule_boot_proc_settings:
+rule/boot/proc/settings:
   name "Setup /proc Filesystem"
 
   on start need boot root
 
-rule_boot_proc_command:
+rule/boot/proc/command:
   start mount /proc
 
-rule_boot_proc_script:
+rule/boot/proc/script:
   start {
     main() {
       local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
@@ -174,13 +174,13 @@ rule_boot_proc_script:
     main ${*}
   }
 
-rule_boot_root_settings:
+rule/boot/root/settings:
   name "Setup Root Filesystem"
 
-rule_boot_root_command:
+rule/boot/root/command:
   start mount -o remount,rw /
 
-rule_boot_root_script:
+rule/boot/root/script:
   start {
     main() {
       local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
@@ -198,12 +198,12 @@ rule_boot_root_script:
     main ${*}
   }
 
-rule_service_mouse_settings:
+rule/service/mouse/settings:
   name "Console Mouse"
   capability all=
   nice 15
 
-rule_service_mouse_script:
+rule/service/mouse/script:
   start {
     main() {
       local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope.
@@ -217,42 +217,42 @@ rule_service_mouse_script:
     main ${*}
   }
 
-rule_service_mouse_service:
+rule/service/mouse/service:
   pid_file /var/run/mouse/mouse.pid
 
   start gpm -m variable:"device" -t variable:"protocol" variable:"options"
 
-rule_terminal_one_settings:
+rule/terminal/one/settings:
   name "System Terminal 1"
 
-rule_terminal_one_command:
+rule/terminal/one/command:
   start agetty -8 -i -J - linux
 
   rerun start success delay 1000 reset
   rerun start failure delay 5000
 
-rule_terminal_two_settings:
+rule/terminal/two/settings:
   name "System Terminal 2"
 
-rule_terminal_two_command:
+rule/terminal/two/command:
   start agetty -8 tty2 linux
 
   rerun start success delay 1000 reset
   rerun start failure delay 5000 max 100
 
-rule_terminal_three_settings:
+rule/terminal/three/settings:
   name "System Terminal 3"
 
-rule_terminal_three_command:
+rule/terminal/three/command:
   start agetty -8 tty3 linux
 
   rerun start success delay 1000 reset
   rerun start failure delay 5000 max 100
 
-rule_terminal_four_settings:
+rule/terminal/four/settings:
   name "System Terminal 4"
 
-rule_terminal_four_command:
+rule/terminal/four/command:
   start agetty -8 tty4 linux
 
   rerun start success delay 1000 reset
index a62a6ddaa202f50eff3f559ab9a4a1333865347d..614e92d68d5e671e3db97a4dd921ef174dbe6479 100644 (file)
@@ -1,7 +1,7 @@
 # fss-0002 iki-0000
 #
 # license: open-standard-license-1.0-or-later
-# version 2025/11/17
+# version 2025/11/21
 #
 # This file (assumed to be named controlfile.txt) can be more easily read using the following iki_read commands:
 #   iki_read controlfile.txt +Q -w -WW code '"' '"' file '"' '"'
@@ -18,7 +18,14 @@ Control File Documentation:
   The goal of of a control file is to collapse the directory hierarchy structure into a single file.
   This imposes no new Objects or other structures.
 
-  Any modifications, or deviations, from this standard that add additional things beyond the entry, exit, and rule are encouraged to follow the naming prefix pattern.
-  The naming pattern is the simple standard name, like code:"entry", code:"exit", or code:"rule", followed by an underscore as a prefix.
+  Any modifications, or deviations, from this standard that add additional things beyond the bold:"Entry", bold:"Exit", and bold:"Rule" are encouraged to follow the naming prefix pattern.
+  The naming pattern is the simple standard name, like code:"entry", code:"exit", or code:"rule" followed by a forward slash (unicode:"U+002F") as a prefix.
   Then all Object names would then have that prefix.
-  For example if there were a specification called file:"system" with an Object called code:"power_on" at the top level, then the control file representation would be code:"system_power_on".
+
+  For example, if there is an bold:"Entry" named code:"main", then the control file representation would be code:"entry/main".
+
+  A bold:"Rule", in addition, also has the directory path part appended (where only a forward slash (unicode:"U+002F") is allowed to represent a directory separation) followed by a forward slash (unicode:"U+002F") as part of the prefix.
+
+  For example, if there is an bold:"Rule" named code:"one" from a directory named code:"terminal" with a bold:"Script", then the control file representation would be code:"rule/terminal/one/script".
+
+  Due to the use of a forward slash (unicode:"U+002F"), bold:"Item" names for an bold:"Entry" or a bold:"Rule" should avoid using a forward slash (unicode:"U+002F").
index 2877989114a029762f6446ebc813c8d47d82e216..3299c3f57c7e696ebdd6a76374d701e68cd6b651 100644 (file)
@@ -39,6 +39,12 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) {
     const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
 
     controller_setting_load(arguments, &data);
+
+    #ifdef _support_controller_controlfile_
+      if (f_file_exists(controller_controlfile_s, F_false) == F_true) {
+        data.setting.flag |= controller_main_flag_single_d;
+      }
+    #endif // _support_controller_controlfile_
   }
 
   const f_status_t status = controller_process(&data);
index df289e39793f5539f310cb937102e1aca1696347..343a2aa1eb8bbe05021eca7f713303c07932fd58 100644 (file)
@@ -42,6 +42,12 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) {
     const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
 
     controller_setting_load(arguments, &data);
+
+    #ifdef _support_controller_controlfile_
+      if (f_file_exists(controller_controlfile_s, F_false) == F_true) {
+        data.setting.flag |= controller_main_flag_single_d;
+      }
+    #endif // _support_controller_controlfile_
   }
 
   const f_status_t status = controller_process(&data);
index 144aa7919b4c3d59762cc3c2fa3d3155c924a5cc..2cf41bafcf8af70acb9a2104214131d71660a315 100644 (file)
@@ -87,10 +87,10 @@ extern "C" {
  *   - fine:                   Check if status is "fine".
  *   - help:                   Print help.
  *   - interruptible:          The process is interruptible.
- *   - loaded:                 Designate that the files are all loaded (generally only set when a controlfile exists and is loaded).
  *   - pid:                    Designate that a custom PID is specified.
  *   - pipe:                   Use the input pipe.
  *   - simulate:               Perform simulation of rules rather than execution.
+ *   - single:                 Designate that a single file is being used (generally only set when a controlfile/initfile is found).
  *   - validate:               Perform validation of rules rather than execution.
  *   - version:                Print version.
  *   - version_copyright_help: A helper flag representing version, copyright, and help flag bits being set.
@@ -103,10 +103,10 @@ extern "C" {
   #define controller_main_flag_fine_d                   0x8
   #define controller_main_flag_help_d                   0x10
   #define controller_main_flag_interruptible_d          0x20
-  #define controller_main_flag_loaded_d                 0x40
-  #define controller_main_flag_pid_d                    0x80
-  #define controller_main_flag_pipe_d                   0x100
-  #define controller_main_flag_simulate_d               0x200
+  #define controller_main_flag_pid_d                    0x40
+  #define controller_main_flag_pipe_d                   0x80
+  #define controller_main_flag_simulate_d               0x100
+  #define controller_main_flag_single_d                 0x200
   #define controller_main_flag_validate_d               0x400
   #define controller_main_flag_version_d                0x800
   #define controller_main_flag_version_copyright_help_d 0x811
index 9ab5a67da718b000d85318e7b6cd414e791f1f93..493749e2adeb7f25584f5c5a987d7e685b770713 100644 (file)
@@ -61,9 +61,9 @@ extern "C" {
  * The controller_controlfile_s implementation is defined within the individual programs.
  */
 #ifndef _di_controller_controlfile_s_
-  #define CONTROLLER_prefix_entry_s "entry_"
-  #define CONTROLLER_prefix_exit_s  "exit_"
-  #define CONTROLLER_prefix_rule_s  "rule_"
+  #define CONTROLLER_prefix_entry_s "entry/"
+  #define CONTROLLER_prefix_exit_s  "exit/"
+  #define CONTROLLER_prefix_rule_s  "rule/"
 
   #define CONTROLLER_prefix_entry_s_length 6
   #define CONTROLLER_prefix_exit_s_length  5
index c0f92d209b0a769ae0ed1e086245a7cc94fcb2e2..06f31ed95b1e73e7c796a894241ae358912b3f9e 100644 (file)
@@ -67,16 +67,28 @@ extern "C" {
           // Process the entry or exit items normally, but if pre-loaded (as with controlfile or initfile), then only process if the proper prefix is present.
           offset = main->thread.cache.object_items.array[i];
 
-          if (main->setting.flag & controller_main_flag_loaded_d) {
-            if (f_compare_dynamic_partial(main->thread.cache.buffer_file, prefix, offset, prefix_range) != F_equal_to) continue;
+          if (main->setting.flag & controller_main_flag_single_d) {
+            entry->status = F_equal_to;
 
-            // Determine the next range position, skipping past any NULL characters.
+            // Perform match while skipping past the prefix.
             for (j = 0; offset.start <= offset.stop && j < prefix.used; ++offset.start) {
 
               if (!main->thread.cache.buffer_file.string[offset.start]) continue;
 
+              for (; j < prefix.used && !prefix.string[j]; ++j) {
+                // Do nothing.
+              } // for
+
+              if (main->thread.cache.buffer_file.string[offset.start] != prefix.string[j]) {
+                entry->status = F_equal_to_not;
+
+                break;
+              }
+
               ++j;
             } // for
+
+            if (entry->status == F_equal_to_not) continue;
           }
 
           state.status = f_string_dynamic_partial_append(main->thread.cache.buffer_file, offset, &main->thread.cache.action.name_item);
@@ -290,7 +302,7 @@ extern "C" {
       status = controller_entry_setup(main, is_entry ? &main->process.entry : &main->process.exit);
     }
 
-    if (F_status_is_error_not(status) && !(main->setting.flag & controller_main_flag_loaded_d)) {
+    if (F_status_is_error_not(status)) {
       status = controller_entry_load(main, is_entry);
     }
 
@@ -328,14 +340,16 @@ extern "C" {
     main->thread.cache.comments.used = 0;
     main->thread.cache.delimits.used = 0;
 
-    main->thread.cache.buffer_file.used = 0;
+    if (!(main->setting.flag & controller_main_flag_single_d)) {
+      main->thread.cache.buffer_file.used = 0;
 
-    if (F_status_is_error_not(state.status)) {
-      if (is_entry) {
-        state.status = controller_file_load(main, F_true, controller_entries_s, main->process.name_entry, controller_entry_s);
-      }
-      else {
-        state.status = controller_file_load(main, F_false, controller_exits_s, main->process.name_entry, controller_exit_s);
+      if (F_status_is_error_not(state.status)) {
+        if (is_entry) {
+          state.status = controller_file_load(main, F_true, controller_entries_s, main->process.name_entry, controller_entry_s);
+        }
+        else {
+          state.status = controller_file_load(main, F_false, controller_exits_s, main->process.name_entry, controller_exit_s);
+        }
       }
     }
 
index b714c036ad27a93e5f2d34de7d3cd135cc18a98f..1ca20b748c1ac8a2b2665c109be999e7c9b195db 100644 (file)
@@ -12,7 +12,6 @@ extern "C" {
 
     f_number_unsigned_t i = 0;
     f_number_unsigned_t j = 0;
-
     f_number_unsigned_t at_i = 0;
     f_number_unsigned_t at_j = 1;
 
@@ -22,15 +21,20 @@ extern "C" {
 
     uint8_t error_has = F_false;
 
+    if (!entry->items.used) {
+      main->process.ready = controller_process_ready_yes_e;
+
+      return F_data_not;
+    }
+
     // This effectively sets the read for an Entry and resets the ready for an Exit.
     main->process.ready = controller_process_ready_no_e;
 
-    cache->ats.used = 0;
-
     cache->action.line_action = 0;
     cache->action.line_item = 0;
     cache->action.name_action.used = 0;
     cache->action.name_item.used = 0;
+    cache->ats.used = 0;
 
     if (cache->ats.size < 2) {
       status = f_memory_array_resize(2, sizeof(f_number_unsigned_t), (void **) &cache->ats.array, &cache->ats.used, &cache->ats.size);
index dc3f97584b136664b4b344b921b80f98d16556aa..6fd1b867f4cdc65be94c311f0f3ee1807b66ab55 100644 (file)
@@ -29,6 +29,8 @@ extern "C" {
  *
  * @return
  *   F_okay on success.
+ *   F_data_not on success but there are no items.
+ *
  *   F_recurse (with error bit) on a recursion error.
  *   F_valid_not (with error bit) on invalid Entry Item, Entry Item Action, or Entry Item Action value.
  *
index 18dff57975edb672d2910890e961e9ab2c9ccc7c..d68110ee19f1d1faa771d0aa261ce8c13f977dfa 100644 (file)
@@ -21,17 +21,17 @@ extern "C" {
     controller_entry_action_t *entry_action = 0;
     controller_entry_actions_t *entry_actions = 0;
 
+    if (!entry->items.used) return F_data_not;
+
     // An empty stack is used here because each Rule here is the first Rule run in the Rule's scope.
     const controller_rules_t stack = controller_rules_t_initialize;
 
-    cache->ats.used = 0;
-    cache->stack.used = 0;
-
-    // @todo Should this have a separate cache for entries and rules (this is important if/when an exit is running while rules are running)?
     cache->action.line_action = 0;
     cache->action.line_item = 0;
     cache->action.name_action.used = 0;
     cache->action.name_item.used = 0;
+    cache->ats.used = 0;
+    cache->stack.used = 0;
 
     if (cache->ats.size < 2) {
       status = f_memory_array_resize(2, sizeof(f_number_unsigned_t), (void **) &cache->ats.array, &cache->ats.used, &cache->ats.size);
@@ -215,7 +215,7 @@ extern "C" {
 
           // The Rule is not yet loaded, ensure that it is loaded (but not when using controlfile/initfile).
           if (status != F_true) {
-            if (main->setting.flag & controller_main_flag_loaded_d) {
+            if (main->setting.flag & controller_main_flag_single_d) {
               status = F_status_set_error(F_load_not);
 
               controller_print_error_entry_action_missing_rule(&main->program.error, &main->thread.cache.action, is_entry, alias_rule, F_status_debug_source_d);
index db4bf509f27d37e6171d149532541872e3f593d1..e49ac49c01dee92dc3e1aa59ca86a558eec4b5dd 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
  *
  * @return
  *   F_okay on success.
+ *   F_data_not on no items to process.
  *   F_execute on success and program exiting (scripts may result in this) or when execute would have been executed but is instead simulated.
  *
  *   F_require (with error bit) if a required Item failed.
index 23b1bb6be661ee8fba16aad0042567c59f70606b..7f1509e58a3daf6bc1b035381b8759cb57722a3c 100644 (file)
@@ -87,7 +87,7 @@ extern "C" {
 
     controller_lock_print(print->to, &main->thread);
 
-    fl_print_format("%r%[%QThe required %r item '%]", print->to, f_string_eol_s, print->context, print->prefix, is_entry ? controller_entry_s : controller_exit_s);
+    fl_print_format("%r%[%QThe required %r item '%]", print->to, f_string_eol_s, print->context, print->prefix, is_entry ? controller_entry_s : controller_exit_s, print->context);
     fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->title, name, print->set->title);
     fl_print_format("' %Q.", print->to, reason, f_string_eol_s);
 
index f9246463673a916e9e2d20f373940df603a34803..08930bfbb2ee70f9bfdf1524652b62d78397601f 100644 (file)
@@ -63,7 +63,9 @@ extern "C" {
       }
       else {
         #ifdef _support_controller_controlfile_
-          status = controller_file_load_controlfile(main); // @todo the main program needs to check if the controlfile exists and do not error when no entry is specified, a custom settings path can be used to override the location of the controlfile of PWD.
+          if (main->setting.flag & controller_main_flag_single_d) {
+            status = controller_file_load_controlfile(main);
+          }
         #endif // _support_controller_controlfile_
 
         if (F_status_is_error_not(status)) {
index f824bd7f0e1ad7d46dea47cc61f678d2ee590c28..1488068b36c1274cb625ecbc57b624b69df37be2 100644 (file)
@@ -497,7 +497,6 @@ extern "C" {
     instance->cache.content_items.used = 0;
     instance->cache.object_actions.used = 0;
     instance->cache.object_items.used = 0;
-    instance->cache.buffer_file.used = 0;
     instance->cache.buffer_item.used = 0;
     instance->cache.buffer_path.used = 0;
     instance->cache.expanded.used = 0;
@@ -512,6 +511,10 @@ extern "C" {
     instance->cache.timestamp.seconds = 0;
     instance->cache.timestamp.seconds_nano = 0;
 
+    if (!(main->setting.flag & controller_main_flag_single_d)) {
+      instance->cache.buffer_file.used = 0;
+    }
+
     instance->stack.used = 0;
 
     instance->main = (void *) main;
@@ -677,7 +680,7 @@ extern "C" {
     if (status == F_child) return status;
 
     if (F_status_set_fine(status) == F_lock) {
-      rule->status[instance->action] = status; // @todo Probably should establish r/w use locks on rule; add appropriate locks to rule structure and handle appropriately.
+      rule->status[instance->action] = status;
     }
 
     // @todo Why are F_lock and related being converted into F_interrupt?
index 2505420fa33b0e2799f85b87c0a9262f4aaddec9..242951845ef181ef84d6d6b4765539f6508764f2 100644 (file)
@@ -9,7 +9,7 @@ extern "C" {
 
     if (!main || !cache || !entry || !rule) return F_status_set_error(F_parameter);
 
-    bool for_item = F_true;
+    uint8_t for_item = F_true;
 
     rule->timeout_kill = entry->timeout_kill ? entry->timeout_kill : 0;
     rule->timeout_start = entry->timeout_start ? entry->timeout_start : 0;
@@ -64,7 +64,10 @@ extern "C" {
     cache->comments.used = 0;
     cache->delimits.used = 0;
 
-    cache->buffer_file.used = 0;
+    if (!(main->setting.flag & controller_main_flag_single_d)) {
+      cache->buffer_file.used = 0;
+    }
+
     cache->buffer_item.used = 0;
     cache->buffer_path.used = 0;
 
@@ -98,6 +101,7 @@ extern "C" {
       } // for
 
       for (i = 0; i < rule->ons.size; ++i) {
+
         rule->ons.array[i].need.used = 0;
         rule->ons.array[i].want.used = 0;
         rule->ons.array[i].wish.used = 0;
@@ -173,7 +177,7 @@ extern "C" {
       controller_print_error_status(&main->program.error, F_status_debug_source_d, F_status_set_fine(state.status));
     }
     else {
-      if (!(main->setting.flag & controller_main_flag_loaded_d)) {
+      if (!(main->setting.flag & controller_main_flag_single_d)) {
         state.status = controller_file_load(main, F_true, controller_rules_s, rule->alias, controller_rule_s);
 
         if (F_status_is_error_not(state.status)) {
@@ -210,8 +214,12 @@ extern "C" {
       else {
         f_number_unsigned_t i = 0;
         f_number_unsigned_t j = 0;
+
+        f_range_t offset = f_range_t_initialize;
         f_state_t state = f_state_t_initialize;
 
+        const f_range_t prefix_range = macro_f_range_t_initialize_2(controller_prefix_rule_s.used);
+
         for (; i < cache->object_items.used; ++i) {
 
           cache->action.line_item = 0;
@@ -250,7 +258,34 @@ extern "C" {
 
           rule->items.array[rule->items.used].line = ++cache->action.line_item;
 
-          state.status = f_rip_dynamic_partial_nulless(cache->buffer_file, cache->object_items.array[i], &cache->action.name_item);
+          // Process the entry or exit items normally, but if pre-loaded (as with controlfile or initfile), then only process if the proper prefix is present.
+          offset = cache->object_items.array[i];
+
+          if (main->setting.flag & controller_main_flag_single_d) {
+            entry->status = F_equal_to;
+
+            // Perform match while skipping past the controller_prefix_rule_s.
+            for (j = 0; offset.start <= offset.stop && j < controller_prefix_rule_s.used; ++offset.start) {
+
+              if (!cache->buffer_file.string[offset.start]) continue;
+
+              for (; j < controller_prefix_rule_s.used && !controller_prefix_rule_s.string[j]; ++j) {
+                // Do nothing.
+              } // for
+
+              if (cache->buffer_file.string[offset.start] != controller_prefix_rule_s.string[j]) {
+                entry->status = F_equal_to_not;
+
+                break;
+              }
+
+              ++j;
+            } // for
+
+            if (entry->status == F_equal_to_not) continue;
+          }
+
+          state.status = f_rip_dynamic_partial_nulless(cache->buffer_file, offset, &cache->action.name_item);
 
           if (F_status_is_error(state.status)) {
             controller_print_error_status(&main->program.error, F_status_debug_source_d, F_status_set_fine(state.status));
index 87f5f5e7b35ee78675fe7cb59cbc998566778808..5da22a9ff85a09ad78a11e8e11aefee940447d6f 100644 (file)
@@ -25,8 +25,6 @@ extern "C" {
       *status = controller_entry_read(main, F_false);
     }
 
-    // @todo pre-load all rule files? find all rules in the entry files and exit files and then load them?
-
     if (F_status_set_fine(*status) == F_interrupt) {
       main->process.ready = controller_process_ready_abort_e;
     }
index ab904bddd7168f0822d4cd209049897e393a64bf..3feecbd3d1fe53b08b72948825174dd08acbde2f 100644 (file)
@@ -1,7 +1,7 @@
 # fss-0002 iki-0000
 #
 # license: open-standard-license-1.0-or-later
-# version 2025/11/17
+# version 2025/11/21
 #
 # This file (assumed to be named controlfile.txt) can be more easily read using the following iki_read commands:
 #   iki_read controlfile.txt +Q -w -WW code '"' '"' file '"' '"'
@@ -21,18 +21,18 @@ Controlfile Specification:
   The names of the Objects are as follows.
 
   For file:"entry.txt":
-    - The code:"main" is now called code:"entry_main".
-    - The code:"settings" is now called code:"entry_settings".
+    - The code:"main" is now called code:"entry/main".
+    - The code:"settings" is now called code:"entry/settings".
 
   For file:"exit.txt":
-    - The code:"main" is now called code:"exit_main".
-    - The code:"settings" is now called code:"exit_settings".
+    - The code:"main" is now called code:"exit/main".
+    - The code:"settings" is now called code:"exit/settings".
 
-  For file:"rule.txt":
-    - The code:"command" is now called code:"rule_command".
-    - The code:"script" is now called code:"rule_script".
-    - The code:"service" is now called code:"rule_service".
-    - The code:"settings" is now called code:"rule_settings".
-    - The code:"utility" is now called code:"rule_utility".
+  For file:"rule.txt" (whose bold:"Rule" with a name of code:"my_rule" is under the path code:"directory"):
+    - The code:"command" is now called code:"rule/directory/my_rule/command".
+    - The code:"script" is now called code:"rule/directory/my_rule/script".
+    - The code:"service" is now called code:"rule/directory/my_rule/service".
+    - The code:"settings" is now called code:"rule/directory/my_rule/settings".
+    - The code:"utility" is now called code:"rule/directory/my_rule/utility".
 
   Any additional specifications brought in are be expected to follow the same pattern for combining.