From 16ea8f1dcc4486e75f0db2405dcf1589e848fa62 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Thu, 20 Nov 2025 22:48:26 -0600 Subject: [PATCH] Progress: Continue implementing controlfile and initfile support. 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. --- .../controller/example/controlfile/controlfile | 157 ++++++++++++++++++++- data/data/controller/example/controlfile/initfile | 62 ++++---- documents/controlfile.txt | 15 +- sources/c/program/controller/controller/main.c | 6 + sources/c/program/controller/init/main.c | 6 + sources/c/program/controller/main/common/define.h | 10 +- sources/c/program/controller/main/common/string.h | 6 +- sources/c/program/controller/main/entry.c | 36 +++-- .../c/program/controller/main/entry/preprocess.c | 10 +- .../c/program/controller/main/entry/preprocess.h | 2 + sources/c/program/controller/main/entry/process.c | 10 +- sources/c/program/controller/main/entry/process.h | 1 + .../controller/main/print/message/entry/item.c | 2 +- sources/c/program/controller/main/process.c | 4 +- sources/c/program/controller/main/rule/instance.c | 7 +- sources/c/program/controller/main/rule/read.c | 43 +++++- sources/c/program/controller/main/thread/entry.c | 2 - specifications/controlfile.txt | 22 +-- 18 files changed, 314 insertions(+), 87 deletions(-) diff --git a/data/data/controller/example/controlfile/controlfile b/data/data/controller/example/controlfile/controlfile index bdec963..68fa31a 100644 --- a/data/data/controller/example/controlfile/controlfile +++ b/data/data/controller/example/controlfile/controlfile @@ -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 ${*} + } diff --git a/data/data/controller/example/controlfile/initfile b/data/data/controller/example/controlfile/initfile index 465d429..4e07a8a 100644 --- a/data/data/controller/example/controlfile/initfile +++ b/data/data/controller/example/controlfile/initfile @@ -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 diff --git a/documents/controlfile.txt b/documents/controlfile.txt index a62a6dd..614e92d 100644 --- a/documents/controlfile.txt +++ b/documents/controlfile.txt @@ -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"). diff --git a/sources/c/program/controller/controller/main.c b/sources/c/program/controller/controller/main.c index 2877989..3299c3f 100644 --- a/sources/c/program/controller/controller/main.c +++ b/sources/c/program/controller/controller/main.c @@ -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); diff --git a/sources/c/program/controller/init/main.c b/sources/c/program/controller/init/main.c index df289e3..343a2aa 100644 --- a/sources/c/program/controller/init/main.c +++ b/sources/c/program/controller/init/main.c @@ -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); diff --git a/sources/c/program/controller/main/common/define.h b/sources/c/program/controller/main/common/define.h index 144aa79..2cf41ba 100644 --- a/sources/c/program/controller/main/common/define.h +++ b/sources/c/program/controller/main/common/define.h @@ -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 diff --git a/sources/c/program/controller/main/common/string.h b/sources/c/program/controller/main/common/string.h index 9ab5a67..493749e 100644 --- a/sources/c/program/controller/main/common/string.h +++ b/sources/c/program/controller/main/common/string.h @@ -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 diff --git a/sources/c/program/controller/main/entry.c b/sources/c/program/controller/main/entry.c index c0f92d2..06f31ed 100644 --- a/sources/c/program/controller/main/entry.c +++ b/sources/c/program/controller/main/entry.c @@ -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); + } } } diff --git a/sources/c/program/controller/main/entry/preprocess.c b/sources/c/program/controller/main/entry/preprocess.c index b714c03..1ca20b7 100644 --- a/sources/c/program/controller/main/entry/preprocess.c +++ b/sources/c/program/controller/main/entry/preprocess.c @@ -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); diff --git a/sources/c/program/controller/main/entry/preprocess.h b/sources/c/program/controller/main/entry/preprocess.h index dc3f975..6fd1b86 100644 --- a/sources/c/program/controller/main/entry/preprocess.h +++ b/sources/c/program/controller/main/entry/preprocess.h @@ -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. * diff --git a/sources/c/program/controller/main/entry/process.c b/sources/c/program/controller/main/entry/process.c index 18dff57..d68110e 100644 --- a/sources/c/program/controller/main/entry/process.c +++ b/sources/c/program/controller/main/entry/process.c @@ -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); diff --git a/sources/c/program/controller/main/entry/process.h b/sources/c/program/controller/main/entry/process.h index db4bf50..e49ac49 100644 --- a/sources/c/program/controller/main/entry/process.h +++ b/sources/c/program/controller/main/entry/process.h @@ -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. diff --git a/sources/c/program/controller/main/print/message/entry/item.c b/sources/c/program/controller/main/print/message/entry/item.c index 23b1bb6..7f1509e 100644 --- a/sources/c/program/controller/main/print/message/entry/item.c +++ b/sources/c/program/controller/main/print/message/entry/item.c @@ -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); diff --git a/sources/c/program/controller/main/process.c b/sources/c/program/controller/main/process.c index f924646..08930bf 100644 --- a/sources/c/program/controller/main/process.c +++ b/sources/c/program/controller/main/process.c @@ -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)) { diff --git a/sources/c/program/controller/main/rule/instance.c b/sources/c/program/controller/main/rule/instance.c index f824bd7..1488068 100644 --- a/sources/c/program/controller/main/rule/instance.c +++ b/sources/c/program/controller/main/rule/instance.c @@ -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? diff --git a/sources/c/program/controller/main/rule/read.c b/sources/c/program/controller/main/rule/read.c index 2505420..2429518 100644 --- a/sources/c/program/controller/main/rule/read.c +++ b/sources/c/program/controller/main/rule/read.c @@ -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)); diff --git a/sources/c/program/controller/main/thread/entry.c b/sources/c/program/controller/main/thread/entry.c index 87f5f5e..5da22a9 100644 --- a/sources/c/program/controller/main/thread/entry.c +++ b/sources/c/program/controller/main/thread/entry.c @@ -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; } diff --git a/specifications/controlfile.txt b/specifications/controlfile.txt index ab904bd..3feecbd 100644 --- a/specifications/controlfile.txt +++ b/specifications/controlfile.txt @@ -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. -- 1.8.3.1