]> Kevux Git Server - controller/commitdiff
Update: Initial import of the project with a skeleton based off of the example project.
authorKevin Day <kevin@kevux.org>
Wed, 20 Mar 2024 03:15:23 +0000 (22:15 -0500)
committerKevin Day <kevin@kevux.org>
Wed, 20 Mar 2024 03:15:23 +0000 (22:15 -0500)
This has some initial files copied over from the controller program from the fll project.

100 files changed:
bootstrap.sh [new file with mode: 0755]
build/documentation/man/man1/controller.1 [new file with mode: 0644]
build/documentation/man/man5/controller-actions.5 [new file with mode: 0644]
build/documentation/man/man5/controller-entry.5 [new file with mode: 0644]
build/documentation/man/man5/controller-exit.5 [new file with mode: 0644]
build/documentation/man/man5/controller-packet.5 [new file with mode: 0644]
build/documentation/man/man5/controller-rule.5 [new file with mode: 0644]
build/includes/program/controller/main/common.h [new file with mode: 0644]
build/includes/program/controller/main/common/define.h [new file with mode: 0644]
build/includes/program/controller/main/common/enumeration.h [new file with mode: 0644]
build/includes/program/controller/main/common/print.h [new file with mode: 0644]
build/includes/program/controller/main/common/string.h [new file with mode: 0644]
build/includes/program/controller/main/common/type.h [new file with mode: 0644]
build/includes/program/controller/main/controller.h [new file with mode: 0644]
build/includes/program/controller/main/print/data.h [new file with mode: 0644]
build/includes/program/controller/main/print/debug.h [new file with mode: 0644]
build/includes/program/controller/main/print/error.h [new file with mode: 0644]
build/includes/program/controller/main/print/message.h [new file with mode: 0644]
build/includes/program/controller/main/print/verbose.h [new file with mode: 0644]
build/includes/program/controller/main/print/warning.h [new file with mode: 0644]
build/includes/program/controller/main/signal.h [new file with mode: 0644]
build/includes/program/controller/main/thread.h [new file with mode: 0644]
build/stage/skeleton-settings.built [new file with mode: 0644]
build/stage/sources_documentation-settings.built [new file with mode: 0644]
build/stage/sources_headers-settings.built [new file with mode: 0644]
build/stage/sources_settings-settings.built [new file with mode: 0644]
data/build/defines [new file with mode: 0644]
data/build/dependencies [new file with mode: 0644]
data/build/fakefile [new file with mode: 0644]
data/build/settings [new file with mode: 0644]
data/build/settings.controller [new file with mode: 0644]
data/build/settings.init [new file with mode: 0644]
data/documentation/man/man1/controller.1 [new file with mode: 0644]
data/documentation/man/man5/controller-actions.5 [new file with mode: 0644]
data/documentation/man/man5/controller-entry.5 [new file with mode: 0644]
data/documentation/man/man5/controller-exit.5 [new file with mode: 0644]
data/documentation/man/man5/controller-packet.5 [new file with mode: 0644]
data/documentation/man/man5/controller-rule.5 [new file with mode: 0644]
documents/actions.txt [new file with mode: 0644]
documents/entry.txt [new file with mode: 0644]
documents/exit.txt [new file with mode: 0644]
documents/packet.txt [new file with mode: 0644]
documents/readme.bootstrap.txt [new file with mode: 0644]
documents/readme.build.txt [new file with mode: 0644]
documents/readme.txt [new file with mode: 0644]
documents/rule.txt [new file with mode: 0644]
documents/simulate.txt [new file with mode: 0644]
documents/time.txt [new file with mode: 0644]
install.sh [new file with mode: 0755]
licenses/cc-by-sa-4.0 [new file with mode: 0644]
licenses/copyrights.txt [new file with mode: 0644]
licenses/lgpl-2.1-or-later [new file with mode: 0644]
licenses/open-standard-license-1.0-or-later [new file with mode: 0644]
sources/c/controller/config.c [new file with mode: 0644]
sources/c/controller/config.h [new file with mode: 0644]
sources/c/controller/controller.c [new file with mode: 0644]
sources/c/controller/controller.h [new file with mode: 0644]
sources/c/controller/main.c [new file with mode: 0644]
sources/c/controller/main.h [new file with mode: 0644]
sources/c/init/config.c [new file with mode: 0644]
sources/c/init/config.h [new file with mode: 0644]
sources/c/init/init.c [new file with mode: 0644]
sources/c/init/init.h [new file with mode: 0644]
sources/c/init/main.c [new file with mode: 0644]
sources/c/init/main.h [new file with mode: 0644]
sources/c/main/common.c [new file with mode: 0644]
sources/c/main/common.h [new file with mode: 0644]
sources/c/main/common/define.c [new file with mode: 0644]
sources/c/main/common/define.h [new file with mode: 0644]
sources/c/main/common/enumeration.c [new file with mode: 0644]
sources/c/main/common/enumeration.h [new file with mode: 0644]
sources/c/main/common/print.c [new file with mode: 0644]
sources/c/main/common/print.h [new file with mode: 0644]
sources/c/main/common/string.c [new file with mode: 0644]
sources/c/main/common/string.h [new file with mode: 0644]
sources/c/main/common/type.c [new file with mode: 0644]
sources/c/main/common/type.h [new file with mode: 0644]
sources/c/main/controller.h [new file with mode: 0644]
sources/c/main/print/data.c [new file with mode: 0644]
sources/c/main/print/data.h [new file with mode: 0644]
sources/c/main/print/debug.c [new file with mode: 0644]
sources/c/main/print/debug.h [new file with mode: 0644]
sources/c/main/print/error.c [new file with mode: 0644]
sources/c/main/print/error.h [new file with mode: 0644]
sources/c/main/print/message.c [new file with mode: 0644]
sources/c/main/print/message.h [new file with mode: 0644]
sources/c/main/print/verbose.c [new file with mode: 0644]
sources/c/main/print/verbose.h [new file with mode: 0644]
sources/c/main/print/warning.c [new file with mode: 0644]
sources/c/main/print/warning.h [new file with mode: 0644]
sources/c/main/signal.c [new file with mode: 0644]
sources/c/main/signal.h [new file with mode: 0644]
sources/c/main/thread.c [new file with mode: 0644]
sources/c/main/thread.h [new file with mode: 0644]
specifications/entry.txt [new file with mode: 0644]
specifications/exit.txt [new file with mode: 0644]
specifications/packet.txt [new file with mode: 0644]
specifications/rule.txt [new file with mode: 0644]
specifications/task.txt [new file with mode: 0644]
specifications/time.txt [new file with mode: 0644]

diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755 (executable)
index 0000000..a5c7550
--- /dev/null
@@ -0,0 +1,3111 @@
+#!/bin/bash
+# license: lgpl-2.1-or-later
+# programmer: Kevin Day
+#
+# The purpose of this script is to provide a simple bootstrap tool to compile any part of the FLL project.
+#
+# The dependencies of this script are: bash, basename, cp, dirname, grep, ln, mkdir, rm, sed, and touch.
+#
+# This script is only designed specifically for bootstrap compiling the FLL project and does not necessarily fully follow the fake (featureless make) build process.
+#
+# This script can also be run under zsh rather than bash by setting the environment variable SHELL_ENGINE to "zsh", such as:
+#   SHELL_ENGINE="zsh" zsh ./bootstrap.sh --help
+#
+
+bootstrap_main() {
+
+  if [[ ${SHELL_ENGINE} == "zsh" ]] ; then
+    emulate ksh
+  fi
+
+  local public_name="Simple FLL Bootstrap Script"
+  local system_name=bootstrap
+  local called_name=$(basename ${0})
+  local version=0.7.0
+
+  local grab_next=
+  local do_color=dark
+  local do_help=
+  local do_copyright=
+  local i=0
+  local m=
+  local p=
+  local t=0
+
+  local c_reset="\\033[0m"
+  local c_title="\\033[1;33m"
+  local c_error="\\033[1;31m"
+  local c_warning="\\033[0;33m"
+  local c_highlight="\\033[1;32m"
+  local c_notice="\\033[0;01m"
+  local c_important="\\033[0;32m"
+  local c_subtle="\\033[1;30m"
+  local c_prefix="\\"
+
+  local key=
+  local -A variables=()
+  local failure=0
+  local settings_name=settings
+  local settings_file=
+  local settings_defines=
+  local mode=
+  local modes=
+  local modes_available=
+  local operation=
+  local operation_failure=
+  local path_build=build/
+  local path_build_stage=build/stage/
+  local path_data=data/
+  local path_documentation=${path_data}documentation/
+  local path_settings=${path_data}settings/
+  local path_sources=sources/
+  local path_language=c/
+  local path_work=
+  local print_line_first="yes"
+  local print_line_last="yes"
+  local project_built=
+  local project_built_shared=
+  local project_built_static=
+  local project_label=
+  local override_path_build=
+  local override_path_data=
+  local override_path_sources=
+  local override_path_work=
+  local define_extra=
+  local process=
+  local verbosity=normal
+  local verbose=
+  local verbose_common=
+
+  local enable_documentation=
+  local enable_shared=
+  local enable_static=
+
+  if [[ $# -gt 0 ]] ; then
+    t=$#
+
+    while [[ ${i} -lt ${t} ]] ; do
+      let i=${i}+1
+
+      if [[ ${SHELL_ENGINE} == "zsh" ]] ; then
+        p=${(P)i}
+      else
+        p=${!i}
+      fi
+
+      if [[ ${grab_next} == "" ]] ; then
+        if [[ ${p} == "-h" || ${p} == "--help" ]] ; then
+          do_help=yes
+        elif [[ ${p} == "+C" || ${p} == "++copyright" ]] ; then
+          do_copyright="yes"
+        elif [[ ${p} == "+d" || ${p} == "++dark" ]] ; then
+          do_color=dark
+          context="+d"
+        elif [[ ${p} == "+l" || ${p} == "++light" ]] ; then
+          do_color=light
+          context="+l"
+        elif [[ ${p} == "+n" || ${p} == "++no_color" ]] ; then
+          do_color=none
+          context="+n"
+        elif [[ ${p} == "+Q" || ${p} == "++quiet" ]] ; then
+          verbosity="quiet"
+          verbose="+Q"
+          verbose_common=
+        elif [[ ${p} == "+E" || ${p} == "++error" ]] ; then
+          verbosity="error"
+          verbose="+E"
+          verbose_common=
+        elif [[ ${p} == "+N" || ${p} == "++normal" ]] ; then
+          verbosity=
+          verbose="+N"
+          verbose_common=
+        elif [[ ${p} == "+V" || ${p} == "++verbose" ]] ; then
+          verbosity="verbose"
+          verbose="+V"
+          verbose_common="-v"
+        elif [[ ${p} == "+D" || ${p} == "++debug" ]] ; then
+          verbosity="debug"
+          verbose="+D"
+          verbose_common="-v"
+        elif [[ ${p} == "+F" || ${p} == "++line_first_no" ]] ; then
+          print_line_first="no"
+        elif [[ ${p} == "+L" || ${p} == "++line_last_no" ]] ; then
+          print_line_last="no"
+        elif [[ ${p} == "+v" || ${p} == "++version" ]] ; then
+          echo ${version}
+          return 0
+        elif [[ ${p} == "-d" || ${p} == "--define" ]] ; then
+          grab_next=define_extra
+        elif [[ ${p} == "-m" || ${p} == "--mode" ]] ; then
+          grab_next="mode"
+        elif [[ ${p} == "-p" || ${p} == "--process" ]] ; then
+          grab_next="process"
+        elif [[ ${p} == "-s" || ${p} == "--settings" ]] ; then
+          grab_next=settings_name
+        elif [[ ${p} == "-b" || ${p} == "--build" ]] ; then
+          grab_next=path_build
+        elif [[ ${p} == "-d" || ${p} == "--data" ]] ; then
+          grab_next=path_data
+        elif [[ ${p} == "-S" || ${p} == "--sources" ]] ; then
+          grab_next=path_sources
+        elif [[ ${p} == "-w" || ${p} == "--work" ]] ; then
+          grab_next=path_work
+        elif [[ ${p} == "--enable-doc" ]] ; then
+          enable_documentation="yes"
+        elif [[ ${p} == "--disable-doc" ]] ; then
+          enable_documentation="no"
+        elif [[ ${p} == "--enable-shared" ]] ; then
+          enable_shared="yes"
+        elif [[ ${p} == "--disable-shared" ]] ; then
+          enable_shared="no"
+        elif [[ ${p} == "--enable-static" ]] ; then
+          enable_static="yes"
+        elif [[ ${p} == "--disable-static" ]] ; then
+          enable_static="no"
+        elif [[ ${operation} == "" ]] ; then
+          operation="${p}"
+        elif [[ ${operation_failure} == "" ]] ; then
+          operation_failure=fail-multiple
+        fi
+      else
+        if [[ ${grab_next} == "define_extra" ]] ; then
+          define_extra="${define_extra}${p} "
+        elif [[ ${grab_next} == "mode" ]] ; then
+          modes="${modes}${p} "
+        elif [[ ${grab_next} == "process" ]] ; then
+          process="${p}"
+        elif [[ ${grab_next} == "settings_name" ]] ; then
+          settings_name="${p}"
+        elif [[ ${grab_next} == "path_build" ]] ; then
+          path_build=$(echo ${p} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+          override_path_build="y"
+        elif [[ ${grab_next} == "path_data" ]] ; then
+          path_data=$(echo ${p} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+          override_path_data="y"
+        elif [[ ${grab_next} == "path_sources" ]] ; then
+          path_sources=$(echo ${p} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+          override_path_sources="y"
+        elif [[ ${grab_next} == "path_work" ]] ; then
+          path_work=$(echo ${p} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+          override_path_work="y"
+        fi
+
+        grab_next=
+      fi
+    done
+
+    p=
+  fi
+
+  if [[ ${verbosity} == "quiet" ]] ; then
+    print_line_first="no"
+    print_line_last="no"
+  fi
+
+  # If the settings_name has a directory separator, then assume it is a path to the settings file.
+  if [[ $(echo ${settings_name} | grep -s -o '/') == "" ]] ; then
+    settings_file="${path_data}build/${settings_name}"
+  else
+    settings_file="${settings_name}"
+
+    # Extract the settings name from the path.
+    settings_name=$(basename ${settings_name})
+  fi
+
+  settings_defines="${path_data}build/defines"
+  path_documentation="${path_data}documentation/"
+  path_settings="${path_data}settings/"
+  path_build_stage="${path_build}stage/"
+
+  bootstrap_handle_colors
+
+  if [[ ${do_help} == "yes" ]] ; then
+    bootstrap_help
+    bootstrap_cleanup
+
+    return 0
+  fi
+
+  if [[ ${do_copyright} == "yes" ]] ; then
+    bootstrap_copyright
+    bootstrap_cleanup
+
+    return 0
+  fi
+
+  bootstrap_load_settings
+
+  # FSS and Featurless Make supports more flexible mode names, but for the purpose of this bootstrap script and avoiding potential problems, keep it simple.
+  if [[ ${modes} != "" ]] ; then
+    for mode in ${modes} ; do
+      if [[ $(echo "${mode}" | grep -s -o "[^_[:alnum:]+-]") != "" ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          bootstrap_print_first
+
+          echo -e "${c_error}ERROR: The mode ${c_notice}${mode}${c_error} includes invalid characters, only alphanumeric, underscore, minus, and plus are allowed.${c_reset}"
+
+          bootstrap_print_last
+        fi
+
+        bootstrap_cleanup
+
+        return 1
+      fi
+    done
+  fi
+
+  if [[ ${?} -ne 0 ]] ; then
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  bootstrap_load_settings_mode
+
+  if [[ ${?} -ne 0 ]] ; then
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  bootstrap_id "build_name"
+  project_built="${path_build_stage}${variables[${key}]}"
+  if [[ ${process} != "" ]] ; then
+    project_built="${project_built}-${process}"
+  fi
+
+  project_built_shared="${project_built}.shared"
+  project_built_static="${project_built}.static"
+
+  if [[ ${modes_available} == "" ]] ; then
+    if [[ ${modes} != "" ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: The mode(s) ${c_notice}${modes}${c_error} are not a valid modes, there are no available modes.${c_error}${c_reset}"
+
+        bootstrap_print_last
+      fi
+
+      bootstrap_cleanup
+
+      return 1
+    fi
+  else
+    let i=0
+    for m in ${modes_available} ; do
+
+      for mode in ${modes} ; do
+
+        if [[ "${mode}" == "${m}" ]] ; then
+          let i=1
+
+          break
+        fi
+      done
+
+      if [[ ${i} -eq 1 ]] ; then break ; fi
+    done
+
+    if [[ ${i} -eq 0 ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: The mode(s) ${c_notice}${modes}${c_error} are not valid modes, they must be one of: ${c_notice}${modes_available}${c_error}.${c_reset}"
+
+        bootstrap_print_last
+      fi
+
+      bootstrap_cleanup
+
+      return 1
+    fi
+  fi
+
+  bootstrap_id "build_name"
+  if [[ ${variables[${key}]} == "" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The required setting '${c_notice}build_name${c_error}' is not specified in the build settings file '${c_notice}${settings_file}${c_error}'.${c_reset}"
+
+      bootstrap_print_last
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  bootstrap_id "version_major"
+  if [[ ${variables[${key}]} == "" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The required setting '${c_notice}version_major${c_error}' is not specified in the build settings file '${c_notice}${settings_file}${c_error}'.${c_reset}"
+
+      bootstrap_print_last
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  bootstrap_id "version_minor"
+  if [[ ${variables[${key}]} == "" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The required setting '${c_notice}version_minor${c_error}' is not specified in the build settings file '${c_notice}${settings_file}${c_error}'.${c_reset}"
+
+      bootstrap_print_last
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  bootstrap_id "version_micro"
+  if [[ ${variables[${key}]} == "" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The required setting '${c_notice}version_micro${c_error}' is not specified in the build settings file '${c_notice}${settings_file}${c_error}'.${c_reset}"
+
+      bootstrap_print_last
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  if [[ ${path_data} == "" || ! -d ${path_data} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The data directory ${c_notice}${path_data}${c_error} is not a valid directory.${c_reset}"
+
+      bootstrap_print_last
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  if [[ ${path_sources} == "" || ! -d ${path_sources} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The sources directory ${c_notice}${path_sources}${c_error} is not a valid directory.${c_reset}"
+
+      bootstrap_print_last
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  if [[ ${path_work} != "" && ! -d ${path_work} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The work directory ${c_notice}${path_work}${c_error} is not a valid directory.${c_reset}"
+
+      bootstrap_print_last
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  bootstrap_id "build_name"
+  project_label="${variables[${key}]}"
+
+  bootstrap_id "version_major"
+  if [[ "${variables[${key}]}" != "" ]] ; then
+    project_label="${project_label}-${variables[${key}]}"
+
+    bootstrap_id "version_minor"
+    if [[ "${variables[${key}]}" != "" ]] ; then
+      project_label="${project_label}.${variables[${key}]}"
+
+      bootstrap_id "version_micro"
+      if [[ "${variables[${key}]}" != "" ]] ; then
+        project_label="${project_label}.${variables[${key}]}"
+      fi
+    fi
+  fi
+
+  if [[ ${operation_failure} == "fail-multiple" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: Only one operation may be specified at a time.${c_reset}"
+
+      bootstrap_print_last
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  elif [[ ${operation} == "build" ]] ; then
+    if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_highlight}Building:${c_reset} ${c_notice}${project_label}${c_highlight} with modes: ${c_notice}${modes}${c_highlight}.${c_reset}"
+    fi
+
+    if [[ ! -f ${project_built}.prepared ]] ; then
+      bootstrap_prepare_build
+
+      if [[ ${?} -ne 0 ]] ; then
+        bootstrap_cleanup
+
+        return 1
+      fi
+    fi
+
+    bootstrap_operation_build
+
+    if [[ ${?} -ne 0 ]] ; then
+      bootstrap_cleanup
+
+      return 1
+    fi
+  elif [[ ${operation} == "clean" ]] ; then
+    if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_highlight}Cleaning Project:${c_reset} ${c_notice}${project_label}${c_highlight}.${c_reset}"
+    fi
+
+    bootstrap_operation_clean
+  elif [[ ${operation} == "" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: No operation was given.${c_reset}"
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  else
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The operation ${c_notice}${operation}${c_error} was not recognized.${c_reset}"
+
+      bootstrap_print_last
+    fi
+
+    bootstrap_cleanup
+
+    return 1
+  fi
+
+  if [[ ${verbosity} != "quiet" ]] ; then
+    if [[ ${failure} -eq 1 || ${verbosity} != "error" ]] ; then
+      bootstrap_print_last
+    fi
+  fi
+
+  bootstrap_cleanup
+
+  return 0
+}
+
+bootstrap_handle_colors() {
+
+  if [[ ${do_color} == "light" ]] ; then
+    c_error="\\033[1;31m"
+    c_warning="\\033[0;31m"
+    c_title="\\033[1;34m"
+    c_highlight="\\033[0;34m"
+    c_notice="\\033[0;01m"
+    c_important="\\033[0;35m"
+  elif [[ ${do_color} == "none" ]] ; then
+    c_reset=
+    c_title=
+    c_error=
+    c_warning=
+    c_highlight=
+    c_notice=
+    c_important=
+    c_subtle=
+    c_prefix=
+  fi
+}
+
+bootstrap_help() {
+
+  bootstrap_print_first
+
+  echo -e "${c_title}${public_name}${c_reset}"
+  echo -e " ${c_notice}Version ${version}${c_reset}"
+  echo
+  echo -e "${c_highlight}${system_name}${c_reset} ${c_notice}[${c_reset} options ${c_notice}]${c_reset} ${c_notice}[${c_reset} operation ${c_notice}]${c_reset}"
+  echo -e " ${c_important}build${c_reset}  Build or compile the code based on build settings file."
+  echo -e " ${c_important}clean${c_reset}  Delete all build files."
+  echo
+  echo -e "${c_highlight}Options:${c_reset}"
+  echo -e " -${c_important}h${c_reset}, --${c_important}help${c_reset}           Print this help message."
+  echo -e " +${c_important}C${c_reset}, ++${c_important}copyright${c_reset}      Print the copyright."
+  echo -e " +${c_important}d${c_reset}, ++${c_important}dark${c_reset}           Output using colors that show up better on dark backgrounds."
+  echo -e " +${c_important}l${c_reset}, ++${c_important}light${c_reset}          Output using colors that show up better on light backgrounds."
+  echo -e " +${c_important}n${c_reset}, ++${c_important}no_color${c_reset}       Do not print using color."
+  echo -e " +${c_important}Q${c_reset}, ++${c_important}quiet${c_reset}          Decrease verbosity, silencing most print.to."
+  echo -e " +${c_important}E${c_reset}, ++${c_important}error${c_reset}          Decrease verbosity, using only error print.to."
+  echo -e " +${c_important}N${c_reset}, ++${c_important}normal${c_reset}         Set verbosity to normal."
+  echo -e " +${c_important}V${c_reset}, ++${c_important}verbose${c_reset}        Increase verbosity beyond normal print.to."
+  echo -e " +${c_important}D${c_reset}, ++${c_important}debug${c_reset}          Enable debugging, significantly increasing verbosity beyond normal print.to."
+  echo -e " +${c_important}v${c_reset}, ++${c_important}version${c_reset}        Print only the version number."
+  echo -e " +${c_important}F${c_reset}, ++${c_important}line_first_no${c_reset}  Disable printing of first line."
+  echo -e " +${c_important}L${c_reset}, ++${c_important}line_last_no${c_reset}   Disable printing of last line."
+  echo
+  echo -e "${c_highlight}Bootstrap Options:${c_reset}"
+  echo -e " -${c_important}d${c_reset}, --${c_important}define${c_reset}     Append an additional define after defines from settings file."
+  echo -e " -${c_important}m${c_reset}, --${c_important}mode${c_reset}       Use this mode when processing the build settings."
+  echo -e " -${c_important}p${c_reset}, --${c_important}process${c_reset}    Process name for storing build states."
+  echo -e " -${c_important}s${c_reset}, --${c_important}settings${c_reset}   Use this settings file, from within the source settings directory."
+  echo
+  echo -e " -${c_important}b${c_reset}, --${c_important}build${c_reset}      Specify a custom build directory."
+  echo -e " -${c_important}D${c_reset}, --${c_important}data${c_reset}       Specify a custom path to the data files."
+  echo -e " -${c_important}S${c_reset}, --${c_important}sources${c_reset}    Specify a custom path to the source files."
+  echo -e " -${c_important}w${c_reset}, --${c_important}work${c_reset}       Use includes/libraries/programs from this directory instead of system."
+  echo
+  echo -e "${c_highlight}Special Options:${c_reset}"
+  echo -e " --${c_important}enable-doc${c_reset}      Forcibly do build documentation files."
+  echo -e " --${c_important}disable-doc${c_reset}     Forcibly do not build documentation files."
+  echo -e " --${c_important}enable-shared${c_reset}   Forcibly do build shared files."
+  echo -e " --${c_important}disable-shared${c_reset}  Forcibly do not build shared files."
+  echo -e " --${c_important}enable-static${c_reset}   Forcibly do build static files."
+  echo -e " --${c_important}disable-static${c_reset}  Forcibly do not build static files."
+
+  bootstrap_print_last
+}
+
+bootstrap_copyright() {
+
+  bootstrap_print_first
+
+  echo "Copyright Â© 2007-2023 Kevin Day."
+  echo
+  echo "Source code license lgpl-2.1-or-later."
+  echo "Standard and specification license open-standard-license-1.0."
+  echo "Documentation license cc-by-sa-4.0."
+
+  bootstrap_print_last
+}
+
+bootstrap_id() {
+
+  case ${1} in
+    "build_compiler") let key=0;;
+    "build_indexer") let key=1;;
+    "build_indexer_arguments") let key=2;;
+    "build_language") let key=3;;
+    "build_libraries") let key=4;;
+    "build_libraries_shared") let key=5;;
+    "build_libraries_static") let key=6;;
+    "build_name") let key=7;;
+    "build_objects_library") let key=8;;
+    "build_objects_library_shared") let key=9;;
+    "build_objects_library_static") let key=10;;
+    "build_objects_program") let key=11;;
+    "build_objects_program_shared") let key=12;;
+    "build_objects_program_static") let key=13;;
+    "build_script") let key=14;;
+    "build_shared") let key=15;;
+    "build_sources_documentation") let key=16;;
+    "build_sources_headers") let key=17;;
+    "build_sources_headers_shared") let key=18;;
+    "build_sources_headers_static") let key=19;;
+    "build_sources_library") let key=20;;
+    "build_sources_library_shared") let key=21;;
+    "build_sources_library_static") let key=22;;
+    "build_sources_object") let key=23;;
+    "build_sources_object_shared") let key=24;;
+    "build_sources_object_static") let key=25;;
+    "build_sources_program") let key=26;;
+    "build_sources_program_shared") let key=27;;
+    "build_sources_program_static") let key=28;;
+    "build_sources_script") let key=29;;
+    "build_sources_setting") let key=30;;
+    "build_static") let key=31;;
+    "defines") let key=32;;
+    "defines_library") let key=33;;
+    "defines_library_shared") let key=34;;
+    "defines_library_static") let key=35;;
+    "defines_object") let key=36;;
+    "defines_object_shared") let key=37;;
+    "defines_object_static") let key=38;;
+    "defines_program") let key=39;;
+    "defines_program_shared") let key=40;;
+    "defines_program_static") let key=41;;
+    "defines_shared") let key=42;;
+    "defines_static") let key=43;;
+    "environment") let key=44;;
+    "flags") let key=45;;
+    "flags_library") let key=46;;
+    "flags_library_shared") let key=47;;
+    "flags_library_static") let key=48;;
+    "flags_object") let key=49;;
+    "flags_object_shared") let key=50;;
+    "flags_object_static") let key=51;;
+    "flags_program") let key=52;;
+    "flags_program_shared") let key=53;;
+    "flags_program_static") let key=54;;
+    "flags_shared") let key=55;;
+    "flags_static") let key=56;;
+    "has_path_standard") let key=57;;
+    "modes") let key=58;;
+    "modes_default") let key=59;;
+    "path_headers") let key=60;;
+    "path_language") let key=61;;
+    "path_library_script") let key=62;;
+    "path_library_shared") let key=63;;
+    "path_library_static") let key=64;;
+    "path_object_script") let key=65;;
+    "path_object_shared") let key=66;;
+    "path_object_static") let key=67;;
+    "path_program_script") let key=68;;
+    "path_program_shared") let key=69;;
+    "path_program_static") let key=70;;
+    "path_sources") let key=71;;
+    "path_sources_object") let key=72;;
+    "preserve_path_headers") let key=73;;
+    "process_post") let key=74;;
+    "process_pre") let key=75;;
+    "search_exclusive") let key=76;;
+    "search_shared") let key=77;;
+    "search_static") let key=78;;
+    "version_file") let key=79;;
+    "version_major") let key=80;;
+    "version_major_prefix") let key=81;;
+    "version_micro") let key=82;;
+    "version_micro_prefix") let key=83;;
+    "version_minor") let key=84;;
+    "version_minor_prefix") let key=85;;
+    "version_nano") let key=86;;
+    "version_nano_prefix") let key=87;;
+    "version_target") let key=88;;
+
+    "build_compiler-mode") let key=89;;
+    "build_indexer-mode") let key=90;;
+    "build_indexer_arguments-mode") let key=91;;
+    "build_language-mode") let key=92;;
+    "build_libraries-mode") let key=93;;
+    "build_libraries_shared-mode") let key=94;;
+    "build_libraries_static-mode") let key=95;;
+    "build_name-mode") let key=96;;
+    "build_objects_library-mode") let key=97;;
+    "build_objects_library_shared-mode") let key=98;;
+    "build_objects_library_static-mode") let key=99;;
+    "build_objects_program-mode") let key=100;;
+    "build_objects_program_shared-mode") let key=101;;
+    "build_objects_program_static-mode") let key=102;;
+    "build_script-mode") let key=103;;
+    "build_shared-mode") let key=104;;
+    "build_sources_documentation-mode") let key=105;;
+    "build_sources_headers-mode") let key=106;;
+    "build_sources_headers_shared-mode") let key=107;;
+    "build_sources_headers_static-mode") let key=108;;
+    "build_sources_library-mode") let key=109;;
+    "build_sources_library_shared-mode") let key=110;;
+    "build_sources_library_static-mode") let key=111;;
+    "build_sources_object-mode") let key=112;;
+    "build_sources_object_shared-mode") let key=113;;
+    "build_sources_object_static-mode") let key=114;;
+    "build_sources_program-mode") let key=115;;
+    "build_sources_program_shared-mode") let key=116;;
+    "build_sources_program_static-mode") let key=117;;
+    "build_sources_script-mode") let key=118;;
+    "build_sources_setting-mode") let key=119;;
+    "build_static-mode") let key=120;;
+    "defines-mode") let key=121;;
+    "defines_library-mode") let key=122;;
+    "defines_library_shared-mode") let key=123;;
+    "defines_library_static-mode") let key=124;;
+    "defines_object-mode") let key=125;;
+    "defines_object_shared-mode") let key=126;;
+    "defines_object_static-mode") let key=127;;
+    "defines_program-mode") let key=128;;
+    "defines_program_shared-mode") let key=129;;
+    "defines_program_static-mode") let key=130;;
+    "defines_shared-mode") let key=131;;
+    "defines_static-mode") let key=132;;
+    "environment-mode") let key=133;;
+    "flags-mode") let key=134;;
+    "flags_library-mode") let key=135;;
+    "flags_library_shared-mode") let key=136;;
+    "flags_library_static-mode") let key=137;;
+    "flags_object-mode") let key=138;;
+    "flags_object_shared-mode") let key=139;;
+    "flags_object_static-mode") let key=140;;
+    "flags_program-mode") let key=141;;
+    "flags_program_shared-mode") let key=142;;
+    "flags_program_static-mode") let key=143;;
+    "flags_shared-mode") let key=144;;
+    "flags_static-mode") let key=145;;
+    "has_path_standard-mode") let key=146;;
+    "path_headers-mode") let key=147;;
+    "path_language-mode") let key=148;;
+    "path_library_script-mode") let key=149;;
+    "path_library_shared-mode") let key=150;;
+    "path_library_static-mode") let key=151;;
+    "path_object_script-mode") let key=152;;
+    "path_object_shared-mode") let key=153;;
+    "path_object_static-mode") let key=154;;
+    "path_program_script-mode") let key=155;;
+    "path_program_shared-mode") let key=156;;
+    "path_program_static-mode") let key=157;;
+    "path_sources-mode") let key=158;;
+    "path_sources_object-mode") let key=159;;
+    "preserve_path_headers-mode") let key=160;;
+    "process_post-mode") let key=161;;
+    "process_pre-mode") let key=162;;
+    "search_exclusive-mode") let key=163;;
+    "search_shared-mode") let key=164;;
+    "search_static-mode") let key=165;;
+    "version_file-mode") let key=166;;
+    "version_major-mode") let key=167;;
+    "version_major_prefix-mode") let key=168;;
+    "version_micro-mode") let key=169;;
+    "version_micro_prefix-mode") let key=170;;
+    "version_minor-mode") let key=171;;
+    "version_minor_prefix-mode") let key=172;;
+    "version_nano-mode") let key=173;;
+    "version_nano_prefix-mode") let key=174;;
+    "version_target-mode") let key=175;;
+
+    "has-build_compiler") let key=176;;
+    "has-build_indexer") let key=177;;
+    "has-build_indexer_arguments") let key=178;;
+    "has-build_name") let key=179;;
+    "has-has_path_standard") let key=180;;
+    "has-path_library_script") let key=181;;
+    "has-path_library_shared") let key=182;;
+    "has-path_library_static") let key=183;;
+    "has-path_object_script") let key=184;;
+    "has-path_object_shared") let key=185;;
+    "has-path_object_static") let key=186;;
+    "has-path_program_script") let key=187;;
+    "has-path_program_shared") let key=188;;
+    "has-path_program_static") let key=189;;
+    "has-path_sources") let key=190;;
+    "has-path_sources_object") let key=191;;
+    "has-search_exclusive") let key=192;;
+    "has-search_shared") let key=193;;
+    "has-search_static") let key=194;;
+    "has-version_major_prefix") let key=195;;
+    "has-version_micro_prefix") let key=196;;
+    "has-version_minor_prefix") let key=197;;
+    "has-version_nano_prefix") let key=198;;
+
+    "has-build_compiler-mode") let key=199;;
+    "has-build_indexer-mode") let key=200;;
+    "has-build_indexer_arguments-mode") let key=201;;
+    "has-build_name-mode") let key=202;;
+    "has-has_path_standard-mode") let key=203;;
+    "has-path_library_script-mode") let key=204;;
+    "has-path_library_shared-mode") let key=205;;
+    "has-path_library_static-mode") let key=206;;
+    "has-path_object_script-mode") let key=207;;
+    "has-path_object_shared-mode") let key=208;;
+    "has-path_object_static-mode") let key=209;;
+    "has-path_program_script-mode") let key=210;;
+    "has-path_program_shared-mode") let key=211;;
+    "has-path_program_static-mode") let key=212;;
+    "has-path_sources-mode") let key=213;;
+    "has-path_sources_object-mode") let key=214;;
+    "has-search_exclusive-mode") let key=215;;
+    "has-search_shared-mode") let key=216;;
+    "has-search_static-mode") let key=217;;
+    "has-version_major_prefix-mode") let key=218;;
+    "has-version_micro_prefix-mode") let key=219;;
+    "has-version_minor_prefix-mode") let key=220;;
+    "has-version_nano_prefix-mode") let key=221;;
+  esac
+}
+
+bootstrap_load_settings() {
+  local i=
+  local key=
+  local value=
+
+  if [[ ! -d ${path_data}build/ ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: No build settings directory '${c_notice}${path_data}build/${c_error}' could not be found or is not a valid directory.${c_reset}"
+    fi
+
+    let failure=1
+  elif [[ ! -f ${settings_file} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: No settings file ${c_notice}${settings_file}${c_error} could not be found or is not a valid file.${c_reset}"
+    fi
+
+    let failure=1
+  fi
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  # Get available modes.
+  if [[ ${modes_available} == "" ]] ; then
+    modes_available=$(grep -s -o "^[[:space:]]*modes[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*modes\>||" -e 's|^[[:space:]]*||')
+  fi
+
+  # Get default modes.
+  modes_default=$(grep -s -o "^[[:space:]]*modes_default[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*modes_default\>||" -e 's|^[[:space:]]*||')
+
+  # Use default modes if no mode is explicitly provided.
+  if [[ ${modes} == "" ]] ; then
+    modes=${modes_default}
+  fi
+
+  # Single value Objects.
+  for i in build_compiler build_indexer build_language build_name build_script build_shared build_sources_object build_sources_object_shared build_sources_object_static build_static has_path_standard path_headers path_language path_library_script path_library_shared path_library_static path_object_script path_object_shared path_object_static path_program_script path_program_shared path_program_static path_sources path_sources_object preserve_path_headers process_post process_pre search_exclusive search_shared search_static version_file version_major version_major_prefix version_micro version_micro_prefix version_minor version_minor_prefix version_nano version_nano_prefix version_target ; do
+
+    bootstrap_id "${i}"
+
+    if [[ ${key} == "" ]] ; then
+      if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+        echo -e "${c_warning}WARNING: Failed to find index for '${c_notice}${i}${c_warning}' when calling ${c_notice}bootstrap_id()${c_warning}.${c_reset}"
+      fi
+
+      key=
+      bootstrap_id "has-${i}"
+      if [[ ${key} != "" ]] ; then
+        variables[${key}]="no"
+      fi
+    else
+      if [[ $(grep -s -o "^[[:space:]]*${i}[[:space:]].*\$" ${settings_file}) != "" ]] ; then
+        value=$(grep -s -o "^[[:space:]]*${i}[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*${i}\>||" -e 's|^[[:space:]]*||')
+        variables[${key}]="${value}"
+
+        key=
+        bootstrap_id "has-${i}"
+        if [[ ${key} != "" ]] ; then
+          variables[${key}]="yes"
+        fi
+      elif [[ $(grep -s -o "^[[:space:]]*${i}\$" ${settings_file}) != "" ]] ; then
+        variables[${key}]=""
+
+        key=
+        bootstrap_id "has-${i}"
+        if [[ ${key} != "" ]] ; then
+          variables[${key}]="yes"
+        fi
+      else
+        key=
+        bootstrap_id "has-${i}"
+        if [[ ${key} != "" ]] ; then
+          variables[${key}]="no"
+        fi
+      fi
+    fi
+  done
+
+  # Multi value Objects.
+  for i in build_indexer_arguments build_libraries build_libraries_shared build_libraries_static build_objects_library build_objects_library_shared build_objects_library_static build_objects_program build_objects_program_shared build_objects_program_static build_sources_documentation build_sources_headers build_sources_headers_shared build_sources_headers_static build_sources_library build_sources_library_shared build_sources_library_static build_sources_program build_sources_program_shared build_sources_program_static build_sources_script build_sources_setting defines defines_library defines_library_shared defines_library_static defines_object defines_object_shared defines_object_static defines_program defines_program_shared defines_program_static defines_shared defines_static environment flags flags_library flags_library_shared flags_library_static flags_object flags_object_shared flags_object_static flags_program flags_program_shared flags_program_static flags_shared flags_static ; do
+
+    bootstrap_id "${i}"
+
+    if [[ ${key} == "" ]] ; then
+      if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+        echo -e "${c_warning}WARNING: Failed to find index for '${c_notice}${i}${c_warning}' when calling ${c_notice}bootstrap_id()${c_warning}.${c_reset}"
+      fi
+
+      key=
+      bootstrap_id "has-${i}"
+      if [[ ${key} != "" ]] ; then
+        variables[${key}]="no"
+      fi
+    else
+      if [[ $(grep -s -o "^[[:space:]]*${i}[[:space:]].*\$" ${settings_file}) != "" ]] ; then
+        value=$(grep -s -o "^[[:space:]]*${i}[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*${i}\>||" -e 's|^[[:space:]]*||')
+        variables[${key}]="${variables[${key}]}${value} "
+
+        key=
+        bootstrap_id "has-${i}"
+        if [[ ${key} != "" ]] ; then
+          variables[${key}]="yes"
+        fi
+      elif [[ $(grep -s -o "^[[:space:]]*${i}\$" ${settings_file}) != "" ]] ; then
+        variables[${key}]=""
+
+        key=
+        bootstrap_id "has-${i}"
+        if [[ ${key} != "" ]] ; then
+          variables[${key}]="yes"
+        fi
+      else
+        key=
+        bootstrap_id "has-${i}"
+        if [[ ${key} != "" ]] ; then
+          variables[${key}]="no"
+        fi
+      fi
+    fi
+  done
+}
+
+bootstrap_load_settings_mode() {
+  local i=
+  local key=
+  local m=
+  local value=
+
+  for m in ${modes} ; do
+
+    # Single value Objects.
+    for i in build_compiler build_indexer build_language build_name build_script build_shared build_sources_object build_sources_object_shared build_sources_object_static build_static has_path_standard path_headers path_language path_library_script path_library_shared path_library_static path_object_script path_object_shared path_object_static path_program_script path_program_shared path_program_static path_sources path_sources_object preserve_path_headers process_post process_pre search_exclusive search_shared search_static version_file version_major version_major_prefix version_micro version_micro_prefix version_minor version_minor_prefix version_nano version_nano_prefix version_target ; do
+
+      bootstrap_id "${i}-mode"
+
+      if [[ ${key} == "" ]] ; then
+        if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+          echo -e "${c_warning}WARNING: Failed to find index for '${c_notice}${i}-${m}${c_warning}' when calling ${c_notice}bootstrap_id()${c_warning}.${c_reset}"
+        fi
+
+        key=
+        bootstrap_id "has-${i}-mode"
+        if [[ ${key} != "" ]] ; then
+          variables[${key}]="no"
+        fi
+      else
+
+        if [[ $(grep -s -o "^[[:space:]]*${i}-${m}[[:space:]].*\$" ${settings_file}) != "" ]] ; then
+          value=$(grep -s -o "^[[:space:]]*${i}-${m}[[:space:]].*\$" ${settings_file} | sed -e "H;/${i}-${m}/h;\$!d;x" | sed -e "s|^[[:space:]]*${i}-${m}\>||" -e 's|^[[:space:]]*||')
+          variables[${key}]="${value}"
+
+          key=
+          bootstrap_id "has-${i}-mode"
+          if [[ ${key} != "" ]] ; then
+            variables[${key}]="yes"
+          fi
+        elif [[ $(grep -s -o "^[[:space:]]*${i}-${m}\$" ${settings_file}) != "" ]] ; then
+          variables[${key}]=""
+
+          key=
+          bootstrap_id "has-${i}-mode"
+          if [[ ${key} != "" ]] ; then
+            variables[${key}]="yes"
+          fi
+        else
+          key=
+          bootstrap_id "has-${i}-mode"
+          if [[ ${key} != "" ]] ; then
+            variables[${key}]="no"
+          fi
+        fi
+      fi
+    done
+
+    # Multi value Objects.
+    for i in build_indexer_arguments build_libraries build_libraries_shared build_libraries_static build_objects_library build_objects_library_shared build_objects_library_static build_objects_program build_objects_program_shared build_objects_program_static build_sources_documentation build_sources_headers build_sources_headers_shared build_sources_headers_static build_sources_library build_sources_library_shared build_sources_library_static build_sources_object_shared build_sources_object_static build_sources_program build_sources_program_shared build_sources_program_static build_sources_script build_sources_setting build_static defines defines_library defines_library_shared defines_library_static defines_object defines_object_shared defines_object_static defines_program defines_program_shared defines_program_static defines_shared defines_static environment flags flags_library flags_library_shared flags_library_static flags_object flags_object_shared flags_object_static flags_program flags_program_shared flags_program_static flags_shared flags_static ; do
+
+      bootstrap_id "${i}-mode"
+
+      if [[ ${key} == "" ]] ; then
+        if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+          echo -e "${c_warning}WARNING: Failed to find index for '${c_notice}${i}-${m}${c_warning}' when calling ${c_notice}bootstrap_id()${c_warning}.${c_reset}"
+        fi
+
+        key=
+        bootstrap_id "has-${i}-mode"
+        if [[ ${key} != "" ]] ; then
+          variables[${key}]="no"
+        fi
+      else
+        if [[ $(grep -s -o "^[[:space:]]*${i}-${m}[[:space:]].*\$" ${settings_file}) != "" ]] ; then
+          value=$(grep -s -o "^[[:space:]]*${i}-${m}[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*${i}-${m}\>||" -e 's|^[[:space:]]*||')
+          variables[${key}]="${variables[${key}]}${value} "
+
+          key=
+          bootstrap_id "has-${i}"
+          if [[ ${key} != "" ]] ; then
+            variables[${key}]="yes"
+          fi
+        elif [[ $(grep -s -o "^[[:space:]]*${i}-${m}\$" ${settings_file}) != "" ]] ; then
+          variables[${key}]=""
+
+          key=
+          bootstrap_id "has-${i}"
+          if [[ ${key} != "" ]] ; then
+            variables[${key}]="yes"
+          fi
+        else
+          key=
+          bootstrap_id "has-${i}-mode"
+          if [[ ${key} != "" && ${variables[${key}]} != "yes" ]] ; then
+            variables[${key}]="no"
+          fi
+        fi
+      fi
+    done
+  done
+}
+
+bootstrap_prepare_build() {
+  local alt=${1}
+  local i=
+
+  mkdir ${verbose_common} -p ${path_build}{documents,documentation,includes,libraries/{script,shared,static},objects/{script,shared,static},programs/{script,shared,static},settings,stage} || failure=1
+
+  if [[ ${failure} -eq 1 ]] ; then
+    if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+      echo -e "${c_warning}WARNING: Failed to create build directories in '${c_notice}${path_build}${c_error}'.${c_reset}"
+    fi
+
+    return 1
+  fi
+
+  bootstrap_id "path_headers-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    mkdir ${verbose_common} -p ${path_build}includes/${variables[${key}]} || failure=1
+  else
+    bootstrap_id "path_headers"
+
+    if [[ ${variables[${key}]} != "" ]] ; then
+      mkdir ${verbose_common} -p ${path_build}includes/${variables[${key}]} || failure=1
+    fi
+  fi
+
+  if [[ ${failure} -eq 1 ]] ; then
+    if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+      echo -e "${c_warning}WARNING: Failed to create ${c_notice}path_heades${c_error} build directories in '${c_notice}${path_build}${c_error}'.${c_reset}"
+    fi
+
+    return 1
+  fi
+
+  touch ${project_built}-${settings_name}.prepared
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  return 0
+}
+
+bootstrap_operation_build() {
+  local i=
+  local n=
+  local version_file=
+  local version_target=
+  local alt=${1}
+  local directory=
+  local key=
+
+  bootstrap_id "build_compiler"
+  local build_compiler=${variables[${key}]}
+
+  bootstrap_id "build_indexer"
+  local build_indexer=${variables[${key}]}
+
+  bootstrap_id "build_indexer_arguments"
+  local build_indexer_arguments=${variables[${key}]}
+
+  bootstrap_id "build_name"
+  local build_name=${variables[${key}]}
+
+  bootstrap_id "build_shared"
+  local build_shared=${variables[${key}]}
+
+  bootstrap_id "build_static"
+  local build_static=${variables[${key}]}
+
+  bootstrap_id "defines"
+  local defines=${variables[${key}]}
+
+  bootstrap_id "defines_library"
+  local defines_library=${variables[${key}]}
+
+  bootstrap_id "defines_library_shared"
+  local defines_library_shared=${variables[${key}]}
+
+  bootstrap_id "defines_library_static"
+  local defines_library_static=${variables[${key}]}
+
+  bootstrap_id "defines_object"
+  local defines_object=${variables[${key}]}
+
+  bootstrap_id "defines_object_shared"
+  local defines_object_shared=${variables[${key}]}
+
+  bootstrap_id "defines_object_static"
+  local defines_object_static=${variables[${key}]}
+
+  bootstrap_id "defines_program"
+  local defines_program=${variables[${key}]}
+
+  bootstrap_id "defines_program_shared"
+  local defines_program_shared=${variables[${key}]}
+
+  bootstrap_id "defines_program_static"
+  local defines_program_static=${variables[${key}]}
+
+  bootstrap_id "defines_shared"
+  local defines_shared=${variables[${key}]}
+
+  bootstrap_id "defines_static"
+  local defines_static=${variables[${key}]}
+
+  bootstrap_id "flags"
+  local flags=${variables[${key}]}
+
+  bootstrap_id "flags_library"
+  local flags_library=${variables[${key}]}
+
+  bootstrap_id "flags_library_shared"
+  local flags_library_shared=${variables[${key}]}
+
+  bootstrap_id "flags_library_static"
+  local flags_library_static=${variables[${key}]}
+
+  bootstrap_id "flags_object"
+  local flags_object=${variables[${key}]}
+
+  bootstrap_id "flags_object_shared"
+  local flags_object_shared=${variables[${key}]}
+
+  bootstrap_id "flags_object_static"
+  local flags_object_static=${variables[${key}]}
+
+  bootstrap_id "flags_program"
+  local flags_program=${variables[${key}]}
+
+  bootstrap_id "flags_program_shared"
+  local flags_program_shared=${variables[${key}]}
+
+  bootstrap_id "flags_program_static"
+  local flags_program_static=${variables[${key}]}
+
+  bootstrap_id "flags_shared"
+  local flags_shared=${variables[${key}]}
+
+  bootstrap_id "flags_static"
+  local flags_static=${variables[${key}]}
+
+  bootstrap_id "build_libraries"
+  local libraries=${variables[${key}]}
+
+  bootstrap_id "build_libraries_shared"
+  local libraries_shared=${variables[${key}]}
+
+  bootstrap_id "build_libraries_static"
+  local libraries_static=${variables[${key}]}
+
+  bootstrap_id "build_objects_library"
+  local objects_library=${variables[${key}]}
+
+  bootstrap_id "build_objects_library_shared"
+  local objects_library_shared=${variables[${key}]}
+
+  bootstrap_id "build_objects_library_static"
+  local objects_library_static=${variables[${key}]}
+
+  bootstrap_id "build_objects_program"
+  local objects_program=${variables[${key}]}
+
+  bootstrap_id "build_objects_program_shared"
+  local objects_program_shared=${variables[${key}]}
+
+  bootstrap_id "build_objects_program_static"
+  local objects_program_static=${variables[${key}]}
+
+  bootstrap_id "path_headers"
+  local path_headers=${variables[${key}]}
+
+  bootstrap_id "preserve_path_headers"
+  local preserve_path_headers=${variables[${key}]}
+
+  bootstrap_id "path_library_script"
+  local path_library_script=${variables[${key}]}
+
+  bootstrap_id "path_library_shared"
+  local path_library_shared=${variables[${key}]}
+
+  bootstrap_id "path_library_static"
+  local path_library_static=${variables[${key}]}
+
+  bootstrap_id "path_object_script"
+  local path_object_script=${variables[${key}]}
+
+  bootstrap_id "path_object_shared"
+  local path_object_shared=${variables[${key}]}
+
+  bootstrap_id "path_object_static"
+  local path_object_static=${variables[${key}]}
+
+  bootstrap_id "path_program_script"
+  local path_program_script=${variables[${key}]}
+
+  bootstrap_id "path_program_shared"
+  local path_program_shared=${variables[${key}]}
+
+  bootstrap_id "path_program_static"
+  local path_program_static=${variables[${key}]}
+
+  bootstrap_id "has_path_standard"
+  local has_path_standard=${variables[${key}]}
+
+  bootstrap_id "search_exclusive"
+  local search_exclusive=${variables[${key}]}
+
+  bootstrap_id "search_shared"
+  local search_shared=${variables[${key}]}
+
+  bootstrap_id "search_static"
+  local search_static=${variables[${key}]}
+
+  bootstrap_id "build_sources_documentation"
+  local sources_documentation=${variables[${key}]}
+
+  bootstrap_id "build_sources_headers"
+  local sources_headers=${variables[${key}]}
+
+  bootstrap_id "build_sources_library"
+  local sources_library=${variables[${key}]}
+
+  bootstrap_id "build_sources_library_shared"
+  local sources_library_shared=${variables[${key}]}
+
+  bootstrap_id "build_sources_library_static"
+  local sources_library_static=${variables[${key}]}
+
+  bootstrap_id "build_sources_object"
+  local sources_object=${variables[${key}]}
+
+  bootstrap_id "build_sources_object_shared"
+  local sources_object_shared=${variables[${key}]}
+
+  bootstrap_id "build_sources_object_static"
+  local sources_object_static=${variables[${key}]}
+
+  bootstrap_id "build_sources_program"
+  local sources_program=${variables[${key}]}
+
+  bootstrap_id "build_sources_program_shared"
+  local sources_program_shared=${variables[${key}]}
+
+  bootstrap_id "build_sources_program_static"
+  local sources_program_static=${variables[${key}]}
+
+  bootstrap_id "build_sources_script"
+  local sources_script=${variables[${key}]}
+
+  bootstrap_id "build_sources_setting"
+  local sources_setting=${variables[${key}]}
+
+  bootstrap_id "version_file"
+  local version_file_value=${variables[${key}]}
+
+  bootstrap_id "version_major"
+  local version_major=${variables[${key}]}
+
+  bootstrap_id "version_major_prefix"
+  local version_major_prefix=${variables[${key}]}
+
+  bootstrap_id "version_minor"
+  local version_minor=${variables[${key}]}
+
+  bootstrap_id "version_minor_prefix"
+  local version_minor_prefix=${variables[${key}]}
+
+  bootstrap_id "version_micro"
+  local version_micro=${variables[${key}]}
+
+  bootstrap_id "version_micro_prefix"
+  local version_micro_prefix=${variables[${key}]}
+
+  bootstrap_id "version_nano"
+  local version_nano=${variables[${key}]}
+
+  bootstrap_id "version_nano_prefix"
+  local version_nano_prefix=${variables[${key}]}
+
+  bootstrap_id "version_target"
+  local version_target_value=${variables[${key}]}
+
+  local links=
+  local sources=
+
+  bootstrap_operation_build_prepare_defaults
+
+  bootstrap_operation_build_prepare_versions
+
+  bootstrap_operation_build_prepare_shared_static
+
+  bootstrap_operation_build_prepare_paths
+
+  bootstrap_operation_build_prepare_flags
+
+  bootstrap_operation_build_prepare_defines
+
+  bootstrap_operation_build_prepare_libraries
+
+  bootstrap_operation_build_prepare_objects
+
+  bootstrap_operation_build_prepare_programs
+
+  bootstrap_operation_build_prepare_settings
+
+  bootstrap_operation_build_prepare_documentation
+
+  bootstrap_operation_build_prepare_headers
+
+  bootstrap_operation_build_prepare_remaining
+
+  if [[ ${build_shared} == "yes" && -f ${project_built_shared}.built || ${build_static} == "yes" && -f ${project_built_static}.built ]] ; then
+    if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+      echo -e "${c_warning}WARNING: This project has already been built.${c_reset}"
+    fi
+
+    return 0
+  fi
+
+  local arguments_include="-I${path_build}includes/"
+  local arguments_shared="-L${path_build}libraries/${path_library_shared}"
+  local arguments_static="-L${path_build}libraries/${path_library_static}"
+
+  if [[ ${path_work} != "" ]] ; then
+    arguments_include="${arguments_include} -I${path_work}includes/"
+    arguments_shared="${arguments_shared} -L${path_work}libraries/${path_library_shared}"
+    arguments_static="${arguments_static} -L${path_work}libraries/${path_library_static}"
+  fi
+
+  bootstrap_operation_build_validate_paths
+
+  bootstrap_operation_build_validate_shared_static
+
+  bootstrap_operation_build_validate_sources
+
+  bootstrap_operation_build_validate_search
+
+  bootstrap_operation_build_validate_build
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  if [[ ${sources_documentation} != "" ]] ; then
+    for i in ${sources_documentation} ; do
+      directory=$(dirname ${i})
+
+      if [[ ! -e ${path_documentation}${i} ]] ; then
+        if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+          echo
+          echo -e "${c_warning}WARNING: Documentation path '${c_notice}${path_documentation}${i}${c_warning}' is not found.${c_reset}"
+        fi
+
+        continue;
+      fi
+
+      if [[ ${directory} == "." ]] ; then
+        cp ${verbose_common} -R ${path_documentation}${i} ${path_build}documentation/ || failure=1
+      else
+        mkdir ${verbose_common} -p ${path_build}documentation/${directory} || failure=1
+
+        if [[ ${failure} -eq 0 ]] ; then
+          cp ${verbose_common} -R ${path_documentation}${i} ${path_build}documentation/${directory}/ || failure=1
+        fi
+      fi
+    done
+  fi
+
+  if [[ ${sources_setting} != "" ]] ; then
+    for i in ${sources_setting} ; do
+      directory=$(dirname ${i})
+
+      if [[ ${directory} == "." ]] ; then
+        cp ${verbose_common} -R ${path_settings}${i} ${path_build}settings/ || failure=1
+      else
+        mkdir ${verbose_common} -p ${path_build}settings/${directory} || failure=1
+
+        if [[ ${failure} -eq 0 ]] ; then
+          cp ${verbose_common} -R ${path_settings}${i} ${path_build}settings/${directory}/ || failure=1
+        fi
+      fi
+    done
+  fi
+
+  if [[ ${failure} -eq 0 && ${sources_headers} != "" ]] ; then
+    if [[ ${preserve_path_headers} == "yes" ]] ; then
+      for i in ${sources_headers} ; do
+        directory=$(dirname ${i})
+
+        if [[ ${directory} == "." ]] ; then
+          cp ${verbose_common} -f ${path_sources}${path_language}${i} ${path_build}includes/${path_headers} || failure=1
+        else
+          if [[ ! -d ${path_build}includes/${path_headers}${directory} ]] ; then
+            mkdir ${verbose_common} -p ${path_build}includes/${path_headers}${directory} || failure=1
+          fi
+
+          if [[ ${failure} -eq 0 ]] ; then
+            cp ${verbose_common} -f ${path_sources}${path_language}${i} ${path_build}includes/${path_headers}${i} || failure=1
+          fi
+        fi
+      done
+    else
+      for i in ${sources_headers} ; do
+        cp ${verbose_common} -f ${path_sources}${path_language}${i} ${path_build}includes/${path_headers} || failure=1
+      done
+    fi
+  fi
+
+  if [[ ${failure} -eq 0 && ${build_shared} == "yes" && ! -f ${project_built_shared}.built ]] ; then
+    if [[ ${sources_object} != "" || ${sources_object_shared} != "" ]] ; then
+      sources=
+      let count=0
+
+      # Sources object only allows for a single value.
+      if [[ ${sources_object_shared} != "" ]] ; then
+        for i in ${sources_object_shared} ; do
+          let count++
+        done
+
+        if [[ ${count} -gt 1 ]] ; then
+          if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+            echo -e "${c_warning}WARNING: Multiple '${c_notice}sources_object_shared${c_warning}' found, only using the first one found is going to be used.${c_reset}"
+          fi
+        fi
+
+        for i in ${sources_object_shared} ; do
+          sources="${path_sources_object}${path_language}${i} "
+
+          break
+        done
+      else
+        for i in ${sources_object} ; do
+          let count++
+        done
+
+        if [[ ${count} -gt 1 ]] ; then
+          if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+            echo -e "${c_warning}WARNING: Multiple '${c_notice}sources_object${c_warning}' found, only using the first one found is going to be used.${c_reset}"
+          fi
+        fi
+
+        for i in ${sources_object} ; do
+          sources="${path_sources_object}${path_language}${i} "
+
+          break
+        done
+      fi
+
+      if [[ ${verbosity} == "verbose" ]] ; then
+        echo ${build_compiler} ${sources} -c -o ${path_build}objects/${path_object_shared}${build_name}.o ${arguments_shared} ${arguments_include} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_object} ${flags_object_shared} ${defines} ${defines_shared} ${defines_object} ${defines_object_shared} ${define_extra}
+      fi
+
+      ${build_compiler} ${sources} -c -o ${path_build}objects/${path_object_shared}${build_name}.o ${arguments_shared} ${arguments_include} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_object} ${flags_object_shared} ${defines} ${defines_shared} ${defines_object} ${defines_object_shared} ${define_extra} || failure=1
+    fi
+
+    if [[ ${sources_library} != "" || ${sources_library_shared} != "" ]] ; then
+      sources=
+
+      if [[ ${objects_library} != "" || ${objects_library_shared} != "" ]] ; then
+        for i in ${objects_library} ${objects_library_shared} ; do
+          sources="${sources}${path_build}objects/${path_object_shared}${i} "
+        done
+      fi
+
+      for i in ${sources_library} ${sources_library_shared} ; do
+        sources="${sources}${path_sources}${path_language}${i} "
+      done
+
+      if [[ ${verbosity} == "verbose" ]] ; then
+        echo ${build_compiler} ${sources} -shared -Wl,-soname,lib${build_name}.so${version_target} -o ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_file} ${arguments_shared} ${arguments_include} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_library} ${flags_library_shared} ${defines} ${defines_shared} ${defines_library} ${defines_library_shared} ${define_extra}
+      fi
+
+      ${build_compiler} ${sources} -shared -Wl,-soname,lib${build_name}.so${version_target} -o ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_file} ${arguments_shared} ${arguments_include} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_library} ${flags_library_shared} ${defines} ${defines_shared} ${defines_library} ${defines_library_shared} ${define_extra} || failure=1
+
+      if [[ ${failure} -eq 0 ]] ; then
+        if [[ ${version_file_value} != "major" ]] ; then
+          if [[ ${version_file_value} == "minor" ]] ; then
+            ln ${verbose_common} -sf lib${build_name}.so${version_file} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major} || failure=1
+          else
+            ln ${verbose_common} -sf lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major} || failure=1
+
+            if [[ ${failure} -eq 0 ]] ; then
+              if [[ ${version_file_value} == "micro" ]] ; then
+                ln ${verbose_common} -sf lib${build_name}.so${version_file} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor} || failure=1
+              else
+                ln ${verbose_common} -sf lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor} || failure=1
+
+                if [[ ${failure} -eq 0 ]] ; then
+                  ln ${verbose_common} -sf lib${build_name}.so${version_file} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro} || failure=1
+                fi
+              fi
+            fi
+          fi
+        fi
+
+        if [[ ${failure} -eq 0 ]] ; then
+          ln ${verbose_common} -sf lib${build_name}.so${version_major_prefix}${version_major} ${path_build}libraries/${path_library_shared}lib${build_name}.so || failure=1
+        fi
+      fi
+    fi
+
+    if [[ ${failure} -eq 0 && ${sources_program} != "" ]] ; then
+      sources=
+      links=
+
+      if [[ ${sources_library} != "" || ${sources_library_shared} != "" ]] ; then
+        links="-l${build_name} "
+      fi
+
+      if [[ ${objects_program} != "" || ${objects_program_shared} != "" ]] ; then
+        for i in ${objects_program} ${objects_program_shared} ; do
+          sources="${sources}${path_build}objects/${path_object_shared}${i} "
+        done
+      fi
+
+      for i in ${sources_program} ${sources_program_shared} ; do
+        sources="${sources}${path_sources}${path_language}${i} "
+      done
+
+      if [[ ${verbosity} == "verbose" ]] ; then
+        echo ${build_compiler} ${sources} -o ${path_build}programs/${path_program_shared}${build_name} ${arguments_shared} ${arguments_include} ${links} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_program} ${flags_program_shared} ${defines} ${defines_shared} ${defines_program} ${defines_program_shared} ${define_extra}
+      fi
+
+      ${build_compiler} ${sources} -o ${path_build}programs/${path_program_shared}${build_name} ${arguments_shared} ${arguments_include} ${links} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_program} ${flags_program_shared} ${defines} ${defines_shared} ${defines_program} ${defines_program_shared} ${define_extra} || failure=1
+    fi
+
+    if [[ ${failure} -eq 0 ]] ; then
+      touch ${project_built_shared}-${settings_name}.built
+    fi
+  fi
+
+  if [[ ${failure} -eq 0 && ${build_static} == "yes" && ! -f ${project_built_static}.built ]] ; then
+    if [[ ${sources_object} != "" || ${sources_object_static} != "" ]] ; then
+      let count=0
+
+      # Sources object only allows for a single value.
+      if [[ ${sources_object_static} != "" ]] ; then
+        for i in ${sources_object_static} ; do
+          let count++
+        done
+
+        if [[ ${count} -gt 1 ]] ; then
+          if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+            echo -e "${c_warning}WARNING: Multiple '${c_notice}sources_object_static${c_warning}' found, only using the first one found is going to be used.${c_reset}"
+          fi
+        fi
+
+        for i in ${sources_object_static} ; do
+          sources="${path_sources_object}${path_language}${i} "
+
+          break
+        done
+      else
+        for i in ${sources_object} ; do
+          let count++
+        done
+
+        if [[ ${count} -gt 1 ]] ; then
+          if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+            echo -e "${c_warning}WARNING: Multiple '${c_notice}sources_object${c_warning}' found, only using the first one found is going to be used.${c_reset}"
+          fi
+        fi
+
+        for i in ${sources_object} ; do
+          sources="${path_sources_object}${path_language}${i} "
+
+          break
+        done
+      fi
+
+      if [[ ${verbosity} == "verbose" ]] ; then
+        echo ${build_compiler} ${sources} -c -o ${path_build}objects/${path_object_static}${build_name}.o ${arguments_static} ${arguments_include} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_object} ${flags_object_static} ${defines} ${defines_static} ${defines_object} ${defines_object_static} ${define_extra}
+      fi
+
+      ${build_compiler} ${sources} -c -o ${path_build}objects/${path_object_static}${build_name}.o ${arguments_static} ${arguments_include} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_object} ${flags_object_static} ${defines} ${defines_static} ${defines_object} ${defines_object_static} ${define_extra} || failure=1
+    fi
+
+    if [[ ${sources_library} != "" || ${sources_library_static} != "" ]] ; then
+      sources=
+
+      if [[ ${objects_library} != "" || ${objects_library_static} != "" ]] ; then
+        for i in ${objects_library} ${objects_library_static} ; do
+          sources="${sources}${path_build}objects/${path_object_static}${i} "
+        done
+      fi
+
+      for i in ${sources_library} ${sources_library_static} ; do
+        directory=$(dirname ${i})
+        n=$(basename ${i} | sed -e 's|\.c$||')
+
+        if [[ ${directory} != "." && ! -d ${path_build}objects/${directory} ]] ; then
+          mkdir ${verbose_common} -p ${path_build}objects/${directory}
+
+          if [[ ${?} -ne 0 ]] ; then
+            let failure=1
+
+            break;
+          fi
+        fi
+
+        # These are objects created by the static build step rather than objects created by the object build step.
+        sources="${sources}${path_build}objects/${directory}/${n}.o "
+
+        if [[ ${verbosity} == "verbose" ]] ; then
+          echo ${build_compiler} ${path_sources}${path_language}${i} -c -static -o ${path_build}objects/${directory}/${n}.o ${arguments_static} ${arguments_include} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_library} ${flags_library_static} ${defines} ${defines_static} ${defines_library} ${defines_library_static} ${define_extra}
+        fi
+
+        ${build_compiler} ${path_sources}${path_language}${i} -c -static -o ${path_build}objects/${directory}/${n}.o ${arguments_static} ${arguments_include} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_library} ${flags_library_static} ${defines} ${defines_static} ${defines_library} ${defines_library_static} ${define_extra} || failure=1
+
+        if [[ ${failure} -eq 1 ]] ; then
+          break;
+        fi
+      done
+
+      if [[ ${failure} -eq 0 && ( ${sources_library} != "" || ${sources_library_static} != "" ) ]] ; then
+
+        if [[ ${verbosity} == "verbose" ]] ; then
+          echo ${build_indexer} ${build_indexer_arguments} ${path_build}libraries/${path_library_static}lib${build_name}.a ${sources}
+        fi
+
+        ${build_indexer} ${build_indexer_arguments} ${path_build}libraries/${path_library_static}lib${build_name}.a ${sources} || failure=1
+      fi
+    fi
+
+    if [[ ${failure} -eq 0 && ${sources_program} != "" ]] ; then
+      sources=
+      links=
+
+      if [[ ${sources_library} != "" || ${sources_library_static} != "" ]] ; then
+        links="-l${build_name} "
+      fi
+
+      if [[ ${objects_program} != "" || ${objects_program_static} != "" ]] ; then
+        for i in ${objects_program} ${objects_program_static} ; do
+          sources="${sources}${path_build}objects/${path_object_static}${i} "
+        done
+      fi
+
+      for i in ${sources_program} ${sources_program_static} ; do
+        sources="${sources}${path_sources}${path_language}${i} "
+      done
+
+      if [[ ${verbosity} == "verbose" ]] ; then
+        echo ${build_compiler} ${sources} -static -o ${path_build}programs/${path_program_static}${build_name} ${arguments_static} ${arguments_include} ${links} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_program} ${flags_program_static} ${defines} ${defines_static} ${defines_program} ${defines_program_static} ${define_extra}
+      fi
+
+      ${build_compiler} ${sources} -static -o ${path_build}programs/${path_program_static}${build_name} ${arguments_static} ${arguments_include} ${links} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_program} ${flags_program_static} ${defines} ${defines_static} ${defines_program} ${defines_program_static} ${define_extra} || failure=1
+    fi
+
+    if [[ ${failure} -eq 0 ]] ; then
+      touch ${project_built_static}-${settings_name}.built
+    fi
+  fi
+
+  if [[ ${failure} -eq 1 ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: Failed to build.${c_reset}"
+    fi
+
+    let failure=1
+
+    return 1
+  fi
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  return 0
+}
+
+bootstrap_operation_build_prepare_defaults() {
+  local key=
+
+  bootstrap_id "has-version_major_prefix-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-version_major_prefix"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      version_major_prefix="."
+    fi
+  fi
+
+  bootstrap_id "has-version_minor_prefix-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-version_minor_prefix"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      version_minor_prefix="."
+    fi
+  fi
+
+  bootstrap_id "has-version_micro_prefix-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-version_micro_prefix"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      version_micro_prefix="."
+    fi
+  fi
+
+  bootstrap_id "has-version_nano_prefix-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-version_nano_prefix"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      version_nano_prefix="."
+    fi
+  fi
+
+  bootstrap_id "has-build_compiler-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-build_compiler"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      build_compiler="gcc"
+    fi
+  fi
+
+  bootstrap_id "has-build_indexer-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-build_indexer"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      build_indexer="ar"
+    fi
+  fi
+
+  bootstrap_id "has-path_library_script-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_library_script"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_library_script="script/"
+    fi
+  fi
+
+  bootstrap_id "has-path_library_shared-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_library_shared"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_library_shared="shared/"
+    fi
+  fi
+
+  bootstrap_id "has-path_library_static-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_library_static"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_library_static="static/"
+    fi
+  fi
+
+  bootstrap_id "has-path_object_script-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_object_script"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_object_script="script/"
+    fi
+  fi
+
+  bootstrap_id "has-path_object_shared-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_object_shared"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_object_shared="shared/"
+    fi
+  fi
+
+  bootstrap_id "has-path_object_static-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_object_static"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_object_static="static/"
+    fi
+  fi
+
+  bootstrap_id "has-path_program_script-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_program_script"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_program_script="script/"
+    fi
+  fi
+
+  bootstrap_id "has-path_program_shared-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_program_shared"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_program_shared="shared/"
+    fi
+  fi
+
+  bootstrap_id "has-path_program_static-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_program_static"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_program_static="static/"
+    fi
+  fi
+
+  bootstrap_id "has-path_sources-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_sources"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_sources="sources/"
+    fi
+  fi
+
+  bootstrap_id "has-path_sources_object-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-path_sources_object"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      path_sources_object="sources/"
+    fi
+  fi
+
+  bootstrap_id "has-has_path_standard-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-has_path_standard"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      has_path_standard="yes"
+    fi
+  fi
+
+  bootstrap_id "has-search_shared-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-search_shared"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      search_shared="yes"
+    fi
+  fi
+
+  bootstrap_id "has-build_shared-mode"
+  if [[ ${variables[${key}]} != "yes" ]] ; then
+
+    bootstrap_id "has-build_shared"
+    if [[ ${variables[${key}]} != "yes" ]] ; then
+      build_shared="yes"
+    fi
+  fi
+}
+
+bootstrap_operation_build_prepare_defines() {
+  local key=
+
+  bootstrap_id "defines-mode"
+  if [[ ${defines} == "" ]] ; then
+    defines=${variables[${key}]}
+  else
+    defines="${defines} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_library-mode"
+  if [[ ${defines_library} == "" ]] ; then
+    defines_library=${variables[${key}]}
+  else
+    defines_library="${defines_library} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_library_shared-mode"
+  if [[ ${defines_library_shared} == "" ]] ; then
+    defines_library_shared=${variables[${key}]}
+  else
+    defines_library_shared="${defines_library_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_library_static-mode"
+  if [[ ${defines_library_static} == "" ]] ; then
+    defines_library_static=${variables[${key}]}
+  else
+    defines_library_static="${defines_library_static} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_object_library-mode"
+  if [[ ${defines_object_library} == "" ]] ; then
+    defines_object_library=${variables[${key}]}
+  else
+    defines_object_library="${defines_object_library} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_object_library_shared-mode"
+  if [[ ${defines_object_library_shared} == "" ]] ; then
+    defines_object_library_shared=${variables[${key}]}
+  else
+    defines_object_library_shared="${defines_object_library_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_object_library_static-mode"
+  if [[ ${defines_object_library_static} == "" ]] ; then
+    defines_object_library_static=${variables[${key}]}
+  else
+    defines_object_library_static="${defines_object_library_static} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_object_program-mode"
+  if [[ ${defines_object_program} == "" ]] ; then
+    defines_object_program=${variables[${key}]}
+  else
+    defines_object_program="${defines_object_program} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_object_program_shared-mode"
+  if [[ ${defines_object_program_shared} == "" ]] ; then
+    defines_object_program_shared=${variables[${key}]}
+  else
+    defines_object_program_shared="${defines_object_program_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_object_program_static-mode"
+  if [[ ${defines_object_program_static} == "" ]] ; then
+    defines_object_program_static=${variables[${key}]}
+  else
+    defines_object_program_static="${defines_object_program_static} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_program-mode"
+  if [[ ${defines_program} == "" ]] ; then
+    defines_program=${variables[${key}]}
+  else
+    defines_program="${defines_program} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_program_shared-mode"
+  if [[ ${defines_program_shared} == "" ]] ; then
+    defines_program_shared=${variables[${key}]}
+  else
+    defines_program_shared="${defines_program_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_program_static-mode"
+  if [[ ${defines_program_static} == "" ]] ; then
+    defines_program_static=${variables[${key}]}
+  else
+    defines_program_static="${defines_program_static} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_shared-mode"
+  if [[ ${defines_shared} == "" ]] ; then
+    defines_shared=${variables[${key}]}
+  else
+    defines_shared="${defines_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "defines_static-mode"
+  if [[ ${defines_static} == "" ]] ; then
+    defines_static=${variables[${key}]}
+  else
+    defines_static="${defines_static} ${variables[${key}]}"
+  fi
+}
+
+bootstrap_operation_build_prepare_documentation() {
+  local key=
+
+  bootstrap_id "build_sources_documentation-mode"
+  if [[ ${sources_documentation} == "" ]] ; then
+    sources_documentation=${variables[${key}]}
+  else
+    sources_documentation="${sources_documentation} ${variables[${key}]}"
+  fi
+}
+
+bootstrap_operation_build_prepare_flags() {
+  local key=
+
+  bootstrap_id "flags-mode"
+  if [[ ${flags} == "" ]] ; then
+    flags=${variables[${key}]}
+  else
+    flags="${flags} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_library-mode"
+  if [[ ${flags_library} == "" ]] ; then
+    flags_library=${variables[${key}]}
+  else
+    flags_library="${flags_library} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_library_shared-mode"
+  if [[ ${flags_library_shared} == "" ]] ; then
+    flags_library_shared=${variables[${key}]}
+  else
+    flags_library_shared="${flags_library_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_library_static-mode"
+  if [[ ${flags_library_static} == "" ]] ; then
+    flags_library_static=${variables[${key}]}
+  else
+    flags_library_static="${flags_library_static} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_object_library-mode"
+  if [[ ${flags_object_library} == "" ]] ; then
+    flags_object_library=${variables[${key}]}
+  else
+    flags_object_library="${flags_object_library} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_object_library_shared-mode"
+  if [[ ${flags_object_library_shared} == "" ]] ; then
+    flags_object_library_shared=${variables[${key}]}
+  else
+    flags_object_library_shared="${flags_object_library_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_object_library_static-mode"
+  if [[ ${flags_object_library_static} == "" ]] ; then
+    flags_object_library_static=${variables[${key}]}
+  else
+    flags_object_library_static="${flags_object_library_static} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_object_program-mode"
+  if [[ ${flags_object_program} == "" ]] ; then
+    flags_object_program=${variables[${key}]}
+  else
+    flags_object_program="${flags_object_program} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_object_program_shared-mode"
+  if [[ ${flags_object_program_shared} == "" ]] ; then
+    flags_object_program_shared=${variables[${key}]}
+  else
+    flags_object_program_shared="${flags_object_program_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_object_program_static-mode"
+  if [[ ${flags_object_program_static} == "" ]] ; then
+    flags_object_program_static=${variables[${key}]}
+  else
+    flags_object_program_static="${flags_object_program_static} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_program-mode"
+  if [[ ${flags_program} == "" ]] ; then
+    flags_program=${variables[${key}]}
+  else
+    flags_program="${flags_program} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_program_shared-mode"
+  if [[ ${flags_program_shared} == "" ]] ; then
+    flags_program_shared=${variables[${key}]}
+  else
+    flags_program_shared="${flags_program_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_program_static-mode"
+  if [[ ${flags_program_static} == "" ]] ; then
+    flags_program_static=${variables[${key}]}
+  else
+    flags_program_static="${flags_program_static} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_shared-mode"
+  if [[ ${flags_shared} == "" ]] ; then
+    flags_shared=${variables[${key}]}
+  else
+    flags_shared="${flags_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "flags_static-mode"
+  if [[ ${flags_static} == "" ]] ; then
+    flags_static=${variables[${key}]}
+  else
+    flags_static="${flags_static} ${variables[${key}]}"
+  fi
+}
+
+bootstrap_operation_build_prepare_headers() {
+  local key=
+
+  bootstrap_id "build_sources_headers-mode"
+  if [[ ${sources_headers} == "" ]] ; then
+    sources_headers=${variables[${key}]}
+  else
+    sources_headers="${sources_headers} ${variables[${key}]}"
+  fi
+
+  if [[ ${build_shared} == "yes" ]] ; then
+    bootstrap_id "build_sources_headers_shared"
+    if [[ ${sources_headers} == "" ]] ; then
+      sources_headers=${variables[${key}]}
+    else
+      sources_headers="${sources_headers} ${variables[${key}]}"
+    fi
+
+    bootstrap_id "build_sources_headers_static"
+    if [[ ${sources_headers} == "" ]] ; then
+      sources_headers=${variables[${key}]}
+    else
+      sources_headers="${sources_headers} ${variables[${key}]}"
+    fi
+  fi
+
+  if [[ ${build_static} == "yes" ]] ; then
+    bootstrap_id "build_sources_headers_shared-mode"
+    if [[ ${sources_headers} == "" ]] ; then
+      sources_headers=${variables[${key}]}
+    else
+      sources_headers="${sources_headers} ${variables[${key}]}"
+    fi
+
+    bootstrap_id "build_sources_headers_static-mode"
+    if [[ ${sources_headers} == "" ]] ; then
+      sources_headers=${variables[${key}]}
+    else
+      sources_headers="${sources_headers} ${variables[${key}]}"
+    fi
+  fi
+
+  bootstrap_id "path_headers-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_headers=${variables[${key}]}
+  else
+    bootstrap_id "path_headers"
+    if [[ ${variables[${key}]} != "" ]] ; then
+      path_headers=${variables[${key}]}
+    fi
+  fi
+
+  if [[ ${path_headers} != "" ]] ; then
+    path_headers=$(echo ${path_headers} | sed -e 's|/*$|/|')
+  fi
+}
+
+bootstrap_operation_build_prepare_libraries() {
+  local key=
+
+  bootstrap_id "build_libraries-mode"
+  if [[ ${libraries} == "" ]] ; then
+    libraries=${variables[${key}]}
+  else
+    libraries="${variables[${key}]} ${libraries}"
+  fi
+
+  bootstrap_id "build_libraries_shared-mode"
+  if [[ ${libraries_shared} == "" ]] ; then
+    libraries_shared=${variables[${key}]}
+  else
+    libraries_shared="${variables[${key}]} ${libraries_shared}"
+  fi
+
+  bootstrap_id "build_libraries_static-mode"
+  if [[ ${libraries_static} == "" ]] ; then
+    libraries_static=${variables[${key}]}
+  else
+    libraries_static="${variables[${key}]} ${libraries_static}"
+  fi
+
+  bootstrap_id "build_sources_library-mode"
+  if [[ ${sources_library} == "" ]] ; then
+    sources_library=${variables[${key}]}
+  else
+    sources_library="${sources_library} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "build_sources_library_shared-mode"
+  if [[ ${sources_library_shared} == "" ]] ; then
+    sources_library_shared=${variables[${key}]}
+  else
+    sources_library_shared="${build_sources_library_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "build_sources_library_static-mode"
+  if [[ ${sources_library_static} == "" ]] ; then
+    sources_library_static=${variables[${key}]}
+  else
+    sources_library_static="${build_sources_library_static} ${variables[${key}]}"
+  fi
+}
+
+bootstrap_operation_build_prepare_objects() {
+  local key=
+
+  bootstrap_id "build_objects_library-mode"
+  if [[ ${objects_library} == "" ]] ; then
+    objects_library=${variables[${key}]}
+  else
+    objects_library="${variables[${key}]} ${objects_library}"
+  fi
+
+  bootstrap_id "build_objects_library_shared-mode"
+  if [[ ${objects_library_shared} == "" ]] ; then
+    objects_library_shared=${variables[${key}]}
+  else
+    objects_library_shared="${variables[${key}]} ${objects_library_shared}"
+  fi
+
+  bootstrap_id "build_objects_library_static-mode"
+  if [[ ${objects_library_static} == "" ]] ; then
+    objects_library_static=${variables[${key}]}
+  else
+    objects_library_static="${variables[${key}]} ${objects_library_static}"
+  fi
+
+  bootstrap_id "build_objects_program-mode"
+  if [[ ${objects_program} == "" ]] ; then
+    objects_program=${variables[${key}]}
+  else
+    objects_program="${variables[${key}]} ${objects_program}"
+  fi
+
+  bootstrap_id "build_objects_program_shared-mode"
+  if [[ ${objects_program_shared} == "" ]] ; then
+    objects_program_shared=${variables[${key}]}
+  else
+    objects_program_shared="${variables[${key}]} ${objects_program_shared}"
+  fi
+
+  bootstrap_id "build_objects_program_static-mode"
+  if [[ ${objects_program_static} == "" ]] ; then
+    objects_program_static=${variables[${key}]}
+  else
+    objects_program_static="${variables[${key}]} ${objects_program_static}"
+  fi
+
+  if [[ ${sources_object} == "" ]] ; then
+    bootstrap_id "build_sources_object-mode"
+    sources_object=${variables[${key}]}
+  fi
+
+  if [[ ${sources_object_shared} == "" ]] ; then
+    bootstrap_id "build_sources_object_shared-mode"
+    sources_object_shared=${variables[${key}]}
+  fi
+
+  if [[ ${sources_object_static} == "" ]] ; then
+    bootstrap_id "build_sources_object_static-mode"
+    sources_object_static=${variables[${key}]}
+  fi
+}
+
+bootstrap_operation_build_prepare_paths() {
+  local key=
+
+  if [[ ${override_path_sources} == "" ]] ; then
+    bootstrap_id "path_sources-mode"
+    if [[ ${variables[${key}]} != "" ]] ; then
+      path_sources=${variables[${key}]}
+    else
+      bootstrap_id "path_sources"
+      if [[ ${variables[${key}]} != "" ]] ; then
+        path_sources=${variables[${key}]}
+      fi
+    fi
+  fi
+
+  if [[ ${path_sources} != "" ]] ; then
+    path_sources=$(echo ${path_sources} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_sources_object-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_sources_object=${variables[${key}]}
+  else
+    bootstrap_id "path_sources_object"
+    if [[ ${variables[${key}]} != "" ]] ; then
+      path_sources_object=${variables[${key}]}
+    fi
+  fi
+
+  if [[ ${path_sources_object} != "" ]] ; then
+    path_sources_object=$(echo ${path_sources_object} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_headers-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_headers=${variables[${key}]}
+  fi
+
+  if [[ ${path_headers} != "" ]] ; then
+    path_headers=$(echo ${path_headers} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "has_path_standard-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    has_path_standard=${variables[${key}]}
+  fi
+
+  if [[ ${has_path_standard} == "no" ]] ; then
+    path_language=
+  else
+    bootstrap_id "path_language-mode"
+    if [[ ${variables[${key}]} != "" ]] ; then
+      path_language=${variables[${key}]}
+    else
+      bootstrap_id "path_language"
+      if [[ ${variables[${key}]} != "" ]] ; then
+        path_language=${variables[${key}]}
+      fi
+    fi
+
+    if [[ ${path_language} != "" ]] ; then
+      path_language=$(echo ${path_language} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+    fi
+  fi
+
+  bootstrap_id "path_object_library-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_library=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_library} != "" ]] ; then
+    path_object_library=$(echo ${path_object_library} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_program-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_program=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_program} != "" ]] ; then
+    path_object_program=$(echo ${path_object_program} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_library_script-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_library_script=${variables[${key}]}
+  fi
+
+  if [[ ${path_library_script} != "" ]] ; then
+    path_library_script=$(echo ${path_library_script} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_library_shared-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_library_shared=${variables[${key}]}
+  fi
+
+  if [[ ${path_library_shared} != "" ]] ; then
+    path_library_shared=$(echo ${path_library_shared} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_library_static-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_library_static=${variables[${key}]}
+  fi
+
+  if [[ ${path_library_static} != "" ]] ; then
+    path_library_static=$(echo ${path_library_static} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_library_script-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_library_script=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_library_script} != "" ]] ; then
+    path_object_library_script=$(echo ${path_object_library_script} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_library_shared-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_library_shared=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_library_shared} != "" ]] ; then
+    path_object_library_shared=$(echo ${path_object_library_shared} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_library_static-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_library_static=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_library_static} != "" ]] ; then
+    path_object_library_static=$(echo ${path_object_library_static} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_program_script-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_program_script=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_program_script} != "" ]] ; then
+    path_object_program_script=$(echo ${path_object_program_script} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_program_shared-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_program_shared=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_program_shared} != "" ]] ; then
+    path_object_program_shared=$(echo ${path_object_program_shared} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_program_static-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_program_static=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_program_static} != "" ]] ; then
+    path_object_program_static=$(echo ${path_object_program_static} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_script-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_script=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_script} != "" ]] ; then
+    path_object_script=$(echo ${path_object_script} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_shared-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_shared=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_shared} != "" ]] ; then
+    path_object_shared=$(echo ${path_object_shared} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_object_static-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_object_static=${variables[${key}]}
+  fi
+
+  if [[ ${path_object_static} != "" ]] ; then
+    path_object_static=$(echo ${path_object_static} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  if [[ ${path_object_static} != "" ]] ; then
+    path_object_static=$(echo ${path_object_static} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_program_script-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_program_script=${variables[${key}]}
+  fi
+
+  if [[ ${path_program_script} != "" ]] ; then
+    path_program_script=$(echo ${path_program_script} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_program_shared-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_program_shared=${variables[${key}]}
+  fi
+
+  if [[ ${path_program_shared} != "" ]] ; then
+    path_program_shared=$(echo ${path_program_shared} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  bootstrap_id "path_program_static-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    path_program_static=${variables[${key}]}
+  fi
+
+  if [[ ${path_program_static} != "" ]] ; then
+    path_program_static=$(echo ${path_program_static} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+
+  if [[ ${path_program_static} != "" ]] ; then
+    path_program_static=$(echo ${path_program_static} | sed -e 's|//*|/|g' -e 's|/*$|/|')
+  fi
+}
+
+bootstrap_operation_build_prepare_programs() {
+  local key=
+
+  bootstrap_id "build_sources_program-mode"
+  if [[ ${sources_program} == "" ]] ; then
+    sources_program=${variables[${key}]}
+  else
+    sources_program="${sources_program} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "build_sources_program_shared-mode"
+  if [[ ${sources_program_shared} == "" ]] ; then
+    sources_program_shared=${variables[${key}]}
+  else
+    sources_program_shared="${sources_program_shared} ${variables[${key}]}"
+  fi
+
+  bootstrap_id "build_sources_program_static-mode"
+  if [[ ${sources_program_static} == "" ]] ; then
+    sources_program_static=${variables[${key}]}
+  else
+    sources_program_static="${sources_program_static} ${variables[${key}]}"
+  fi
+}
+
+bootstrap_operation_build_prepare_remaining() {
+  local key=
+
+  bootstrap_id "has-build_compiler-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "build_compiler-mode"
+    build_compiler=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-build_indexer-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "build_indexer-mode"
+    build_indexer=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-build_indexer_arguments-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "build_indexer_arguments-mode"
+    build_indexer_arguments=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-build_name-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "build_name-mode"
+    build_name=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-version_major-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "version_major-mode"
+    version_major=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-version_major_prefix-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "version_major_prefix-mode"
+    version_major_prefix=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-version_minor-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "version_minor-mode"
+    version_minor=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-version_minor_prefix-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "version_minor_prefix-mode"
+    version_minor_prefix=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-version_micro-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "version_micro-mode"
+    version_micro=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-version_micro_prefix-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "version_micro_prefix-mode"
+    version_micro_prefix=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-version_nano-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "version_nano-mode"
+    version_nano=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-version_nano_prefix-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "version_nano_prefix-mode"
+    version_nano_prefix=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_headers-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_headers-mode"
+    path_headers=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-preserve_path_headers-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "preserve_path_headers-mode"
+    preserve_path_headers=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_library_script-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_library_script-mode"
+    path_library_script=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_library_shared-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_library_shared-mode"
+    path_library_shared=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_library_static-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_library_static-mode"
+    path_library_static=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_object_script-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_object_script-mode"
+    path_object_script=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_object_shared-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_object_shared-mode"
+    path_object_shared=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_object_static-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_object_static-mode"
+    path_object_static=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_program_script-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_program_script-mode"
+    path_program_script=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_program_shared-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_program_shared-mode"
+    path_program_shared=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-path_program_static-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "path_program_static-mode"
+    path_program_static=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-has_path_standard-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "has_path_standard-mode"
+    has_path_standard=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-search_exclusive-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "search_exclusive-mode"
+    search_exclusive=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-search_shared-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "search_shared-mode"
+    search_shared=${variables[${key}]}
+  fi
+
+  bootstrap_id "has-search_static-mode"
+  if [[ ${variables[${key}]} == "yes" ]] ; then
+    bootstrap_id "search_static-mode"
+    search_static=${variables[${key}]}
+  fi
+}
+
+bootstrap_operation_build_prepare_settings() {
+  local key=
+
+  bootstrap_id "build_sources_setting-mode"
+  if [[ ${sources_setting} == "" ]] ; then
+    sources_setting=${variables[${key}]}
+  else
+    sources_setting="${sources_setting} ${variables[${key}]}"
+  fi
+}
+
+bootstrap_operation_build_prepare_shared_static() {
+  local key=
+
+  bootstrap_id "build_shared-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    build_shared=${variables[${key}]}
+  fi
+
+  bootstrap_id "build_static-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    build_static=${variables[${key}]}
+  fi
+
+  if [[ ${enable_shared} == "yes" ]] ; then
+    build_shared="yes"
+    search_shared="yes"
+  elif [[ ${enable_shared} == "no" ]] ; then
+    build_shared="no"
+    search_shared="no"
+  fi
+
+  if [[ ${enable_static} == "yes" ]] ; then
+    build_static="yes"
+    search_static="yes"
+  elif [[ ${enable_static} == "no" ]] ; then
+    build_static="no"
+    search_static="no"
+  fi
+
+  if [[ ${search_shared} == "no" ]] ; then
+    arguments_shared=
+  fi
+
+  if [[ ${search_static} == "no" ]] ; then
+    arguments_static=
+  fi
+}
+
+bootstrap_operation_build_validate_build() {
+
+  if [[ ${build_compiler} == "" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: Cannot Build, no '${c_notice}build_compiler${c_error}' specified, such as '${c_notice}gcc${c_error}'.${c_reset}"
+    fi
+
+    let failure=1
+  fi
+
+  if [[ ${build_indexer} == "" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: Cannot Build, no '${c_notice}build_indexer${c_error}' specified, such as '${c_notice}ar${c_error}'.${c_reset}"
+    fi
+
+    let failure=1
+  fi
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  return 0
+}
+
+bootstrap_operation_build_validate_paths() {
+
+  if [[ ${path_sources} == "" || ! -d ${path_sources} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The sources directory ${c_notice}${path_sources}${c_error} is not a valid directory.${c_reset}"
+    fi
+
+    let failure=1
+  fi
+
+  if [[ ${failure} -eq 0 && ${path_sources_object} != "" && ! -d ${path_sources_object} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: The sources object directory ${c_notice}${path_sources_object}${c_error} is not a valid directory.${c_reset}"
+    fi
+
+    let failure=1
+  fi
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  return 0
+}
+
+bootstrap_operation_build_validate_search() {
+
+  # When not in search exclusive mode, allow static libraries to be linked into shared libraries if the shared library is not found first.
+  if [[ ${search_exclusive} == "no" ]] ; then
+    arguments_shared="${arguments_shared} ${arguments_static}"
+  fi
+}
+
+bootstrap_operation_build_validate_shared_static() {
+
+  if [[ ${build_shared} != "yes" && ${build_static} != "yes" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: Cannot Build, either build_shared or build_static must be set to 'yes'.${c_reset}"
+    fi
+
+    let failure=1
+  fi
+
+  if [[ ${search_shared} != "yes" && ${search_static} != "yes" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      bootstrap_print_first
+
+      echo -e "${c_error}ERROR: Cannot Build, either search_shared or search_static must be set to 'yes'.${c_reset}"
+    fi
+
+    let failure=1
+  fi
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  return 0
+}
+
+bootstrap_operation_build_validate_sources() {
+
+  for i in ${sources_script} ; do
+    if [[ ${i} != "$(echo ${i} | sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||')" ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_script path provided: '${i}'.${c_reset}"
+      fi
+
+      let failure=1
+    fi
+  done
+
+  for i in ${sources_headers} ; do
+    if [[ ${i} != "$(echo ${i} | sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||')" ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_headers path provided: '${i}'.${c_reset}"
+      fi
+
+      let failure=1
+    fi
+  done
+
+  for i in ${sources_library} ; do
+    if [[ ${i} != "$(echo ${i} | sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||')" ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_library path provided: '${i}'.${c_reset}"
+      fi
+
+      let failure=1
+    fi
+  done
+
+  for i in ${sources_library_object} ; do
+    if [[ ${i} != "$(echo ${i} | sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||')" ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_library_object path provided: '${i}'.${c_reset}"
+      fi
+
+      let failure=1
+    fi
+  done
+
+  for i in ${sources_program_object} ; do
+    if [[ ${i} != "$(echo ${i} | sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||')" ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_program_object path provided: '${i}'.${c_reset}"
+      fi
+
+      let failure=1
+    fi
+  done
+
+  for i in ${sources_program} ; do
+    if [[ ${i} != "$(echo ${i} | sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||')" ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_program path provided: '${i}'.${c_reset}"
+      fi
+
+      let failure=1
+    fi
+  done
+
+  for i in ${sources_documentation} ; do
+    if [[ ${i} != "$(echo ${i} | sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||')" ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_documentation path provided: '${i}'.${c_reset}"
+      fi
+
+      let failure=1
+    fi
+  done
+
+  for i in ${sources_setting} ; do
+    if [[ ${i} != "$(echo ${i} | sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||')" ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        bootstrap_print_first
+
+        echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_setting path provided: '${i}'.${c_reset}"
+      fi
+
+      let failure=1
+    fi
+  done
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  return 0
+}
+
+bootstrap_operation_build_prepare_versions() {
+  local key=
+
+  bootstrap_id "version_file-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    version_file_value=${variables[${key}]}
+  fi
+
+  bootstrap_id "version_target-mode"
+  if [[ ${variables[${key}]} != "" ]] ; then
+    version_target_value=${variables[${key}]}
+  fi
+
+  if [[ ${version_file_value} == "" ]] ; then
+    version_file_value="micro"
+  fi
+
+  if [[ ${version_target_value} == "" ]] ; then
+    version_target_value="major"
+  fi
+
+  if [[ ${version_major} == "" ]] ; then
+    version_major_prefix=
+  fi
+
+  if [[ ${version_minor} == "" ]] ; then
+    version_minor_prefix=
+  fi
+
+  if [[ ${version_micro} == "" ]] ; then
+    version_micro_prefix=
+  fi
+
+  if [[ ${version_nano} == "" ]] ; then
+    version_nano_prefix=
+  fi
+
+  if [[ ${version_file_value} == "major" ]] ; then
+    version_file="${version_major_prefix}${version_major}"
+  elif [[ ${version_file_value} == "minor" ]] ; then
+    version_file="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}"
+  elif [[ ${version_file_value} == "micro" ]] ; then
+    version_file="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro}"
+  elif [[ ${version_file_value} == "nano" ]] ; then
+    version_file="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro}${version_nano_prefix}${version_nano}"
+  fi
+
+  if [[ ${version_target_value} == "major" ]] ; then
+    version_target="${version_major_prefix}${version_major}"
+  elif [[ ${version_target_value} == "minor" ]] ; then
+    version_target="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}"
+  elif [[ ${version_target_value} == "micro" ]] ; then
+    version_target="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro}"
+  elif [[ ${version_target_value} == "nano" ]] ; then
+    version_target="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro}${version_nano_prefix}${version_nano}"
+  fi
+}
+
+bootstrap_operation_clean() {
+
+  local i=
+
+  for i in ${path_build}{documents,documentation,includes,libraries,objects,programs,settings,stage} ; do
+    if [[ -e ${i} ]] ; then
+      rm ${verbose_common} -Rf ${i}
+    fi
+  done
+
+  if [[ -f ${project_built}.prepared ]] ; then
+    rm ${verbose_common} -f ${project_built}-${settings_name}.prepared
+  fi
+
+  if [[ -f ${project_built_shared}-${settings_name}.built ]] ; then
+    rm ${verbose_common} -f ${project_built_shared}-${settings_name}.built
+  fi
+
+  if [[ -f ${project_built_static}-${settings_name}.built ]] ; then
+    rm ${verbose_common} -f ${project_built_static}-${settings_name}.built
+  fi
+}
+
+bootstrap_print_first() {
+
+  if [[ ${print_line_first} == "yes" ]] ; then
+    echo
+
+    print_line_first=
+  fi
+}
+
+bootstrap_print_last() {
+
+  if [[ ${print_line_last} == "yes" ]] ; then
+    echo
+  fi
+}
+
+bootstrap_cleanup() {
+
+  unset bootstrap_copyright
+  unset bootstrap_main
+  unset bootstrap_handle_colors
+  unset bootstrap_help
+  unset bootstrap_id
+  unset bootstrap_load_settings
+  unset bootstrap_load_settings_mode
+  unset bootstrap_prepare_build
+  unset bootstrap_operation_build
+  unset bootstrap_operation_build_prepare_defaults
+  unset bootstrap_operation_build_prepare_defines
+  unset bootstrap_operation_build_prepare_documentation
+  unset bootstrap_operation_build_prepare_flags
+  unset bootstrap_operation_build_prepare_headers
+  unset bootstrap_operation_build_prepare_libraries
+  unset bootstrap_operation_build_prepare_objects
+  unset bootstrap_operation_build_prepare_paths
+  unset bootstrap_operation_build_prepare_programs
+  unset bootstrap_operation_build_prepare_remaining
+  unset bootstrap_operation_build_prepare_settings
+  unset bootstrap_operation_build_prepare_shared_static
+  unset bootstrap_operation_build_prepare_versions
+  unset bootstrap_operation_build_validate_build
+  unset bootstrap_operation_build_validate_paths
+  unset bootstrap_operation_build_validate_search
+  unset bootstrap_operation_build_validate_shared_static
+  unset bootstrap_operation_build_validate_sources
+  unset bootstrap_operation_clean
+  unset bootstrap_print_first
+  unset bootstrap_print_last
+  unset bootstrap_cleanup
+}
+
+bootstrap_main $*
diff --git a/build/documentation/man/man1/controller.1 b/build/documentation/man/man1/controller.1
new file mode 100644 (file)
index 0000000..80c49e5
--- /dev/null
@@ -0,0 +1,102 @@
+.TH CONTROLLER "1" "January 2023" "FLL - Controller 0.7.0" "User Commands"
+.SH NAME
+controller \- Perform a series of operations in a manner similar to that of an init program.
+.SH SYNOPSIS
+.B controller
+[\fI\,OPTIONS\/\fR] [\fI\,ENTRY\/\fR]
+.SH DESCRIPTION
+.PP
+This program performs a series of operations described by an \fBentry\fR file.
+This includes error handling.
+
+The \fBentry\fR file consists of several rules defined in individual \fBrule\fR files.
+Thee \fBrule\fR file allows for both programs and scripts to be executed.
+Any scripting language whose program supports piping commands to it are effectively supported scripting languages.
+
+Upon completion, this program may optionally process an \fBexit\fR file whose name is identical to the \fBentry\fR used.
+
+When both the \fB\-\-simulate\fR parameter and the \fB\-\-validate\fR parameter are specified, then additional information on each would be executed rule is printed but no simulation is performed.
+
+The default interrupt behavior is to operate as if the \fB\-\-interruptible\fR parameter is passed.
+
+Specify an empty string for the \fB\-\-pid\fR parameter to disable pid file creation for this program.
+.SH OPTIONS
+.TP
+\fB\{\-h, \-\-help\fR
+Print the help message.
+.TP
+\fB+C, ++copyright\fR
+Print the copyright.
+.TP
+\fB+d, ++dark\fR
+Output using colors that show up better on dark backgrounds.
+.TP
+\fB+l, ++light\fR
+Output using colors that show up better on light backgrounds.
+.TP
+\fB+n, ++no_color\fR
+Do not print using color.
+.TP
+\fB+Q, ++quiet\fR
+Decrease verbosity, silencing most output.
+.TP
+\fB+E, ++error\fR
+Decrease verbosity, using only error output.
+.TP
+\fB+N, ++normal\fR
+Set verbosity to normal.
+.TP
+\fB+V, ++verbose\fR
+Increase verbosity beyond normal output.
+.TP
+\fB+D, ++debug\fR
+Enable debugging, significantly increasing verbosity beyond normal output.
+.TP
+\fB+v, ++version\fR
+Print only the version number.
+.TP
+\fB\-c, \-\-cgroup\fR
+Specify a custom control group file path, such as '/sys/fs/cgroup/'.
+.TP
+\fB\-d, \-\-daemon\fR
+Run in daemon only mode (do not process the entry).
+.TP
+\fB\-I, \-\-init\fR
+The program will run as an init replacement.
+.TP
+\fB\-i, \-\-interruptible\fR
+Designate that this program can be interrupted by a signal.
+.TP
+\fB\-p, \-\-pid\fR
+Specify a custom pid file path, such as 'controller/run/default.pid'.
+.TP
+\fB\-s, \-\-settings\fR
+Specify a custom settings path, such as 'controller/'.
+.TP
+\fB\-S, \-\-simulate\fR
+Run as a simulation.
+.TP
+\fB\-k, \-\-socket\fR
+Specify a custom socket file path, such as 'controller/run/default.socket'.
+.TP
+\fB\-U, \-\-uninterruptible\fR
+Designate that this program cannot be interrupted by a signal.
+.TP
+\fB\-v, \-\-validate\fR
+Validate the settings (entry and rules) without running (does not simulate).
+.SH ENTRY
+.TP
+The name of an \fBentry\fR.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-packet\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, GNU LGPL Version 2.1 or later.
diff --git a/build/documentation/man/man5/controller-actions.5 b/build/documentation/man/man5/controller-actions.5
new file mode 100644 (file)
index 0000000..eb79f8b
--- /dev/null
@@ -0,0 +1,89 @@
+.TH controller-rule "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "rule" file.
+.SH SYNOPSIS
+.B rule
+.SH DESCRIPTION
+.PP
+This describes the intent and purpose of the actions provided for individual Rules (or things related to a Rule).
+
+Each Action represents a specific intent and purpose but many of these actions are customizable via the rule file.
+One should expect an Action to operate as described here but the system administrator or distributor is fully capable of doing something different.
+For those doing something different, appropriate documentation is suggested.
+
+These actions should be usable by any \fBcontrol\fR program that communicates with this \fBcontroller\fR program.
+Should any \fBcontrol\fR or \fBcontroller\fR program implementation not support any particular Action for any reason, one should report that the Action is unsupported.
+
+\- \fBFreeze Action\fR:
+  The Freeze Action is an extension of a Control Group.
+  This is internal to the \fBcontroller\fR program and is not customizable via any Rule file.
+  For a customizable \fBfreeze\fR\-like capability, look into the Pause and Resume Actions.
+  This is the complement of the Thaw Action.
+
+  This designates that a processes Control Group is to be frozen.
+  All Rules (or any process not controlled by the \fBcontroller\fR) that is within the same Control Group will be frozen.
+  (@todo consider instead designing this around the Control Groups instead of a \fBrule\fR.)
+  (This documentation will likely change with consideration to the above @todo once this gets implemented.)
+
+  This must not attempt to freeze (or unfreeze) the Control Group that the \fBcontroller\fR belongs to.
+  Therefore, if a Rule does not specify a Control Group, then it is likely that the Freeze Action will be unsupported for that Rule/Control Group.
+
+\- \fBKill Action\fR:
+  Forcefully terminate some process controlled by the \fBcontroller\fR.
+  This action cannot be blocked and it is recommended to use a Stop Action instead for a more proper termination.
+
+\- \fBPause Action\fR:
+  The Pause Action will pause (or freeze) the process controlled by the Rule.
+  Although similar to the Freeze Action, this is intended to communicate to an individual process and inform to Pause.
+  This is complemented by the Resume Action.
+
+\- \fBRestart Action\fR:
+  The Restart Action will either perform a Stop Action and then a Restart Action or it will perform the Restart Action designated in some Rule file.
+  Ideally this should inform some process to perform its own restart routines.
+
+\- \fBResume Action\fR:
+  The Resume Action will unpause (or unfreeze) the process controlled by the Rule.
+  Although similar to the Thaw Action, this is intended to communicate to an individual process and inform to Resume.
+  This is complemented by the Pause Action.
+
+\- \fBReload Action\fR:
+  The Reload Action will perform the Reload Action designated in some Rule file.
+  Ideally this should inform some process to perform its own reload routines.
+  Many programs often differentiate the concept \fBreload\fR from the concept "restart" in that the program remains running during a \fBreload\fR.
+
+\- \fBStart Action\fR:
+  The Start Action will perform the Start Action designated in some Rule file.
+  This action should be used to start some program or script.
+  This is the action called by Entry file.
+  This is complemented by the Stop Action.
+
+\- \fBStop Action\fR:
+  The Stop Action will perform the Stop Action designated in some Rule file.
+  This action should be used to stop some program or script.
+  This is the action called for all running controlled processes on shutdown.
+  This is complemented by the Start Action.
+
+\- \fBThaw Action\fR:
+  The Thaw Action is an extension of a Control Group.
+  This is internal to the \fBcontroller\fR program and is not customizable via any Rule file.
+  For a customizable \fBthaw\fR\-like capability, look into the \fBpause\fR and \fBresume\fR Actions.
+  This is complemented by the Freeze Action.
+
+  This designates that a processes Control Group is to be unfrozen.
+  All Rules (or any process not controlled by the \fBcontroller\fR) that is within the same Control Group will be unfrozen.
+
+  This must not attempt to thaw (or unthaw) the Control Group that the \fBcontroller\fR belongs to.
+  Therefore, if a Rule does not specify a Control Group, then it is likely that the Thaw Action will be unsupported for that Rule/Control Group.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-packet\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/build/documentation/man/man5/controller-entry.5 b/build/documentation/man/man5/controller-entry.5
new file mode 100644 (file)
index 0000000..976bcf3
--- /dev/null
@@ -0,0 +1,352 @@
+.TH controller-entry "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "entry" file.
+.SH SYNOPSIS
+.B entry
+.SH DESCRIPTION
+.PP
+This describes the intent and purpose of an Entry file.
+
+An Entry file, such as \fBdefault.entry\fR, is intended to store a set of rules in which the controller will process on execution.
+These are used to run some set of commands, such as booting a system.
+
+The \fBmain\fR Item Object is always executed first (Therefore \fBmain\fR is both reserved and required).
+All other Basic List Objects are not executed unless either an \fBitem\fR or a \fBfailsafe\fR specifies a valid Item name.
+Execution of all Items is top\-down.
+
+\- The \fBsettings\fR item Object:
+  Represents Entry settings and is not an \fBitem\fR that can be executed.
+  A number of settings are supported, but if this Item Object is not specified, then defaults are used.
+  The following settings are available: \fBcontrol\fR, \fBcontrol_group\fR, \fBcontrol_mode\fR, \fBcontrol_user\fR, \fBdefine\fR, \fBmode\fR, \fBparameter\fR, \fBpid\fR, \fBpid_file\fR, \fBsession\fR, \fBshow\fR.
+
+  \- The \fBcontrol\fR setting:
+    Represents the path to the socket file in which the Controller uses to communicate over with clients such as a Control program.
+    A relative path is relative to the Controller PID directory.
+    An absolute path is treated exactly as the path given.
+    If no socket setting is specified, then no socket will be made available.
+    This socket file is only created once \fBready\fR mode is achieved.
+
+    Providing \fBreadonly\fR after the socket path instructs the Controller program not to create or delete the Socket file because the file system is assumed to be readonly.
+    The socket file itself must therefore already exist.
+    This should be possible in the cases of file systems that have pre\-created a socket file at the designated path.
+    When \fBreadonly\fR, the group, mode, and user are also not processed effectively resulting in the \fBcontrol_group\fR, \fBcontrol_mode\fR, and \fBcontrol_user\fR settings being ignored.
+
+    Future versions might expand this into supporting network addresses in addition to socket files.
+
+  \- The \fBcontrol_group\fR setting:
+    Represents the group name or group ID to assign to the socket file as the group.
+
+  \- The \fBcontrol_mode\fR setting:
+    Represents the file mode assigned to the socket file.
+    This could either be the string version that might look like \fBu+rw\-x,g+r\-wx,o\-rwx\fR or a numeric value like \fB0750\fR.
+
+  \- The \fBcontrol_user\fR setting:
+    Represents the user name or user ID to assign to the socket file as the owner.
+
+  \- The \fBdefine\fR setting:
+    Use this to define an environment variable (this overwrites any existing environment variable with this name).
+    A define is both exported as an environment variable as well as exposed as an IKI variable.
+    Example IKI variable substitution: for \fBdefine PATH /bin:/sbin\fR, the associated IKI variable would look like: PATH.
+
+    All environment variables, including those defined using this, must be in the \fBenvironment\fR list in any given Rule to be exported to the executed process.
+    Environment variables added here that are not added to the environment are still exposed as an IKI variable.
+
+    This is only expanded within any Rule operated on by this Entry.
+
+  \- The \fBmode\fR setting:
+    Represents the mode in which the Entry is operating in.
+    The following modes are supported: \fBhelper\fR, \fBprogram\fR, and \fBservice\fR.
+
+    - The \fBhelper\fR mode:
+      Designates that the Entry operates as a helper for starting programs or performing actions and exits when complete.
+      On exit, any background (asynchronous) processes are not cancelled.
+      If terminated, the foreground (synchronous) process is cancelled.
+      Will call the \fBexit\fR with the same name as this Entry, but with the extension \fBexit\fR, such as \fBdefault.exit\fR.
+      Supports the Item Action \fBexecute\fR to execute a program (switching the \fBcontroller\fR program entirely with the executed process).
+
+    \- The \fBprogram\fR mode:
+      Designates that the Entry operates as a program and exits when complete.
+      On exit, any background (asynchronous) processes are also cancelled.
+      If terminated, the foreground (synchronous) process is cancelled.
+      Will call the \fBexit\fR with the same name as this Entry, but with the extension \fBexit\fR, such as \fBdefault.exit\fR.
+      Supports the Item Action \fBexecute\fR to execute a program (switching the \fBcontroller\fR program entirely with the executed process).
+
+    \- The \fBservice\fR mode:
+      Designates that the Entry operates as a service and will sit and wait for control commands when complete.
+      Will call the \fBexit\fR with the same name as this Entry, but with the extension \fBexit\fR, such as \fBdefault.exit\fR.
+      Does not support the Item Action \fBexecute\fR.
+      This is the default mode.
+
+  \- The \fBparameter\fR setting:
+    Use this to define an IKI variable name and value.
+    These do not conflict with environment variables and are not exposed as environment variables.
+    Example IKI variable substitution: for \fBparameter hello world\fR, the associated IKI variable would look like: hello.
+
+    This is only expanded within any Rule operated on by this Entry.
+
+  \- The \fBpid\fR setting:
+    Represents how the Entry PID file is generated or not.
+    The following modes are supported: \fBdisable\fR, \fBrequire\fR, and \fBready\fR.
+    For \fBdisable\fR, not PID file representing the Entry is created.
+    For \fBrequire\fR, check to see if the PID file exists for an Entry at startup and then when \fBready\fR create a PID file, display error on PID file already exists or on failure and then fail.
+    For \fBready\fR, when \fBready\fR create a PID file, display error on failure and then fail (does not check if PID file exists).
+
+  \- The \fBpid_file\fR setting:
+    When \fBpid\fR is not disabled this represents the path to the PID file.
+    If \fB\-p\fR or \fB\-\-pid\fR is passed to the controller program, then this value is ignored in favor of the value passed along the command line.
+
+  \- The \fBsession\fR setting:
+    Represents the default way in which child processes are executed.
+    This default can be overridden by individual Rules.
+    For \fBnew\fR, Execute Rule processes in a new session setting the process group to the executed process' id (making the executed process a \fBcontrolling terminal\fR).
+    For \fBsame\fR, Execute Rule processes in the same session where the process group is set to the parent process id.
+
+  \- The \fBshow\fR setting:
+    Represents the way Entry processing presents information to the screen.
+    This applies only to the Entry and Rule processing itself and does not handle the output of programs and scripts being executed by some Entry or Rule.
+    The following show options are supported: \fBnormal\fR and \fBinit\fR.
+    For \fBnormal\fR, will not report the start or stop of some Entry or Rule execution but will report any errors or warnings as appropriate.
+    For \fBinit\fR, will report when starting programs and may include reporting success and failure status.
+
+  \- The \fBtimeout\fR setting:
+    Represents the default timeouts for the Entry.
+    See the \fBtimeout\fR Action below for details.
+
+\- The \fBmain\fR item Object:
+  Each \fBitem\fR supports the following Action Names: \fBconsider\fR, \fBexecute\fR, \fBfailsafe\fR, \fBfreeze\fR, \fBitem\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBready\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBtimeout\fR.
+  Of those types, the following are considered a \fBrule\fR Action: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBthaw\fR.
+
+  \- The \fBconsider\fR Item Action:
+    A special case of a \fBrule\fR Action.
+    All Action Parameters are the same as with the \fBrule\fR Action Parameters.
+    The difference is that \fBconsider\fR is only processed (instead of being processed and executed) and when some \fBrule\fR Action designates that this consideration is required (via \fBneed\fR), wanted (via \fBwant\fR), or wished for (via \fBwish\fR) from the within the Rule file.
+    If this is determined to be executed, then this is immediately executed when needed, wanted or wished for and applies all properties as appropriate (such as \fBasynchronous\fR, for example).
+    If this is determined not to be executed, then this \fBconsider\fR is ignored as if it was never there in the first place.
+
+  \- The \fBexecute\fR Item Action:
+    Execute into the specified program.
+    On successful execution, the controller program will no longer be running and will be replaced with the designated program.
+    This Item Action is only supported when operating in \fBprogram\fR mode.
+
+  \- The \fBfailsafe\fR Item Action:
+    Accepts only a valid Item Name in which will be executed when a failure is detected.
+    Only a single \fBfailsafe\fR Item Action may function at a time.
+    Each successive \fBfailsafe\fR Item Action specified replaces the previously defined \fBfailsafe\fR Item Action (in a top\-down manner).
+    When operating in \fBfailsafe\fR, the \fBrequire\fR Item Action is ignored (given that it is meaningless once operating in \fBfailsafe\fR mode).
+
+  \- The \fBfreeze\fR Item Action:
+    A \fBrule\fR Action for freezing some Control Group.
+    This Item Action will process the \fBfreeze\fR inner Content of the named Rule.
+    This is specific to Control Groups and is not yet fully implemented.
+    Once implemented this documentation will need to be updated and clarified.
+
+  \- The \fBitem\fR Item Action:
+    Accepts only a valid Item Name in which will be immediately executed.
+    Any valid Item Name, except for the reserved \fBmain\fR, may be used.
+
+  \- The \fBkill\fR Item Action:
+    A \fBrule\fR Action for forcibly terminating some process.
+    This Item Action will process the \fBkill\fR inner Content of the named Rule.
+
+  \- The \fBpause\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBpause\fR inner Content of the named Rule.
+
+  \- The \fBreload\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBreload\fR inner Content of the named Rule.
+
+  \- The \fBrestart\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBrestart\fR inner Content of the named Rule.
+
+  \- The \fBresume\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBresume\fR inner Content of the named Rule.
+
+  \- The \fBready\fR Item Action:
+    Instructs the controller program when it is safe to perform normal tasks, such as creating the PID file.
+    When not specified, the state is always assumed to be ready.
+    For example, the controller program may be used as a full blown \fBinit\fR replacement and therefore may need to mount the /var/run/ directory.
+    If the PID file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready.
+    This could be a problem, such as on a read\-only file system the PID creation fails and controller bails out on error.
+    Adding \fBready\fR essentially specifies a point in time in the Entry in which things are expected to be safe for such basic operations.
+    When the optional \fBwait\fR is provided, then \fBready\fR will wait for all currently started asynchronous processes to complete before operating.
+
+  \- The \fBstart\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBstart\fR inner Content of the named Rule.
+
+  \- The \fBstop\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBstop\fR inner Content of the named Rule.
+
+  \- The \fBthaw\fR Item Action:
+    A \fBrule\fR Action for unfreezing some Control Group.
+    This Item Action will process the \fBthaw\fR inner Content of the named Rule.
+    This is specific to Control Groups and is not yet fully implemented.
+    Once implemented this documentation will need to be updated and clarified.
+
+  \- The \fBtimeout\fR Item Action:
+    (This is not currently fully implemented, only \fBexit\fR is implemented.)
+    Provides default global settings for each of the four special situations: \fBexit\fR, \fBkill\fR, \fBstart\fR, and \fBstop\fR.
+    Each of these may only have a single one exist at a time (one \fBexit\fR, one \fBkill\fR, one \fBstart\fR, and one \fBstop\fR).
+    Each successive \fBtimeout\fR Item Action, specific to each Action Name (such as \fBstart\fR), specified replaces the previously defined \fBtimeout\fR Action (in a top\-down manner).
+    The second Content for each of these, when specified, may be a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+    For \fBkill\fR, this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule).
+    For \fBstart\fR, this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed.
+    For \fBstop\fR, this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed.
+    If the second Content is not specified, then this disables the type (prevents the specified timeout action).
+    For \fBexit\fR, this represents the number of MegaTime to wait when the Controller program is exiting (such as having received a terminate signal).
+    In this case, a terminate signal is sent to all child processes.
+    The \fBexit\fR timeout represents the amount of time to wait after sending the terminate signal before sending a kill signal to each child process still running.
+    When disabled, the program will not send a kill signal will continue running until all child processes to terminate.
+    The \fBexit\fR timeout does not get applied to any Rule.
+.SH SPECIFICATION
+.PP
+The Entry files follow the \fBFSS\-0005 (Somewhat Basic List)\fR format.
+
+An Entry file name is expected to have the file extension \fB.entry\fR.
+
+For each Entry file:
+  \- The outer most part is a \fBFSS\-0002 (Basic List)\fR.
+  \- The Basic List Object is considered the \fBItem\fR.
+  \- The Basic List Content are considered the \fBActions\fR.
+  \- The \fBActions\fR are \fBFSS\-0001 (Extended)\fR.
+  \- Each Action Object is the \fBAction Name\fR.
+  \- Each Action Content are the \fBAction Parameters\fR.
+
+The Items:
+  \- \fBmain\fR: required.
+
+  \- \fBsettings\fR: optional, Actions may be one of:
+    \- \fBcontrol\fR: One to two Content.
+      The first Content is a relative or absolute path to a socket file.
+      The second Content an optional \fBreadonly\fR.
+    \- \fBcontrol_group\fR: Exactly one Content that is a group name or group id.
+    \- \fBcontrol_mode\fR: Exactly one Content that is a valid file mode.
+    \- \fBcontrol_user\fR: Exactly one Content that is a user name or user id.
+    \- \fBdefine\fR: Two Content, the first Content must be a case\-sensitive valid environment variable name (alpha\-numeric or underscore, but no leading digits).
+    \- \fBmode\fR: Exactly one Content that is one of \fBprogram\fR or \fBservice\fR.
+    \- \fBparameter\fR: Two Content, the first Content must be a case\-sensitive valid IKI name and the second being an IKI value.
+    \- \fBpid\fR: Exactly one Content that is one of \fBdisable\fR, \fBrequire\fR, or \fBready\fR.
+    \- \fBpid_file\fR: Exactly one Content that is a relative or absolute path to a pid file.
+    \- \fBsession\fR: Exactly one Content that is one of \fBnew\fR or \fBsame\fR.
+    \- \fBshow\fR: Exactly one Content that is one of \fBnormal\fR or \fBinit\fR.
+    \- \fBtimeout\fR: One or two content with the first being one of \fBexit\fR, \fBstart\fR, \fBstop\fR, or \fBkill\fR and the (optional) second Content being a positive whole number or 0.
+
+  The Entry file may have any other valid Item Objects, but only the above are reserved.
+
+  The Actions:
+    \- \fBconsider\fR: One or more Content.
+      The first Content is the relative file path (without any leading/trailing slashes and without file extension).
+      The second Content is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBexecute\fR: One or more Content.
+      The first Content is the program name or full path to the program (the program may be a script).
+      All remaining Content are passed as parameters to the program being executed.
+
+    \- \fBfailsafe\fR: One Content that is a valid Object name, except for the reserved \fBmain\fR.
+
+    \- \fBfreeze\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBitem\fR: One Content that is a valid Object name, except for the reserved \fBmain\fR.
+
+    \- \fBkill\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBpause\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBready\fR: Zero or One Content.
+      The first may only be one of:
+      \- \fBwait\fR
+
+    \- \fBreload\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBrestart\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBresume\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBstart\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBstop\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBthaw\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBtimeout\fR: One or two Content.
+      The first being one of:
+        \- \fBexit\fR
+        \- \fBstart\fR
+        \- \fBstop\fR
+        \- \fBkill\fR
+      The (optional) second Content being a positive whole number or 0.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-packet\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/build/documentation/man/man5/controller-exit.5 b/build/documentation/man/man5/controller-exit.5
new file mode 100644 (file)
index 0000000..a4969ea
--- /dev/null
@@ -0,0 +1,283 @@
+.TH controller-rule "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "rule" file.
+.SH SYNOPSIS
+.B rule
+.SH DESCRIPTION
+.PP
+This describes the intent and purpose of an Exit file.
+
+An Exit file, such as \fBdefault.exit\fR, is intended to store a set of rules in which the controller will process on execution.
+These are used to run some set of commands, such as shutting down a system.
+
+An Exit is a special variation or subset of an Entry.
+
+\- The \fBsettings\fR Item Object:
+  Represents Exit settings and is not an \fBitem\fR that can be executed.
+  A number of settings are supported, but if this Item Object is not specified, then defaults are used.
+  The following settings are available: \fBpid\fR and \fBshow\fR.
+
+  \- The \fBdefine\fR setting:
+    Use this to define an environment variable (this overwrites any existing environment variable with this name).
+    A define is both exported as an environment variable as well as exposed as an IKI variable.
+    Example IKI variable substitution: for \fBdefine PATH /bin:/sbin\fR, the associated IKI variable would look like: PATH.
+
+    All environment variables, including those defined using this, must be in the \fBenvironment\fR list in any given Rule to be exported to the executed process.
+    Environment variables added here that are not added to the environment are still exposed as an IKI variable.
+
+    This is only expanded within any Rule operated on by this Exit.
+
+  \- The \fBparameter\fR setting:
+    Use this to define an IKI variable name and value.
+    These do not conflict with environment variables and are not exposed as environment variables.
+    Example IKI variable substitution: for \fBparameter hello world\fR, the associated IKI variable would look like: hello.
+
+    This is only expanded within any Rule operated on by this Exit.
+
+  \- The \fBpid\fR setting:
+    Represents how the Exit PID file is generated or not.
+    The following modes are supported: \fBdisable\fR, \fBrequire\fR, and \fBready\fR.
+    For \fBdisable\fR, not PID file representing the Exit is created.
+    For \fBrequire\fR, check to see if the PID file exists for an Exit at startup and then when \fBready\fR create a PID file, display error on PID file already exists or on failure and then fail.
+    For \fBready\fR, when \fBready\fR create a PID file, display error on failure and then fail (does not check if PID file exists).
+
+  \- The \fBshow\fR setting:
+    Represents the way Exit processing presents information to the screen.
+    This applies only to the Exit and Rule processing itself and does not handle the output of programs and scripts being executed by some Exit or Rule.
+    The following show options are supported: \fBnormal\fR and \fBinit\fR.
+    For \fBnormal\fR, will not report the start or stop of some Exit or Rule execution but will report any errors or warnings as appropriate.
+    For \fBinit\fR, will report when starting programs and may include reporting success and failure status.
+
+  \- The \fBtimeout\fR setting:
+    Represents the default timeouts for the Exit.
+    See the \fBtimeout\fR Action below for details.
+
+\- The \fBmain\fR Item Object:
+  Is always executed first (Therefore \fBmain\fR is both reserved and required).
+  All other Basic List Objects are not executed unless either an \fBitem\fR or a \fBfailsafe\fR specifies a valid Item name.
+  Execution of all Items are top\-down.
+
+  Each \fBitem\fR supports the following Action Names: \fBconsider\fR, \fBexecute\fR, \fBfailsafe\fR, \fBfreeze\fR, \fBitem\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBready\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBtimeout\fR.
+  Of those types, the following are considered a \fBrule\fR Action: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBthaw\fR.
+
+  \- The \fBconsider\fR Item Action:
+    A special case of a \fBrule\fR Action.
+    All Action Parameters are the same as with the \fBrule\fR Action Parameters.
+    The difference is that \fBconsider\fR is only processed (instead of being processed and executed) and when some \fBrule\fR Action designates that this consideration is required (via \fBneed\fR), wanted (via \fBwant\fR), or wished for (via \fBwish\fR) from the within the Rule file.
+    If this is determined to be executed, then this is immediately executed when needed, wanted or wished for and applies all properties as appropriate (such as \fBasynchronous\fR, for example).
+    If this is determined not to be executed, then this \fBconsider\fR is ignored as if it was never there in the first place.
+
+  \- The \fBexecute\fR Item Action:
+    Execute into the specified program.
+    On successful execution, the controller program will no longer be running and will be replaced with the designated program.
+    This Item Action is only supported when operating in \fBprogram\fR mode.
+
+  \- The \fBfailsafe\fR Item Action:
+    Accepts only a valid Item Name in which will be executed when a failure is detected.
+    Only a single \fBfailsafe\fR Item Action may function at a time.
+    Each successive \fBfailsafe\fR Item Action specified replaces the previously defined \fBfailsafe\fR Item Action (in a top\-down manner).
+    When operating in \fBfailsafe\fR, the \fBrequire\fR Item Action is ignored (given that it is meaningless once operating in \fBfailsafe\fR mode).
+
+  \- The \fBfreeze\fR Item Action:
+    A \fBrule\fR Action for freezing some Control Group.
+    This Item Action will process the \fBfreeze\fR inner Content of the named Rule.
+    This is specific to Control Groups and is not yet fully implemented.
+    Once implemented this documentation will need to be updated and clarified.
+
+  \- The \fBitem\fR Item Action:
+    Accepts only a valid Item Name in which will be immediately executed.
+    Any valid Item Name, except for the reserved \fBmain\fR, may be used.
+
+  \- The \fBkill\fR Item Action:
+    A \fBrule\fR Action for forcibly terminating some process.
+    This Item Action will process the \fBkill\fR inner Content of the named Rule.
+
+  \- The \fBpause\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBpause\fR inner Content of the named Rule.
+
+  \- The \fBreload\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBreload\fR inner Content of the named Rule.
+
+  \- The \fBrestart\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBrestart\fR inner Content of the named Rule.
+
+  \- The \fBresume\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBresume\fR inner Content of the named Rule.
+
+  \- The \fBready\fR Action:
+    Instructs the controller program when it is safe to perform normal tasks, such as creating the PID file.
+    When not specified, the state is always assumed to be ready.
+    For example, the controller program may be used as a full blown \fBinit\fR replacement and therefore may need to mount the /var/run/ directory.
+    If the PID file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready.
+    This could be a problem, such as on a read\-only file system the PID creation fails and controller bails out on error.
+    Adding \fBready\fR essentially specifies a point in time in the Exit in which things are expected to be safe for such basic operations.
+    When the optional \fBwait\fR is provided, then \fBready\fR will wait for all currently started asynchronous processes to complete before operating.
+
+  \- The \fBstart\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBstart\fR inner Content of the named Rule.
+
+  \- The \fBstop\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBstop\fR inner Content of the named Rule.
+
+  \- The \fBthaw\fR Item Action:
+    A \fBrule\fR Action for unfreezing some Control Group.
+    This Item Action will process the \fBthaw\fR inner Content of the named Rule.
+    This is specific to Control Groups and is not yet fully implemented.
+    Once implemented this documentation will need to be updated and clarified.
+
+  \- The \fBtimeout\fR Item Action:
+    (This is not currently fully implemented, only \fBexit\fR is implemented.)
+    Provides default global settings for each of the four special situations: \fBexit\fR, \fBkill\fR, \fBstart\fR, and \fBstop\fR.
+    Each of these may only have a single one exist at a time (one \fBexit\fR, one \fBkill\fR, one \fBstart\fR, and one \fBstop\fR).
+    Each successive \fBtimeout\fR Item Action, specific to each Action Name (such as \fBstart\fR), specified replaces the previously defined \fBtimeout\fR Action (in a top\-down manner).
+    The second Content for each of these, when specified, may be a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+    For \fBkill\fR, this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule).
+    For \fBstart\fR, this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed.
+    For \fBstop\fR, this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed.
+    If the second Content is not specified, then this disables the type (prevents the specified timeout action).
+
+    For \fBexit\fR, this represents the number of MegaTime to wait when the Controller program is exiting (such as having received a terminate signal).
+    In this case, a terminate signal is sent to all child processes.
+    The \fBexit\fR timeout represents the amount of time to wait after sending the terminate signal before sending a kill signal to each child process still running.
+    When disabled, the program will not send a kill signal will continue running until all child processes to terminate.
+    The \fBexit\fR timeout does not get applied to any Rule.
+.SH SPECIFICATION
+.PP
+The Exit files follow the \fBFSS\-0005 (Somewhat Basic List)\fR format.
+
+An Exit file name is expected to have the file extension \fB.exit\fR.
+
+For each Exit file:
+  \- The outer most part is a \fBFSS\-0002 (Basic List)\fR.
+  \- The Basic List Object is considered the \fBItem\fR.
+  \- The Basic List Content are considered the \fBActions\fR.
+  \- The \fBActions\fR are \fBFSS\-0001 (Extended)\fR.
+  \- Each Action Object is the \fBAction Name\fR.
+  \- Each Action Content are the \fBAction Parameters\fR.
+
+The Items:
+  \- \fBmain\fR: required.
+
+  \- \fBsettings\fR: optional, Actions may be one of:
+    \- \fBpid\fR: Exactly one Content that is one of \fBdisable\fR, \fBrequire\fR, or \fBready\fR.
+    \- \fBsession\fR: Exactly one Content that is one of  \fBnew\fR or \fBsame\fR.
+    \- \fBshow\fR: Exactly one Content that is one of  \fBnormal\fR or \fBinit\fR.
+    \- \fBtimeout\fR: One or Two content with the first being one of \fBexit\fR, \fBstart\fR, \fBstop\fR, or \fBkill\fR and the (optional) second Content being a positive whole number or 0.
+
+  The Exit file may have any other valid Item Objects, but only the above are reserved.
+
+  The Actions:
+    \- \fBconsider\fR: One or more Content.
+      The first Content that is the relative file path (without any leading/trailing slashes and without file extension).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBfailsafe\fR: One Content that is a valid Object name, except for the reserved \fBmain\fR.
+
+    \- \fBfreeze\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBitem\fR: One Content that is a valid Object name, except for the reserved \fBmain\fR.
+
+    \- \fBkill\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBpause\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBready\fR: Zero or One Content.
+      The first may only be one of:
+      \- \fBwait\fR
+
+    \- \fBreload\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBrestart\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBresume\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBstart\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBstop\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBthaw\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBtimeout\fR: Two Content.
+      The first being one of:
+        \- \fBexit\fR
+        \- \fBstart\fR
+        \- \fBstop\fR
+        \- \fBkill\fR
+      The (optional) second Content being a positive whole number or 0.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-packet\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/build/documentation/man/man5/controller-packet.5 b/build/documentation/man/man5/controller-packet.5
new file mode 100644 (file)
index 0000000..c62cc93
--- /dev/null
@@ -0,0 +1,140 @@
+.TH controller-rule "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "rule" file.
+.SH SYNOPSIS
+.B rule
+.SH DESCRIPTION
+.PP
+Describes how a packet is designed and intended to be used.
+
+The \fBpacket\fR is the general category in which multiple types of packets belong.
+This describes the different packets based on their \fBtype\fR.
+
+Each packet begins with a control block and a size block followed by a payload block.
+
+  The control block:
+    The leading bit (starting from the left) designates the the format of the payload, which is 0 for string and 1 for binary.
+    The second bit (starting from the left) designates the the byte order for the rest of the packet, which 0 is for little endian and 1 is for big endian.
+    The remaining 6\-bits are reserved for future use.
+
+  The size block:
+    The size block represents the size of the entire packet (the control block, the size blocks, and the payload block).
+    This number is a single 32\-bit unsigned integer.
+
+    Example packet structure:
+
+      [ Control Block ] [ Size Block                                  ] [ Payload Block         ]
+      [ 0b10000000    ] [ 0b00000000 0b00000000 0b00000100 0b11010010 ] [ size: 1229 (1234 \- 5) ]
+
+
+  The payload block:
+    This block is represented by the \fBFSS\-000E (Payload)\fR specification and its structure ad use is described in the next sections.
+
+    The following types of payload are received or sent:
+    1) controller payload.
+    2) error payload.
+    3) init payload.
+
+The controller payload:
+  Commands being sent to the controller and their respective responses utilize a \fBcontroller\fR payload.
+  These are pre\-defined commands to rules or the controller program itself.
+  Commands such as starting or stopping some rule, for example.
+  A controller payload is also sent in response to a controller payload request to represent a success.
+
+    The \fBnow\fR condition designates that the kexec, reboot, or shutdown is to begin immediately.
+    The \fBat\fR condition designates that the kexec, reboot, or shutdown is to begin once a specific date and time is reached by the system clock.
+    The \fBin\fR condition designates that the kexec, reboot, or shutdown is to begin once a specific amount of time is passed by the system clock since the execution of this command started.
+
+  For these \fBtime\fR conditions, different units of time should be supported, such as \fBseconds\fR, \fBdays\fR, \fByears\fR as standard time, Time, or UNIX Time (Epoch Time).
+
+  The normal \fBcontroller\fR payload commands are any valid Rule Action that performs some action.
+  This does not include Actions that provide some setting or configuration (such as \fBwith_pid\fR).
+  Some of the supported commands are: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrerun\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, or \fBthaw\fR.
+  Multiple commands may be sent multiple \fBaction\fR headers.
+  The \fBaction\fR headers are order sensitive, executing from top to bottom, and one does not start until the previous successfully completes.
+
+  Multiple \fBstatus\fR headers may exist in the response so long as they each match an \fBaction\fR in the request.
+
+  The \fBpayload\fR is expected to be empty and have a length of 0 for a request.
+  The \fBpayload\fR may have an \fBFSS\-0000 (Basic)\fR format containing a single Object \fBmessage\fR to represent a message associated with an action.
+  Multiple \fBmessage\fR may exist in the response so long as they each match an \fBaction\fR in the request.
+
+The error payload:
+  The error payload is intended to communicate some sort of failure.
+  The error payload is only sent in response to some request (and not in response to another response).
+  The control (the client) is not expected to send error payloads and the controller (the service) should send an error in response to an error payload or ignore it entirely.
+  The \fBstatus\fR from the \fBheader\fR designates the status code as either a status code name string or a status code number (where a number may have error and warning bits).
+  The \fBpayload\fR will contain a NULL terminated string representing the message used to describe the error.
+
+The init payload:
+  The init payload is intended exclusively for the \fBinit\fR operation mode and is expected to only be available when running as \fBinit\fR.
+  This is used to provide special actions, namely \fBkexec\fR, \fBreboot\fR, and \fBshutdown\fR.
+
+  The \fBkexec\fR is for booting into another kernel, which may effectively be the same as a \fBreboot\fR ("kexec" is currently neither supported nor implemented).
+  The \fBreboot\fR is for rebooting the machine (currently not implemented).
+  The \fBshutdown\fR is for shutting down the machine (currently not implemented).
+  These three commands are configurable to fire off based on conditions.
+.SH SPECIFICATION
+.PP
+The controller program communicates use the \fBFSS\-000F (Packet)\fR.
+This specification declares how the Payload Block, which is in \fBFSS\-000E (Payload)\fR format, is required to be used.
+
+Only a single \fBheader\fR is allowed.
+Only a single \fBpayload\fR is allowed.
+
+Packet Structure:
+  Packet is grouped into the following blocks:
+    \- \fBcontrol\fR: A single 1\-byte block representing control codes.
+    \- \fBsize\fR: A single 4\-byte block representing the size of the entire packet, including the control block.
+
+The \fBheader\fR Object contains the following \fBFSS\-0001 (Extended)\fR Objects (depending on \fBtype\fR):
+  \- \fBaction\fR: A valid action type: \fBfreeze\fR, \fBkexec\fR, \fBkill\fR, \fBpause\fR, \fBreboot\fR, \fBreload\fR, \fBrerun\fR, \fBrestart\fR, \fBresume\fR, \fBshutdown\fR, \fBstart\fR, \fBstop\fR, or \fBthaw\fR.
+  \- \fBlength\fR: A positive whole number inclusively between 0 and 4294965248 representing the length of the \fBpayload\fR (may be in binary, octal, decimal, duodecimal, or hexidecimal).
+  \- \fBstatus\fR: The status code name or number representing an FSS status code, such as F_okay, F_failure, or 200 (where a number may have error and warning bits and may be in binary, octal, decimal, duodecimal, or hexidecimal).
+  \- \fBtype\fR: The packet type that is one of \fBcontroller\fR, \fBerror\fR, or \fBinit\fR.
+
+When there are multiple Objects of the same name inside the \fBheader\fR:
+  \- \fBaction\fR: The order represents the order in which the actions are performed.
+  \- \fBlength\fR: There may only be one length Object, all others after the first are ignored (may be in binary, octal, decimal, duodecimal, or hexidecimal).
+  \- \fBstatus\fR: A status for each action, in the same order as the order of the action, such as F_okay, F_failure, or 200 (where a number may have error and warning bits and may be in binary, octal, decimal, duodecimal, or hexidecimal).
+  \- \fBtype\fR: The first represent the type and all others represents a sub\-type.
+
+There are different headers and payload properties based on the \fBtype\fR.
+
+The \fBcontroller\fR type:
+  Supports the following headers: \fBaction\fR, \fBlength\fR, \fBstatus\fR, and \fBtype\fR.
+
+  Only a single \fBaction\fR may be provided and must exist for request and response packets.
+  Only a single \fBstatus\fR may be provided and must exist for response packets.
+
+  The \fBpayload\fR is dependent on the \fBaction\fR.
+
+The \fBerror\fR type:
+  Supports the following headers: \fBlength\fR, \fBstatus\fR, and \fBtype\fR.
+
+  Only a single \fBstatus\fR may be provided and must exist for request and response packets.
+
+  The \fBpayload\fR is a NULL terminated string whose length is defined by the \fBlength\fR \fBheader\fR Content.
+
+There are different headers and payload properties based on the \fBtype\fR.
+
+The \fBinit\fR type:
+  Supports the following headers: \fBaction\fR, \fBlength\fR, \fBstatus\fR, and \fBtype\fR.
+
+  Only a single \fBaction\fR may be provided and must exist for request and response packets.
+  Only a single \fBstatus\fR may be provided and must exist for response packets.
+
+  The \fBpayload\fR is dependent on the \fBaction\fR.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/build/documentation/man/man5/controller-rule.5 b/build/documentation/man/man5/controller-rule.5
new file mode 100644 (file)
index 0000000..47b81b5
--- /dev/null
@@ -0,0 +1,245 @@
+.TH controller-rule "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "rule" file.
+.SH SYNOPSIS
+.B rule
+.SH DESCRIPTION
+.PP
+This describes the intent and purpose of a Rule file.
+
+A Rule file, such as \fBssh.rule\fR, is intended to designate what to execute.
+
+The rule file is read top\-down, except for the outer most list \fBsettings\fR, which is intended to store setting data for this rule.
+Multiple outer most list Objects may be specified and they are executed as provided, in a top\-down manner.
+
+\- The \fBsettings\fR Rule Type has the following \fBFSS\-0001 (Extended)\fR Content:
+  \- \fBaffinity\fR: Define one or more processors to restrict this rule by with each number representing a specific processor by its id (starting at 0).
+  \- \fBcapability\fR: Define a set of capabilities in which to use, using the capability \fBtext\fR format (such as \fB= cap_chown+ep\fR).
+  \- \fBcgroup\fR: Define a cgroup (control group) in which everything within this rule executes under.
+  \- \fBdefine\fR: A single environment variable name and its associated value that is automatically exposed to processes executed within this rule.
+  \- \fBengine\fR: An executable name of a script, such as \fBbash\fR, to use for the \fBscript\fR Rule Type (which likely defaults to \fBbash\fR if not specified).
+  \- \fBenvironment\fR: A set of environment variables to expose to the processes executed within this rule (PATH is always exposed).
+  \- \fBgroup\fR: A set of group names or IDs to execute as with the first group being the primary group and all remaining being supplementary groups.
+  \- \fBlimit\fR: Define a resource limit to use (multiple limits may be specified, but only once for each type).
+  \- \fBname\fR: A name used to represent this rule, which is printed to the user, screen, logs, etc...
+  \- \fBnice\fR: A single niceness value to run all processes executed within this rule as (\-20 gets to be greediest in CPU usage and 19 being the nicest in CPU usage).
+  \- \fBon\fR: Define a Rule Action in which a specified dependency is needed, wanted, or wished for.
+  \- \fBparameter\fR: An IKI name and its associated value for use in this rule file.
+  \- \fBpath\fR: A single Content used to set a custom PATH environment variable value.
+  \- \fBscheduler\fR: A valid name of a scheduler to use followed by an optional priority number.
+  \- \fBtimeout\fR: A set of timeouts to wait for in which to perform a set action or to consider failure.
+  \- \fBuser\fR: A single user name or ID to execute as.
+
+\- The \fBcapability\fR setting:
+  If the user the controller program is run as does not have the desired capabilities already, they cannot be added.
+  This essentially maintains or reduces the capabilities already available.
+  Due to capabilities only being a draft in the POSIX standard, one may expect \fBcapabilities\fR support may not be available and in such a case this setting will do nothing.
+  If the dependent project (f_capability) does not have libcap support enabled, then capabilities will be unsupported by the compilation of this project.
+
+\- The \fBcontrol\fR setting:
+  The first argument is either \fBexisting\fR or \fBnew\fR, where for \fBexisting\fR the process is run inside the existing control used by the parent and when \fBnew\fR the process is executed within a new control group namespace entirely.
+
+\- The \fBdefine\fR setting:
+  Use this to define an environment variable (this overwrites any existing environment variable with this name).
+  A define is both exported as an environment variable as well as exposed as an IKI variable.
+  Example IKI variable substitution: for \fBdefine PATH /bin:/sbin\fR, the associated IKI variable would look like: PATH.
+
+  All environment variables, including those defined using this, must be in the \fBenvironment\fR list to be exported to the executed process.
+  Environment variables added here that are not added to the environment are still exposed as an IKI variable.
+
+\- The \fBengine\fR setting:
+  This engine is used for both \fBscript\fR and \fButility\fR Rule Types.
+  The program that engine refers to must accept a standard input pipe to be supported.
+  Additional parameters may be passed to the engine.
+
+\- The \fBgroup\fR and \fBuser\fR settings:
+  Only users and groups that the user the controller program is being run as is allowed to use may be used.
+
+\- The \fBlimit\fR setting:
+  The first parameter must be one of: \fBas\fR, \fBcore\fR, \fBcpu\fR, \fBdata\fR, \fBfsize\fR, \fBlocks\fR, \fBmemlock\fR, \fBmsgqueue\fR, \fBnice\fR, \fBnofile\fR, \fBnproc\fR, \fBrss\fR, \fBrtprio\fR, \fBrttime\fR, \fBsigpending\fR, or \fBstack\fR.
+  The second parameter represents the soft limit.
+  The third parameter represents the hard limit.
+  This may be specified multiply times, but only once for each type.
+
+\- The \fBon\fR setting:
+  The first parameter represents the Action the dependency exists under and must be one of: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, or \fBthaw\fR.
+  The second parameter represents how the dependency is required and must be one of: \fBneed\fR, \fBwant\fR, or \fBwish\fR.
+  The third parameter is a partial path to the rule file.
+  The fourth parameter represents the name of the rule file.
+
+  \- In the case of the second parameter:
+    \- A \fBneed\fR designates that the dependent rule is required to be executed (must exist and must succeed).
+    \- A \fBwant\fR designates that the dependent rule is to be executed (may exist and if it does, then it must succeed).
+    \- A \fBwish\fR designates that the dependent rule is to be executed (may exist and if it does, but it does not need to succeed).
+
+    In the case of \fBwant\fR and \fBwish\fR, if the desired rule is either not found or is otherwise disabled, then this will not fail or otherwise block the wanting or wishing rule.
+
+\- The \fBpath\fR setting:
+  When specified, the \fBPATH\fR environment variable is automatically added to the \fBenvironment\fR setting.
+
+\- The \fBparameter\fR setting:
+  Use this to define an IKI variable name and value.
+  These do not conflict with environment variables and are not exposed as environment variables.
+  Example IKI variable substitution: for \fBparameter hello world\fR, the associated IKI variable would look like: hello.
+
+\- The \fBscheduler\fR setting:
+  The valid range of the priority number is dependent on the scheduler.
+  For example, non\-real\-time schedulers (such as \fBidle\fR) only support a value of 0 whereas real\-time schedulers (such as \fBfifo\fR) only support an inclusive range of 1 to 99.
+  Supported non\-real\-time schedulers are: \fBbatch\fR, \fBidle\fR, and \fBother\fR (aka: normal/default).
+  Supported real\-time schedulers are: \fBdeadline\fR, \fBfifo\fR, \fBround_robin\fR.
+
+\- The \fBtimeout\fR setting:
+  (This is not currently implemented.)
+  Provides settings for each of the three special situations: \fBkill\fR, \fBstart\fR, and \fBstop\fR.
+  Each of these may only have a single one exist at a time (one \fBkill\fR, one \fBstart\fR, and one \fBstop\fR).
+  Each successive \fBtimeout\fR Item Action, specific to each Action Name (such as \fBstart\fR), specified replaces the previously defined \fBtimeout\fR Action (in a top\-down manner).
+  The second Content for each of these, when specified, may be a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+  For \fBkill\fR, this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule).
+  For \fBstart\fR, this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed.
+  For \fBstop\fR, this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed.
+  If the second Content is not specified, then this disables the type (prevents the specified timeout action).
+
+There are four available Rule Types to choose from: \fBcommand\fR, \fBservice\fR, \fBscript\fR, and \fButility\fR.
+
+The \fBcommand\fR Rule Type provides a simple command to run under the different circumstances: \fBstart\fR, \fBstop\fR, \fBrestart\fR, and \fBreload\fR.
+A \fBcommand\fR always operates in the foreground.
+
+The \fBservice\fR Rule Type provides a \fBcommand\fR accompanied with a PID file (Process Identifier file).
+
+The \fBscript\fR Rule Type provides a series of lines to be executed by some engine, such as GNU Bash.
+This \fBscript\fR operates in the foreground, but individual things done within the script may operate in foreground or background.
+The last return state is treated as an error, so be sure to finish the script with a return code of 0 to designate no error and any other whole number, such a 1, to designate an error.
+Therefore passing \fBexit 1\fR would return as an error and passing \fBexit 0\fR would return as a success.
+A \fBscript\fR is assumed to be in GNU Bash, which is the default expected behavior, but the specification does not explicitly require this.
+Another scripting language can be used but changing this incurs the responsibility to ensure all rules are updated to the appropriate scripting language.
+
+The \fButility\fR Rule Type provides a \fBscript\fR accompanied with a PID file (Process Identifier file).
+
+There are nine Rule Actions used to execute ("freeze", \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBthaw\fR):
+  When \fBrestart\fR Object's Content is not provided, then \fBstart\fR and \fBstop\fR is called when the rule is executed using the restart Action, if both \fBstart\fR and \fBstop\fR are provided.
+  When \fBreload\fR, \fBstart\fR, or \fBstop\fR Object's Content are not provided, then no respective Action is performed.
+
+  Commands are conditionally available depending on the presence of these, such as if \fBstop\fR is not provided then \fBstop\fR (and \fBrestart\fR) will not be available for the \fBcontrol\fR program(s) to use.
+
+Thee are additional Rule Actions not used to execute ("pid_file", \fBrerun\fR, and \fBwith\fR):
+  \- The \fBpid_file\fR Object's Content designates the path to the PID file created by the called program.
+
+  \- The \fBrerun\fR Object's Content designates how to re\-run a given execution Rule type.
+    \- The first Content represents the execution type, which may be one of: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBthaw\fR.
+
+    \- The second Content represents when to run this re\-run is triggered, which is either \fBsuccess\fR (return code of 0) or \fBfailure\fR (return code is not 0).
+
+    \- The third Content and more represent additional options for fine tuning how the re\-run is Performed:
+      When \fBdelay\fR, followed by a number of MegaTime (MT) (equivalent to milliseconds) in which to wait before attempting the re\-run.
+      When \fBmax\fR, followed by a positive number or the number 0 designating the maximum number of re\-runs to perform.
+      When \fBreset\fR, the \fBmax\fR re\-run counter is reset for the opposite re\-run when this re\-run is triggered, such as:
+        A \fBrerun start success reset\fR and a \fBrerun failure max 10\fR, the failure counter would reset to 0 when the \fBsuccess\fR re\-run is performed and not when the \fBfailure\fR re\-run is performed.
+
+      A \fBmax\fR of 0 designates that the re\-run will happen infinitely.
+
+  \- The \fBwith\fR Object's Content designates special flags designating very specific behavior to be applied to any single Rule Type.
+.SH SPECIFICATION
+.PP
+The Rule files follow the \fBFSS\-000D (Basic Rule)\fR format with IKI\-0000 (Unrestricted).
+
+A Rule file name is expected to have the file extension \fB.rule\fR.
+
+For each Rule file:
+  \- The outer most part is a \fBFSS\-0002 (Basic List)\fR.
+  \- The Basic List Object is considered the \fBRule Type\fR.
+  \- The Basic List Content is determined by the specific \fBRule Type\fR.
+  \- The Content for each \fBRule Type\fR is called the \fBItem\fR.
+  \- Each Item Object is the \fBItem Name\fR.
+  \- Each Item Content is either the \fBAction\fR or the \fBSetting\fR.
+  \- Each Action Object is the \fBAction Name\fR.
+  \- Each Action Content are the \fBAction Parameters\fR.
+  \- Each Setting Object is the \fBSetting Name\fR.
+  \- Each Setting Content are the \fBSetting Values\fR.
+
+The Rule Types:
+  \- \fBcommand\fR: Follows either \fBFSS\-0003 (Extended List)\fR or \fBFSS\-0001 (Extended)\fR.
+  \- \fBscript\fR: Follows either \fBFSS\-0003 (Extended List)\fR or \fBFSS\-0001 (Extended)\fR.
+  \- \fBservice\fR: Follows either \fBFSS\-0003 (Extended List)\fR or \fBFSS\-0001 (Extended)\fR.
+  \- \fBsettings\fR: Is required and follows either  \fBFSS\-0001 (Extended)\fR.
+  \- \fButility\fR: Follows either \fBFSS\-0003 (Extended List)\fR or \fBFSS\-0001 (Extended)\fR.
+
+For the above Rule Types, \fBsettings\fR may be specified only once whereas the others may be specifed multiple times.
+The \fBsettings\fR Rule Type is always processed first, regardless of position.
+The other Rule Types are processed top\-down.
+
+The \fBsettings\fR Rule Type has the following \fBFSS\-0001 (Extended)\fR:
+  \- \fBaffinity\fR: One or more Content, each must be a 0 or greater whole number.
+  \- \fBcapability\fR: One Content representing capabilities.
+  \- \fBcgroup\fR: Two or more Content, the first Content being either \fBexisting\fR or \fBnew\fR and the remaining representing a valid cgroup (control group) name, must have at least 1 graph character (non white space printing character) (leading and trailing white space are trimmed off).
+  \- \fBdefine\fR: Two Content, the first Content must be a case\-sensitive valid environment variable name (alpha\-numeric or underscore, but no leading digits).
+  \- \fBengine\fR: One or more Content representing a valid program name or path (such as \fBbash\fR or \fB/bin/bash\fR) and any optional arguments.
+  \- \fBenvironment\fR: Zero or more Content, each must be a case\-sensitive valid environment variable name (alpha\-numeric or underscore, but no leading digits).
+  \- \fBgroup\fR: One or more Content representing group names or group ids.
+  \- \fBlimit\fR: Three Content, with the first representing a valid resource type and the second and third being a valid resource limit number (positive whole number or 0).
+  \- \fBname\fR: One Content, must have at least 1 graph character (non white space printing character) (leading and trailing white space are trimmed off).
+  \- \fBnice\fR: One Content, must be a valid number for process \fBniceness\fR (Any whole number inclusively between \-20 to 19).
+  \- \fBon\fR: Four Content, the first being a Rule Action, the second being \fBneed\fR, \fBwant\fR, or \fBwish\fR, the third being a partial path, and the fourth being a Rule file name without \fB.rule\fR extension.
+  \- \fBparameter\fR: Two Content, the first Content must be a case\-sensitive valid IKI name and the second being an IKI value.
+  \- \fBpath\fR: One Content representing a valid \fBPATH\fR environment string (such as \fB/bin:/sbin:/usr/bin\fR).
+  \- \fBscheduler\fR: One or two Content representing a scheduler name and the optional numeric priority (Any whole number inclusively between 0 and 99).
+  \- \fBtimeout\fR: One or two content with the first being one of \fBexit\fR, \fBstart\fR, \fBstop\fR, or \fBkill\fR and the (optional) second Content being a positive whole number or 0.
+  \- \fBuser\fR: One Content representing a user name or user id.
+
+The \fBcommand\fR and \fBscript\fR Rule Types allow the following the \fBFSS\-0001 (Extended)\fR:
+  \- \fBfreeze\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBkill\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBpause\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBreload\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBrerun\fR: Two or more Content representing a Rule type that executes and its properties.
+  \- \fBrestart\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBresume\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBstart\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBstop\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBthaw\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBwith\fR: One or more Content representing special options for the Rule Type.
+
+The \fBservice\fR and \fButility\fR Rule Types allow the following the \fBFSS\-0001 (Extended)\fR:
+  \- \fBpid_file\fR: One Content representing the path to a PID file.
+  \- \fBrerun\fR: Two or more Content representing a Rule type that executes and its properties.
+  \- \fBwith\fR: One or more Content being one of \fBfull_path\fR, \fBsession_new\fR, or \fBsession_same\fR.
+
+The \fBcommand\fR and \fBservice\fR Rule Types allow the following the \fBFSS\-0003 (Extended List)\fR:
+  \- \fBfreeze\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBkill\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBpause\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBreload\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBrestart\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBresume\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBstart\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBstop\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBthaw\fR: A list repesenting multiple programs and their respective arguments to execute.
+
+The \fBscript\fR and \fButility\fR Rule Types allow the following the \fBFSS\-0003 (Extended List)\fR:
+  \- \fBfreeze\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBkill\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBpause\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBreload\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBrestart\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBresume\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBstart\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBstop\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBthaw\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+
+The \fBrerun\fR Rule Type Content has the following structure:
+  The first Content represents one of: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, or \fBthaw\fR.
+  The second Content represents one of: \fBsuccess\fR or \fBfailure\fR.
+  The third and more Content represents one of: \fBdelay\fR, \fBmax\fR, or \fBreset\fR.
+  Where \fBdelay\fR and \fBmax\fR must be followed by a positive number or the number 0.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-packet\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/build/includes/program/controller/main/common.h b/build/includes/program/controller/main/common.h
new file mode 100644 (file)
index 0000000..9d1a594
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_h
+#define _controller_main_common_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Perform the standard program setting load process.
+ *
+ * This prints error messages as appropriate.
+ *
+ * If either main or setting is NULL, then this immediately returns without doing anything.
+ *
+ * @param arguments
+ *   The parameters passed to the process (often referred to as command line arguments).
+ * @param main
+ *   The program and settings data.
+ *
+ *   This alters setting.state.status:
+ *     F_okay on success.
+ *
+ *     Errors (with error bit) from: f_console_parameter_process().
+ *     Errors (with error bit) from: fll_program_parameter_process_context().
+ *
+ * @see f_console_parameter_process()
+ * @see fll_program_parameter_process_context()
+ */
+#ifndef _di_controller_main_setting_load_
+  extern void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main);
+#endif // _di_controller_main_setting_load_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_h
diff --git a/build/includes/program/controller/main/common/define.h b/build/includes/program/controller/main/common/define.h
new file mode 100644 (file)
index 0000000..8bf7926
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common define types.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_define_h
+#define _controller_main_common_define_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The program allocation defines.
+ *
+ * controller_allocation_*_d:
+ *   - console: An allocation step used for small buffers specifically for console parameter.
+ *   - large:   An allocation step used for buffers that are anticipated to have large buffers.
+ *   - pipe:    A buffer size used for processing piped data.
+ *   - small:   An allocation step used for buffers that are anticipated to have small buffers.
+ */
+#ifndef _di_controller_allocation_d_
+  #define controller_allocation_console_d 4
+  #define controller_allocation_large_d   256
+  #define controller_allocation_pipe_d    16384
+  #define controller_allocation_small_d   16
+#endif // _di_controller_allocation_d_
+
+/**
+ * The program signal defines.
+ *
+ * controller_signal_*_d:
+ *   - check:          Number of iterations before performing signal check in non-threaded signal handling.
+ *   - check_failsafe: When using threads, how many consecutive failures to check signal before aborting (as a recursion failsafe).
+ *   - check_tiny:     The tiny check.
+ *   - check_short:    The short signal check.
+ */
+#ifndef _di_controller_signal_d_
+  #define controller_signal_check_d          500000
+  #define controller_signal_check_failsafe_d 20000
+  #define controller_signal_check_tiny_d     4
+  #define controller_signal_check_short_d    16
+#endif // _di_controller_signal_d_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_define_h
diff --git a/build/includes/program/controller/main/common/enumeration.h b/build/includes/program/controller/main/common/enumeration.h
new file mode 100644 (file)
index 0000000..19b272b
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common enumeration types.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_enumeration_h
+#define _controller_main_common_enumeration_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Flags passed to the main function or program.
+ *
+ * When number mode is not specified, then mode is "string" mode (there is no flag for "string" mode).
+ *
+ * controller_main_flag_*_e:
+ *   - none:                   No flags set.
+ *   - copyright:              Print copyright.
+ *   - error:                  Check if status is "error".
+ *   - fine:                   Check if status is "fine".
+ *   - help:                   Print help.
+ *   - pipe:                   Use the input pipe.
+ *   - print_first:            When set, print new line to message output on program begin after loading settings.
+ *   - print_last:             When set, print new line to message output on program end.
+ *   - version:                Print version.
+ *   - version_copyright_help: A helper flag representing version, copyright, and help flag bits being set.
+ *   - warning:                Check if status is "warning".
+ */
+#ifndef _di_controller_main_flag_e_
+  enum {
+    controller_main_flag_none_e                   = 0x0,
+    controller_main_flag_copyright_e              = 0x1,
+    controller_main_flag_error_e                  = 0x2,
+    controller_main_flag_fine_e                   = 0x4,
+    controller_main_flag_help_e                   = 0x8,
+    controller_main_flag_pipe_e                   = 0x10,
+    controller_main_flag_print_first_e            = 0x20,
+    controller_main_flag_print_last_e             = 0x40,
+    controller_main_flag_version_e                = 0x80,
+    controller_main_flag_version_copyright_help_e = 0x89,
+    controller_main_flag_warning_e                = 0x100,
+  }; // enum
+#endif // _di_controller_main_flag_e_
+
+/**
+ * The main program parameters.
+ */
+#ifndef _di_controller_parameter_e_
+  enum {
+    controller_parameter_controller_e = f_console_standard_parameter_last_e,
+  }; // enum
+
+  #define controller_console_parameter_t_initialize \
+    { \
+      macro_fll_program_console_parameter_standard_initialize, \
+      \
+      macro_f_console_parameter_t_initialize_3(controller_short_controller_s, controller_long_controller_s, 0, f_console_flag_normal_e), \
+    }
+
+  #define controller_parameter_total_d (f_console_parameter_state_type_total_d + 1)
+#endif // _di_controller_parameter_e_
+
+/**
+ * Flags for fine-tuned print control.
+ *
+ * controller_print_flag_*_e:
+ *   - none:    No flags set.
+ *   - debug:   Stream is for debug printing.
+ *   - error:   Stream is for error printing.
+ *   - in:      Stream is a source file.
+ *   - message: Stream is for message printing.
+ *   - out:     Stream is a destination file.
+ *   - warning: Stream is for warning printing.
+ */
+#ifndef _di_controller_print_flag_e_
+  enum {
+    controller_print_flag_none_e    = 0x0,
+    controller_print_flag_debug_e   = 0x1,
+    controller_print_flag_error_e   = 0x2,
+    controller_print_flag_file_e    = 0x4,
+    controller_print_flag_in_e      = 0x8,
+    controller_print_flag_out_e     = 0x10,
+    controller_print_flag_message_e = 0x20,
+    controller_print_flag_warning_e = 0x40,
+  }; // enum
+#endif // _di_controller_print_flag_e_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_enumeration_h
diff --git a/build/includes/program/controller/main/common/print.h b/build/includes/program/controller/main/common/print.h
new file mode 100644 (file)
index 0000000..3d48967
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common print functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_print_h
+#define _controller_main_common_print_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A special array of strings intended for representing funciton names.
+ *
+ * These are primarily used for printing errors with the function names.
+ *
+ * The macro macro_controller_f() is used to reference the array index by the enum name.
+ *
+ * macro_controller_f():
+ *   - name: The name of the function.
+ */
+#ifndef _di_controller_f_a_
+  extern const f_string_t controller_f_a[];
+
+  #define macro_controller_f(name) controller_f_a[controller_f_##name##_e]
+#endif // _di_controller_f_a_
+
+/**
+ * An enum representing specific indexes within the above array.
+ *
+ * This is a convenience enum used to make code slightly more readable.
+ */
+#ifndef _di_controller_f_e_
+  enum {
+    controller_f_f_console_parameter_process_e,
+    controller_f_f_thread_create_e,
+    controller_f_fll_program_parameter_process_context_standard_e,
+    controller_f_fll_program_parameter_process_verbosity_standard_e,
+  }; // enum
+#endif // _di_controller_f_e_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_print_h
diff --git a/build/includes/program/controller/main/common/string.h b/build/includes/program/controller/main/common/string.h
new file mode 100644 (file)
index 0000000..fff2a1e
--- /dev/null
@@ -0,0 +1,83 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common string structures.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_string_h
+#define _controller_main_common_string_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The program version.
+ */
+#ifndef _di_controller_program_version_s_
+  #define CONTROLLER_program_version_major_s F_string_ascii_0_s
+  #define CONTROLLER_program_version_minor_s F_string_ascii_7_s
+  #define CONTROLLER_program_version_micro_s F_string_ascii_0_s
+
+  #define CONTROLLER_program_version_major_s_length F_string_ascii_0_s_length
+  #define CONTROLLER_program_version_minor_s_length F_string_ascii_7_s_length
+  #define CONTROLLER_program_version_micro_s_length F_string_ascii_0_s_length
+
+  #if !(defined(CONTROLLER_program_version_nano_prefix_s) && defined(CONTROLLER_program_version_nano_prefix_s_length))
+    #define CONTROLLER_program_version_nano_prefix_s
+    #define CONTROLLER_program_version_nano_prefix_s_length 0
+  #endif // !(defined(CONTROLLER_program_version_nano_prefix_s) && defined(CONTROLLER_program_version_nano_prefix_s_length))
+
+  #if !(defined(CONTROLLER_program_version_nano_s) && defined(CONTROLLER_program_version_nano_s_length))
+    #define CONTROLLER_program_version_nano_s
+    #define CONTROLLER_program_version_nano_s_length 0
+  #endif // !(defined(CONTROLLER_program_version_nano_s) && defined(CONTROLLER_program_version_nano_s_length))
+
+  #define CONTROLLER_program_version_s CONTROLLER_program_version_major_s F_string_ascii_period_s CONTROLLER_program_version_minor_s F_string_ascii_period_s CONTROLLER_program_version_micro_s CONTROLLER_program_version_nano_prefix_s CONTROLLER_program_version_nano_s
+
+  #define CONTROLLER_program_version_s_length CONTROLLER_program_version_major_s_length + F_string_ascii_period_s_length + CONTROLLER_program_version_minor_s_length + F_string_ascii_period_s_length + CONTROLLER_program_version_micro_s_length + CONTROLLER_program_version_nano_prefix_s_length + CONTROLLER_program_version_nano_s_length
+
+  extern const f_string_static_t controller_program_version_s;
+#endif // _di_controller_program_version_s_
+
+/**
+ * The program name.
+ */
+#ifndef _di_controller_program_name_s_
+  #define CONTROLLER_program_name_s      "controller"
+  #define CONTROLLER_program_name_long_s "Controller"
+
+  #define CONTROLLER_program_name_s_length      10
+  #define CONTROLLER_program_name_long_s_length 10
+
+  extern const f_string_static_t controller_program_name_s;
+  extern const f_string_static_t controller_program_name_long_s;
+#endif // _di_controller_program_name_s_
+
+/**
+ * The main program parameters.
+ */
+#ifndef _di_controller_parameter_s_
+  #define CONTROLLER_short_controller_s "e"
+
+  #define CONTROLLER_long_controller_s "controller"
+
+  #define CONTROLLER_short_controller_s_length 1
+
+  #define CONTROLLER_long_controller_s_length 7
+
+  extern const f_string_static_t controller_short_controller_s;
+
+  extern const f_string_static_t controller_long_controller_s;
+#endif // _di_controller_parameter_s_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_string_h
diff --git a/build/includes/program/controller/main/common/type.h b/build/includes/program/controller/main/common/type.h
new file mode 100644 (file)
index 0000000..4a9bd23
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common type structures.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_type_h
+#define _controller_main_common_type_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The controller main program cache.
+ *
+ * buffer: A generic buffer.
+ */
+#ifndef _di_controller_cache_t_
+  typedef struct {
+    f_string_dynamic_t buffer;
+  } controller_cache_t;
+
+  #define controller_cache_t_initialize \
+    { \
+      f_string_dynamic_t_initialize, \
+    }
+#endif // _di_controller_cache_t_
+
+/**
+ * The controller main program settings.
+ *
+ * This is passed to the program-specific main entry point to designate program settings.
+ * These program settings are often processed from the program arguments (often called the command line arguments).
+ *
+ * flag: Flags passed to the main function.
+ *
+ * status_signal: A status used eclusively by the threaded signal handler.
+ * state:         The state data used when processing the FSS data.
+ */
+#ifndef _di_controller_setting_t_
+  typedef struct {
+    uint16_t flag;
+
+    f_status_t status_signal;
+    f_state_t state;
+
+    const f_string_static_t *program_name;
+    const f_string_static_t *program_name_long;
+  } controller_setting_t;
+
+  #define controller_setting_t_initialize \
+    { \
+      controller_main_flag_none_e, \
+      F_okay, \
+      f_state_t_initialize, \
+      0, \
+      0, \
+    }
+#endif // _di_controller_setting_t_
+
+/**
+ * The main program data as a single structure.
+ *
+ * program: The main program data.
+ * setting: The settings data.
+ */
+#ifndef _di_controller_main_t_
+  typedef struct {
+    fll_program_data_t program;
+    controller_setting_t setting;
+    controller_cache_t cache;
+  } controller_main_t;
+
+  #define controller_main_t_initialize \
+    { \
+      fll_program_data_t_initialize, \
+      controller_setting_t_initialize, \
+      controller_cache_t_initialize, \
+    }
+#endif // _di_controller_main_t_
+
+/**
+ * Deallocate main program data.
+ *
+ * @param cache
+ *   The program cache.
+ *
+ *   Must not be NULL.
+ *
+ * @see f_memory_array_resize()
+ */
+#ifndef _di_controller_cache_delete_
+  extern void controller_cache_delete(controller_cache_t * const cache);
+#endif // _di_controller_cache_delete_
+
+/**
+ * Deallocate main program data.
+ *
+ * @param main
+ *   The main program data.
+ *
+ *   Must not be NULL.
+ *
+ *   This does not alter main.setting.state.status.
+ *
+ * @see controller_cache_delete()
+ * @see controller_setting_delete()
+ * @see fll_program_data_delete()
+ */
+#ifndef _di_controller_main_delete_
+  extern void controller_main_delete(controller_main_t * const main);
+#endif // _di_controller_main_delete_
+
+/**
+ * Delete the program main setting data.
+ *
+ * @param setting
+ *   The program main setting data.
+ *
+ *   Must not be NULL.
+ *
+ *   This does not alter setting.state.status.
+ */
+#ifndef _di_controller_setting_delete_
+  extern void controller_setting_delete(controller_setting_t * const setting);
+#endif // _di_controller_setting_delete_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_type_h
diff --git a/build/includes/program/controller/main/controller.h b/build/includes/program/controller/main/controller.h
new file mode 100644 (file)
index 0000000..16e3257
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * This program provides an controller base project.
+ *
+ * This program does nothing but can be used as a starting point for new program projects.
+ */
+#ifndef _controller_h
+#define _controller_h
+
+// Libc includes.
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// FLL-0 includes.
+#include <fll/level_0/type.h>
+#include <fll/level_0/status.h>
+#include <fll/level_0/memory.h>
+#include <fll/level_0/string.h>
+#include <fll/level_0/utf.h>
+#include <fll/level_0/color.h>
+#include <fll/level_0/compare.h>
+#include <fll/level_0/console.h>
+#include <fll/level_0/conversion.h>
+#include <fll/level_0/pipe.h>
+#include <fll/level_0/print.h>
+#include <fll/level_0/rip.h>
+#include <fll/level_0/signal.h>
+
+#ifndef _di_thread_support_
+  #include <fll/level_0/thread.h>
+#endif // _di_thread_support_
+
+// FLL-1 includes.
+#include <fll/level_1/conversion.h>
+#include <fll/level_1/print.h>
+
+// FLL-2 includes.
+#include <fll/level_2/error.h>
+#include <fll/level_2/print.h>
+#include <fll/level_2/program.h>
+
+// Controller includes.
+#include <program/controller/main/common/define.h>
+#include <program/controller/main/common/enumeration.h>
+#include <program/controller/main/common/print.h>
+#include <program/controller/main/common/string.h>
+#include <program/controller/main/common/type.h>
+#include <program/controller/main/common.h>
+#include <program/controller/main/print/data.h>
+#include <program/controller/main/print/debug.h>
+#include <program/controller/main/print/error.h>
+#include <program/controller/main/print/message.h>
+#include <program/controller/main/print/verbose.h>
+#include <program/controller/main/print/warning.h>
+#include <program/controller/main/signal.h>
+#include <program/controller/main/thread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_h
diff --git a/build/includes/program/controller/main/print/data.h b/build/includes/program/controller/main/print/data.h
new file mode 100644 (file)
index 0000000..17ef811
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print data functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_data_h
+#define _controller_main_print_data_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_data_h
diff --git a/build/includes/program/controller/main/print/debug.h b/build/includes/program/controller/main/print/debug.h
new file mode 100644 (file)
index 0000000..1eb6491
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print debug functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_debug_h
+#define _controller_main_print_debug_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_debug_h
diff --git a/build/includes/program/controller/main/print/error.h b/build/includes/program/controller/main/print/error.h
new file mode 100644 (file)
index 0000000..3f67c87
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print error functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_error_h
+#define _controller_main_print_error_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Print generic error message regarding a function failing in some way.
+ *
+ * @param print
+ *   The output structure to print to.
+ *
+ *   This does not alter print.custom.setting.state.status.
+ * @param function
+ *   The name of the function associated with the error.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_print()
+ */
+#ifndef _di_controller_main_print_error_
+  extern f_status_t controller_main_print_error(fl_print_t * const print, const f_string_t function);
+#endif // _di_controller_main_print_error_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_error_h
diff --git a/build/includes/program/controller/main/print/message.h b/build/includes/program/controller/main/print/message.h
new file mode 100644 (file)
index 0000000..3be5523
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print message functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_message_h
+#define _controller_main_print_message_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Print help.
+ *
+ * @param print
+ *   The output structure to print to.
+ *
+ *   This requires print.custom to be controller_main_t.
+ *
+ *   This does not alter print.custom.setting.state.status.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see f_file_stream_flush()
+ * @see f_file_stream_lock()
+ * @see f_file_stream_unlock()
+ * @see f_print_dynamic_raw()
+ * @see fll_program_print_help_header()
+ * @see fll_program_print_help_option()
+ * @see fll_program_print_help_usage()
+ */
+#ifndef _di_controller_main_print_message_help_
+  extern f_status_t controller_main_print_message_help(fl_print_t * const print);
+#endif // _di_controller_main_print_message_help_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_message_h
diff --git a/build/includes/program/controller/main/print/verbose.h b/build/includes/program/controller/main/print/verbose.h
new file mode 100644 (file)
index 0000000..0cab65e
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print verbose functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_verbose_h
+#define _controller_main_print_verbose_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_verbose_h
diff --git a/build/includes/program/controller/main/print/warning.h b/build/includes/program/controller/main/print/warning.h
new file mode 100644 (file)
index 0000000..654e77f
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print warning functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_warning_h
+#define _controller_main_print_warning_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_warning_h
diff --git a/build/includes/program/controller/main/signal.h b/build/includes/program/controller/main/signal.h
new file mode 100644 (file)
index 0000000..404caca
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides signal functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_signal_h
+#define _controller_main_signal_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Check to see if a signal is received.
+ *
+ * If main.signal is non-zero, then this handles the following signals:
+ *   - F_signal_abort
+ *   - F_signal_broken_pipe
+ *   - F_signal_hangup
+ *   - F_signal_interrupt
+ *   - F_signal_quit
+ *   - F_signal_termination
+ *
+ * There is a threaded and a non-threaded version of this.
+ * The non-threaded version checks periodically using controller_main_signal_check_d and updates main->signal_check as needed.
+ * The threaded version checks the flag state which is set by a separate thread that is blocking until signal is received.
+ *
+ * @param main
+ *   The main program and settings data.
+ *
+ *   This does not alter main.setting.state.status.
+ *
+ * @return
+ *   F_true on signal received.
+ *   F_false otherwise.
+ *
+ * @see controller_main_signal_handler()
+ *
+ * @see fll_program_standard_signal_received()
+ */
+#ifndef _di_controller_main_signal_check_
+  extern f_status_t controller_main_signal_check(controller_main_t * const main);
+#endif // _di_controller_main_signal_check_
+
+/**
+ * Signal handler for signals/interrupts.
+ *
+ * This blocks until an expected signal is recieved.
+ * When an expected signal is received it then sets the
+ *
+ * If main.signal is non-zero, then this handles the following signals:
+ *   - F_signal_abort
+ *   - F_signal_broken_pipe
+ *   - F_signal_hangup
+ *   - F_signal_interrupt
+ *   - F_signal_quit
+ *   - F_signal_termination
+ *
+ * @param main
+ *   The main program and settings data.
+ *
+ *   This alters main.program.signal_received, setting it to a received signal.
+ *
+ *   This alters main.setting.state.status:
+ *     Errors (with error bit) from: f_signal_open()
+ *     Errors (with error bit) from: f_signal_wait()
+ *
+ * @see f_signal_close()
+ * @see f_signal_open()
+ * @see f_signal_wait()
+ */
+#if !defined(_di_controller_main_signal_handler_) && !defined(_di_thread_support_)
+  extern void controller_main_signal_handler(controller_main_t * const main);
+#endif // !defined(_di_controller_main_signal_handler_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_signal_h
diff --git a/build/includes/program/controller/main/thread.h b/build/includes/program/controller/main/thread.h
new file mode 100644 (file)
index 0000000..df7fe9e
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides thread functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_thread_h
+#define _controller_main_thread_h
+
+/**
+ * Thread handler for signals/interrupts.
+ *
+ * If main.signal is non-zero, then this handles the following signals:
+ *   - F_signal_abort
+ *   - F_signal_broken_pipe
+ *   - F_signal_hangup
+ *   - F_signal_interrupt
+ *   - F_signal_quit
+ *   - F_signal_termination
+ *
+ * @param main
+ *   The program and settings data.
+ *
+ *   Must be of type controller_main_t.
+ *
+ * @return
+ *   0, always.
+ *
+ * @see f_thread_cancel_state_set()
+ *
+ * @see controller_signal_handler()
+ */
+#if !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
+  extern void * controller_main_thread_signal(void * const main);
+#endif // !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_thread_h
diff --git a/build/stage/skeleton-settings.built b/build/stage/skeleton-settings.built
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build/stage/sources_documentation-settings.built b/build/stage/sources_documentation-settings.built
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build/stage/sources_headers-settings.built b/build/stage/sources_headers-settings.built
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build/stage/sources_settings-settings.built b/build/stage/sources_settings-settings.built
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/data/build/defines b/data/build/defines
new file mode 100644 (file)
index 0000000..a5c6973
--- /dev/null
@@ -0,0 +1,30 @@
+# fss-0000
+
+_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
+_di_thread_support_ Disables thread support.
+
+_libcap_legacy_only_ Disable functionality provided by later versions of libcap (2.43 and later).
+_controller_as_init_ Build the program to run as if it were "init" by default, including displaying the program name as "Init Program" or "Init". This changes the main.c file only, leaving the library shareable between both "controller" and "init".
+_override_controller_default_engine_ Provide a custom scripting engine name string to execute (such as php).
+_override_controller_default_engine_length_ The number of bytes representing the string in _override_controller_default_engine_ (not including the terminating NULL).
+_override_controller_path_pid_ Use this as the default custom directory path representing the location of the controller program pid.
+_override_controller_path_pid_init_ Provide a custom init path for the pid file rather than the default.
+_override_controller_path_pid_init_length_ The number of bytes representing the string in _override_controller_path_pid_init_ (not including the terminating NULL).
+_override_controller_path_pid_length_ The number of bytes representing the string in _override_controller_path_pid_ (not including the terminating NULL).
+_override_controller_path_pid_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
+_override_controller_path_pid_prefix_length_ The number of bytes representing the string in _override_controller_path_pid_prefix_ (not including the terminating NULL).
+_override_controller_path_pid_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
+_override_controller_path_pid_suffix_length_ The number of bytes representing the string in _override_controller_path_pid_suffix_ (not including the terminating NULL).
+_override_controller_path_settings_init_ Provide a custom init path for the settings file rather than the default.
+_override_controller_path_settings_init_length_ The number of bytes representing the string in _override_controller_path_settings_init_ (not including the terminating NULL).
+_override_controller_path_socket_ Use this as the default custom directory path representing the location of the controller program socket.
+_override_controller_path_socket_init_ Provide a custom init path for the socket file rather than the default.
+_override_controller_path_socket_init_length_ The number of bytes representing the string in _override_controller_path_socket_init_ (not including the terminating NULL).
+_override_controller_path_socket_length_ The number of bytes representing the string in _override_controller_path_socket_ (not including the terminating NULL).
+_override_controller_path_socket_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
+_override_controller_path_socket_prefix_length_ The number of bytes representing the string in _override_controller_path_socket_prefix_ (not including the terminating NULL).
+_override_controller_path_socket_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
+_override_controller_path_socket_suffix_length_ The number of bytes representing the string in _override_controller_path_socket_suffix_ (not including the terminating NULL).
+
+_pthread_attr_unsupported_ Disable non-portable functionality associated with pthread_attr.
+_pthread_sigqueue_unsupported_ Disable GNU specific sigqueue().
diff --git a/data/build/dependencies b/data/build/dependencies
new file mode 100644 (file)
index 0000000..ca0cecf
--- /dev/null
@@ -0,0 +1,48 @@
+# fss-0000
+
+f_type
+f_status
+f_memory
+f_type_array
+f_string
+f_utf
+f_account
+f_capability
+f_color
+f_compare
+f_console
+f_control_group
+f_conversion
+f_directory
+f_environment
+f_execute
+f_file
+f_fss
+f_iki
+f_limit
+f_parse
+f_path
+f_pipe
+f_print
+f_rip
+f_signal
+f_socket
+f_status_string
+f_thread
+
+fl_control_group
+fl_conversion
+fl_directory
+fl_environment
+fl_fss
+fl_iki
+fl_path
+fl_print
+
+fll_control_group
+fll_error
+fll_execute
+fll_fss
+fll_print
+fll_program
+fll_status_string
diff --git a/data/build/fakefile b/data/build/fakefile
new file mode 100644 (file)
index 0000000..1de733a
--- /dev/null
@@ -0,0 +1,51 @@
+# fss-0005 iki-0002
+
+settings:
+  fail exit
+  modes individual individual_thread level monolithic clang test fanalyzer coverage thread threadlesss
+
+  environment PATH LD_LIBRARY_PATH
+  environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
+
+main:
+  build settings
+  build settings.controller
+  build settings.init
+
+build_controller:
+  build settings
+  build settings.controller
+
+build_init:
+  build settings
+  build settings.init
+
+install:
+  shell ./install.sh parameter:'work' parameter:'verbosity' parameter:'color'
+  shell ./install.sh parameter:'work' parameter:'verbosity' parameter:'color' -s data/build/settings.controller
+  shell ./install.sh parameter:'work' parameter:'verbosity' parameter:'color' -s data/build/settings.init
+
+install_controller:
+  shell ./install.sh parameter:'work' parameter:'verbosity' parameter:'color'
+  shell ./install.sh parameter:'work' parameter:'verbosity' parameter:'color' -s data/build/settings.controller
+
+install_init:
+  shell ./install.sh parameter:'work' parameter:'verbosity' parameter:'color'
+  shell ./install.sh parameter:'work' parameter:'verbosity' parameter:'color' -s data/build/settings.init
+
+help:
+  print
+  print context:'title'Fakefile Options for Controller Program.context:'reset'
+
+  print
+  print The following operations are available\:
+  print "  - context:'notable'help:context:'reset'               Perform the help operation, printing this message."
+  print "  - context:'notable'build_controller:context:'reset'   Compilation using the build settings mode for the controller program."
+  print "  - context:'notable'build_init:context:'reset'         Compilation using the build settings mode for the init program."
+  print "  - context:'notable'install:context:'reset'            A helper operation that simply calls the ./install.sh script with default settings."
+  print "  - context:'notable'install_controller:context:'reset' A helper operation that simply calls the ./install.sh script with default settings."
+  print "  - context:'notable'install_init:context:'reset'       A helper operation that simply calls the ./install.sh script with default settings."
+  print "  - context:'notable'main:context:'reset'               The default compilation using the build settings mode."
+
+  print
+  print The context:'notable'install context:'reset'operation supports the context:'notable'work,context:'reset' context:'notable'verbosity,context:'reset' and context:'notable'color context:'reset'parameters.
diff --git a/data/build/settings b/data/build/settings
new file mode 100644 (file)
index 0000000..d074de0
--- /dev/null
@@ -0,0 +1,99 @@
+# fss-0001
+#
+# Modes:
+#   - individual:        Compile using per project (individual) libraries, does not handle thread or threadless cases.
+#   - individual_thread: This is required when compiling in individual mode with "thread" mode.
+#   - level:             Compile using per level libraries.
+#   - monolithic:        Compile using per monolithic libraries.
+#   - clang:             Use clang rather than the default, which is generally gcc.
+#   - gcc:               Use gcc specific settings.
+#   - test:              Compile for a test, such as unit testing.
+#   - fanalyzer:         Compile using GCC's -fanalyzer compile time option.
+#   - coverage:          Compile for building coverage.
+#   - thread:            Compile with thread support.
+#   - threadless:        Compile without thread support.
+#
+
+build_name controller
+
+version_major 0
+version_minor 7
+version_micro 0
+version_file micro
+version_target minor
+
+modes individual individual_thread level monolithic clang gcc test fanalyzer coverage thread threadless as_init
+modes_default monolithic thread gcc
+
+build_compiler gcc
+build_compiler-clang clang
+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_print -lfll_program -lfll_status_string
+build_libraries-individual_thread -lf_thread
+build_libraries-individual -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_path -lfl_print
+build_libraries-individual -lf_account -lf_capability -lf_color -lf_compare -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_parse -lf_path -lf_pipe -lf_print -lf_rip -lf_signal -lf_socket -lf_status_string -lf_string -lf_type_array -lf_utf
+build_libraries-individual_thread -lf_thread
+build_libraries-level -lfll_2 -lfll_1 -lfll_0
+build_libraries-monolithic -lfll
+
+build_sources_object main/common.c main/common/define.c main/common/enumeration.c main/common/print.c main/common/string.c main/common/type.c
+build_sources_object main/print/data.c main/print/debug.c main/print/error.c main/print/message.c main/print/verbose.c main/print/warning.c
+build_sources_object main/signal.c main/thread.c
+
+build_sources_headers main/common.h main/controller.h main/common/define.h main/common/enumeration.h main/common/print.h main/common/string.h main/common/type.h
+build_sources_headers main/print/data.h main/print/debug.h main/print/error.h main/print/message.h main/print/verbose.h main/print/warning.h
+build_sources_headers main/signal.h main/thread.h
+
+build_sources_documentation man
+
+build_sources_setting controller
+
+build_script yes
+build_shared yes
+build_static no
+
+path_headers program/controller
+path_library_script script
+path_library_shared shared
+path_library_static static
+path_object_script script
+path_object_shared shared
+path_object_static static
+path_program_script script
+path_program_shared shared
+path_program_static static
+
+has_path_standard yes
+preserve_path_headers yes
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+environment PATH LD_LIBRARY_PATH
+environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
+
+#defines -D_di_libcap_
+defines -D_libcap_legacy_only_
+defines-threadless -D_di_thread_support_
+defines-thread -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_
+defines-as_init -D_controller_as_init_
+
+flags -O2 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses -Wno-missing-braces
+flags -fstack-clash-protection -fno-delete-null-pointer-checks
+flags -D_FORTIFY_SOURCE=3
+flags -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
+flags-thread -pthread
+flags-clang -Wno-logical-op-parentheses
+flags-gcc_13 -fstrict-flex-arrays=3
+flags-test -O0 -fstack-protector-strong -Wall
+flags-fanalyzer -fanalyzer
+flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/
+
+flags_library -fPIC
+flags_object -fPIC
+flags_program -fPIE
diff --git a/data/build/settings.controller b/data/build/settings.controller
new file mode 100644 (file)
index 0000000..3431701
--- /dev/null
@@ -0,0 +1,99 @@
+# fss-0001
+#
+# Modes:
+#   - individual:        Compile using per project (individual) libraries, does not handle thread or threadless cases.
+#   - individual_thread: This is required when compiling in individual mode with "thread" mode.
+#   - level:             Compile using per level libraries.
+#   - monolithic:        Compile using per monolithic libraries.
+#   - clang:             Use clang rather than the default, which is generally gcc.
+#   - gcc:               Use gcc specific settings.
+#   - test:              Compile for a test, such as unit testing.
+#   - fanalyzer:         Compile using GCC's -fanalyzer compile time option.
+#   - coverage:          Compile for building coverage.
+#   - thread:            Compile with thread support.
+#   - threadless:        Compile without thread support.
+#
+
+build_name controller
+
+version_major 0
+version_minor 7
+version_micro 0
+version_file micro
+version_target minor
+
+modes individual individual_thread level monolithic clang gcc test fanalyzer coverage thread threadless as_init
+modes_default monolithic thread gcc
+
+build_compiler gcc
+build_compiler-clang clang
+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_print -lfll_program -lfll_status_string
+build_libraries-individual_thread -lf_thread
+build_libraries-individual -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_path -lfl_print
+build_libraries-individual -lf_account -lf_capability -lf_color -lf_compare -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_parse -lf_path -lf_pipe -lf_print -lf_rip -lf_signal -lf_socket -lf_status_string -lf_string -lf_type_array -lf_utf
+build_libraries-individual_thread -lf_thread
+build_libraries-level -lfll_2 -lfll_1 -lfll_0
+build_libraries-monolithic -lfll
+
+build_objects_library main/controller.o
+
+build_sources_library controller/controller.c
+
+build_sources_program controller/config.c controller/main.c
+
+build_sources_headers controller/controller.h
+
+build_sources_documentation man
+
+build_sources_setting controller
+
+build_script yes
+build_shared yes
+build_static no
+
+path_headers program/controller
+path_library_script script
+path_library_shared shared
+path_library_static static
+path_object_script script
+path_object_shared shared
+path_object_static static
+path_program_script script
+path_program_shared shared
+path_program_static static
+
+has_path_standard yes
+preserve_path_headers yes
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+environment PATH LD_LIBRARY_PATH
+environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
+
+#defines -D_di_libcap_
+defines -D_libcap_legacy_only_
+defines-threadless -D_di_thread_support_
+defines-thread -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_
+defines-as_init -D_controller_as_init_
+
+flags -O2 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses -Wno-missing-braces
+flags -fstack-clash-protection -fno-delete-null-pointer-checks
+flags -D_FORTIFY_SOURCE=3
+flags -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
+flags-thread -pthread
+flags-clang -Wno-logical-op-parentheses
+flags-gcc_13 -fstrict-flex-arrays=3
+flags-test -O0 -fstack-protector-strong -Wall
+flags-fanalyzer -fanalyzer
+flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/
+
+flags_library -fPIC
+flags_object -fPIC
+flags_program -fPIE
diff --git a/data/build/settings.init b/data/build/settings.init
new file mode 100644 (file)
index 0000000..1f30305
--- /dev/null
@@ -0,0 +1,99 @@
+# fss-0001
+#
+# Modes:
+#   - individual:        Compile using per project (individual) libraries, does not handle thread or threadless cases.
+#   - individual_thread: This is required when compiling in individual mode with "thread" mode.
+#   - level:             Compile using per level libraries.
+#   - monolithic:        Compile using per monolithic libraries.
+#   - clang:             Use clang rather than the default, which is generally gcc.
+#   - gcc:               Use gcc specific settings.
+#   - test:              Compile for a test, such as unit testing.
+#   - fanalyzer:         Compile using GCC's -fanalyzer compile time option.
+#   - coverage:          Compile for building coverage.
+#   - thread:            Compile with thread support.
+#   - threadless:        Compile without thread support.
+#
+
+build_name init
+
+version_major 0
+version_minor 7
+version_micro 0
+version_file micro
+version_target minor
+
+modes individual individual_thread level monolithic clang gcc test fanalyzer coverage thread threadless as_init
+modes_default monolithic thread gcc
+
+build_compiler gcc
+build_compiler-clang clang
+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_print -lfll_program -lfll_status_string
+build_libraries-individual_thread -lf_thread
+build_libraries-individual -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_path -lfl_print
+build_libraries-individual -lf_account -lf_capability -lf_color -lf_compare -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_parse -lf_path -lf_pipe -lf_print -lf_rip -lf_signal -lf_socket -lf_status_string -lf_string -lf_type_array -lf_utf
+build_libraries-individual_thread -lf_thread
+build_libraries-level -lfll_2 -lfll_1 -lfll_0
+build_libraries-monolithic -lfll
+
+build_objects_library main/controller.o
+
+build_sources_library init/init.c
+
+build_sources_program init/config.c init/main.c
+
+build_sources_headers init/init.h
+
+build_sources_documentation man
+
+build_sources_setting init
+
+build_script yes
+build_shared yes
+build_static no
+
+path_headers program/controller
+path_library_script script
+path_library_shared shared
+path_library_static static
+path_object_script script
+path_object_shared shared
+path_object_static static
+path_program_script script
+path_program_shared shared
+path_program_static static
+
+has_path_standard yes
+preserve_path_headers yes
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+environment PATH LD_LIBRARY_PATH
+environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
+
+#defines -D_di_libcap_
+defines -D_libcap_legacy_only_
+defines-threadless -D_di_thread_support_
+defines-thread -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_
+defines-as_init -D_controller_as_init_
+
+flags -O2 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses -Wno-missing-braces
+flags -fstack-clash-protection -fno-delete-null-pointer-checks
+flags -D_FORTIFY_SOURCE=3
+flags -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
+flags-thread -pthread
+flags-clang -Wno-logical-op-parentheses
+flags-gcc_13 -fstrict-flex-arrays=3
+flags-test -O0 -fstack-protector-strong -Wall
+flags-fanalyzer -fanalyzer
+flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/
+
+flags_library -fPIC
+flags_object -fPIC
+flags_program -fPIE
diff --git a/data/documentation/man/man1/controller.1 b/data/documentation/man/man1/controller.1
new file mode 100644 (file)
index 0000000..80c49e5
--- /dev/null
@@ -0,0 +1,102 @@
+.TH CONTROLLER "1" "January 2023" "FLL - Controller 0.7.0" "User Commands"
+.SH NAME
+controller \- Perform a series of operations in a manner similar to that of an init program.
+.SH SYNOPSIS
+.B controller
+[\fI\,OPTIONS\/\fR] [\fI\,ENTRY\/\fR]
+.SH DESCRIPTION
+.PP
+This program performs a series of operations described by an \fBentry\fR file.
+This includes error handling.
+
+The \fBentry\fR file consists of several rules defined in individual \fBrule\fR files.
+Thee \fBrule\fR file allows for both programs and scripts to be executed.
+Any scripting language whose program supports piping commands to it are effectively supported scripting languages.
+
+Upon completion, this program may optionally process an \fBexit\fR file whose name is identical to the \fBentry\fR used.
+
+When both the \fB\-\-simulate\fR parameter and the \fB\-\-validate\fR parameter are specified, then additional information on each would be executed rule is printed but no simulation is performed.
+
+The default interrupt behavior is to operate as if the \fB\-\-interruptible\fR parameter is passed.
+
+Specify an empty string for the \fB\-\-pid\fR parameter to disable pid file creation for this program.
+.SH OPTIONS
+.TP
+\fB\{\-h, \-\-help\fR
+Print the help message.
+.TP
+\fB+C, ++copyright\fR
+Print the copyright.
+.TP
+\fB+d, ++dark\fR
+Output using colors that show up better on dark backgrounds.
+.TP
+\fB+l, ++light\fR
+Output using colors that show up better on light backgrounds.
+.TP
+\fB+n, ++no_color\fR
+Do not print using color.
+.TP
+\fB+Q, ++quiet\fR
+Decrease verbosity, silencing most output.
+.TP
+\fB+E, ++error\fR
+Decrease verbosity, using only error output.
+.TP
+\fB+N, ++normal\fR
+Set verbosity to normal.
+.TP
+\fB+V, ++verbose\fR
+Increase verbosity beyond normal output.
+.TP
+\fB+D, ++debug\fR
+Enable debugging, significantly increasing verbosity beyond normal output.
+.TP
+\fB+v, ++version\fR
+Print only the version number.
+.TP
+\fB\-c, \-\-cgroup\fR
+Specify a custom control group file path, such as '/sys/fs/cgroup/'.
+.TP
+\fB\-d, \-\-daemon\fR
+Run in daemon only mode (do not process the entry).
+.TP
+\fB\-I, \-\-init\fR
+The program will run as an init replacement.
+.TP
+\fB\-i, \-\-interruptible\fR
+Designate that this program can be interrupted by a signal.
+.TP
+\fB\-p, \-\-pid\fR
+Specify a custom pid file path, such as 'controller/run/default.pid'.
+.TP
+\fB\-s, \-\-settings\fR
+Specify a custom settings path, such as 'controller/'.
+.TP
+\fB\-S, \-\-simulate\fR
+Run as a simulation.
+.TP
+\fB\-k, \-\-socket\fR
+Specify a custom socket file path, such as 'controller/run/default.socket'.
+.TP
+\fB\-U, \-\-uninterruptible\fR
+Designate that this program cannot be interrupted by a signal.
+.TP
+\fB\-v, \-\-validate\fR
+Validate the settings (entry and rules) without running (does not simulate).
+.SH ENTRY
+.TP
+The name of an \fBentry\fR.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-packet\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, GNU LGPL Version 2.1 or later.
diff --git a/data/documentation/man/man5/controller-actions.5 b/data/documentation/man/man5/controller-actions.5
new file mode 100644 (file)
index 0000000..eb79f8b
--- /dev/null
@@ -0,0 +1,89 @@
+.TH controller-rule "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "rule" file.
+.SH SYNOPSIS
+.B rule
+.SH DESCRIPTION
+.PP
+This describes the intent and purpose of the actions provided for individual Rules (or things related to a Rule).
+
+Each Action represents a specific intent and purpose but many of these actions are customizable via the rule file.
+One should expect an Action to operate as described here but the system administrator or distributor is fully capable of doing something different.
+For those doing something different, appropriate documentation is suggested.
+
+These actions should be usable by any \fBcontrol\fR program that communicates with this \fBcontroller\fR program.
+Should any \fBcontrol\fR or \fBcontroller\fR program implementation not support any particular Action for any reason, one should report that the Action is unsupported.
+
+\- \fBFreeze Action\fR:
+  The Freeze Action is an extension of a Control Group.
+  This is internal to the \fBcontroller\fR program and is not customizable via any Rule file.
+  For a customizable \fBfreeze\fR\-like capability, look into the Pause and Resume Actions.
+  This is the complement of the Thaw Action.
+
+  This designates that a processes Control Group is to be frozen.
+  All Rules (or any process not controlled by the \fBcontroller\fR) that is within the same Control Group will be frozen.
+  (@todo consider instead designing this around the Control Groups instead of a \fBrule\fR.)
+  (This documentation will likely change with consideration to the above @todo once this gets implemented.)
+
+  This must not attempt to freeze (or unfreeze) the Control Group that the \fBcontroller\fR belongs to.
+  Therefore, if a Rule does not specify a Control Group, then it is likely that the Freeze Action will be unsupported for that Rule/Control Group.
+
+\- \fBKill Action\fR:
+  Forcefully terminate some process controlled by the \fBcontroller\fR.
+  This action cannot be blocked and it is recommended to use a Stop Action instead for a more proper termination.
+
+\- \fBPause Action\fR:
+  The Pause Action will pause (or freeze) the process controlled by the Rule.
+  Although similar to the Freeze Action, this is intended to communicate to an individual process and inform to Pause.
+  This is complemented by the Resume Action.
+
+\- \fBRestart Action\fR:
+  The Restart Action will either perform a Stop Action and then a Restart Action or it will perform the Restart Action designated in some Rule file.
+  Ideally this should inform some process to perform its own restart routines.
+
+\- \fBResume Action\fR:
+  The Resume Action will unpause (or unfreeze) the process controlled by the Rule.
+  Although similar to the Thaw Action, this is intended to communicate to an individual process and inform to Resume.
+  This is complemented by the Pause Action.
+
+\- \fBReload Action\fR:
+  The Reload Action will perform the Reload Action designated in some Rule file.
+  Ideally this should inform some process to perform its own reload routines.
+  Many programs often differentiate the concept \fBreload\fR from the concept "restart" in that the program remains running during a \fBreload\fR.
+
+\- \fBStart Action\fR:
+  The Start Action will perform the Start Action designated in some Rule file.
+  This action should be used to start some program or script.
+  This is the action called by Entry file.
+  This is complemented by the Stop Action.
+
+\- \fBStop Action\fR:
+  The Stop Action will perform the Stop Action designated in some Rule file.
+  This action should be used to stop some program or script.
+  This is the action called for all running controlled processes on shutdown.
+  This is complemented by the Start Action.
+
+\- \fBThaw Action\fR:
+  The Thaw Action is an extension of a Control Group.
+  This is internal to the \fBcontroller\fR program and is not customizable via any Rule file.
+  For a customizable \fBthaw\fR\-like capability, look into the \fBpause\fR and \fBresume\fR Actions.
+  This is complemented by the Freeze Action.
+
+  This designates that a processes Control Group is to be unfrozen.
+  All Rules (or any process not controlled by the \fBcontroller\fR) that is within the same Control Group will be unfrozen.
+
+  This must not attempt to thaw (or unthaw) the Control Group that the \fBcontroller\fR belongs to.
+  Therefore, if a Rule does not specify a Control Group, then it is likely that the Thaw Action will be unsupported for that Rule/Control Group.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-packet\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/data/documentation/man/man5/controller-entry.5 b/data/documentation/man/man5/controller-entry.5
new file mode 100644 (file)
index 0000000..976bcf3
--- /dev/null
@@ -0,0 +1,352 @@
+.TH controller-entry "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "entry" file.
+.SH SYNOPSIS
+.B entry
+.SH DESCRIPTION
+.PP
+This describes the intent and purpose of an Entry file.
+
+An Entry file, such as \fBdefault.entry\fR, is intended to store a set of rules in which the controller will process on execution.
+These are used to run some set of commands, such as booting a system.
+
+The \fBmain\fR Item Object is always executed first (Therefore \fBmain\fR is both reserved and required).
+All other Basic List Objects are not executed unless either an \fBitem\fR or a \fBfailsafe\fR specifies a valid Item name.
+Execution of all Items is top\-down.
+
+\- The \fBsettings\fR item Object:
+  Represents Entry settings and is not an \fBitem\fR that can be executed.
+  A number of settings are supported, but if this Item Object is not specified, then defaults are used.
+  The following settings are available: \fBcontrol\fR, \fBcontrol_group\fR, \fBcontrol_mode\fR, \fBcontrol_user\fR, \fBdefine\fR, \fBmode\fR, \fBparameter\fR, \fBpid\fR, \fBpid_file\fR, \fBsession\fR, \fBshow\fR.
+
+  \- The \fBcontrol\fR setting:
+    Represents the path to the socket file in which the Controller uses to communicate over with clients such as a Control program.
+    A relative path is relative to the Controller PID directory.
+    An absolute path is treated exactly as the path given.
+    If no socket setting is specified, then no socket will be made available.
+    This socket file is only created once \fBready\fR mode is achieved.
+
+    Providing \fBreadonly\fR after the socket path instructs the Controller program not to create or delete the Socket file because the file system is assumed to be readonly.
+    The socket file itself must therefore already exist.
+    This should be possible in the cases of file systems that have pre\-created a socket file at the designated path.
+    When \fBreadonly\fR, the group, mode, and user are also not processed effectively resulting in the \fBcontrol_group\fR, \fBcontrol_mode\fR, and \fBcontrol_user\fR settings being ignored.
+
+    Future versions might expand this into supporting network addresses in addition to socket files.
+
+  \- The \fBcontrol_group\fR setting:
+    Represents the group name or group ID to assign to the socket file as the group.
+
+  \- The \fBcontrol_mode\fR setting:
+    Represents the file mode assigned to the socket file.
+    This could either be the string version that might look like \fBu+rw\-x,g+r\-wx,o\-rwx\fR or a numeric value like \fB0750\fR.
+
+  \- The \fBcontrol_user\fR setting:
+    Represents the user name or user ID to assign to the socket file as the owner.
+
+  \- The \fBdefine\fR setting:
+    Use this to define an environment variable (this overwrites any existing environment variable with this name).
+    A define is both exported as an environment variable as well as exposed as an IKI variable.
+    Example IKI variable substitution: for \fBdefine PATH /bin:/sbin\fR, the associated IKI variable would look like: PATH.
+
+    All environment variables, including those defined using this, must be in the \fBenvironment\fR list in any given Rule to be exported to the executed process.
+    Environment variables added here that are not added to the environment are still exposed as an IKI variable.
+
+    This is only expanded within any Rule operated on by this Entry.
+
+  \- The \fBmode\fR setting:
+    Represents the mode in which the Entry is operating in.
+    The following modes are supported: \fBhelper\fR, \fBprogram\fR, and \fBservice\fR.
+
+    - The \fBhelper\fR mode:
+      Designates that the Entry operates as a helper for starting programs or performing actions and exits when complete.
+      On exit, any background (asynchronous) processes are not cancelled.
+      If terminated, the foreground (synchronous) process is cancelled.
+      Will call the \fBexit\fR with the same name as this Entry, but with the extension \fBexit\fR, such as \fBdefault.exit\fR.
+      Supports the Item Action \fBexecute\fR to execute a program (switching the \fBcontroller\fR program entirely with the executed process).
+
+    \- The \fBprogram\fR mode:
+      Designates that the Entry operates as a program and exits when complete.
+      On exit, any background (asynchronous) processes are also cancelled.
+      If terminated, the foreground (synchronous) process is cancelled.
+      Will call the \fBexit\fR with the same name as this Entry, but with the extension \fBexit\fR, such as \fBdefault.exit\fR.
+      Supports the Item Action \fBexecute\fR to execute a program (switching the \fBcontroller\fR program entirely with the executed process).
+
+    \- The \fBservice\fR mode:
+      Designates that the Entry operates as a service and will sit and wait for control commands when complete.
+      Will call the \fBexit\fR with the same name as this Entry, but with the extension \fBexit\fR, such as \fBdefault.exit\fR.
+      Does not support the Item Action \fBexecute\fR.
+      This is the default mode.
+
+  \- The \fBparameter\fR setting:
+    Use this to define an IKI variable name and value.
+    These do not conflict with environment variables and are not exposed as environment variables.
+    Example IKI variable substitution: for \fBparameter hello world\fR, the associated IKI variable would look like: hello.
+
+    This is only expanded within any Rule operated on by this Entry.
+
+  \- The \fBpid\fR setting:
+    Represents how the Entry PID file is generated or not.
+    The following modes are supported: \fBdisable\fR, \fBrequire\fR, and \fBready\fR.
+    For \fBdisable\fR, not PID file representing the Entry is created.
+    For \fBrequire\fR, check to see if the PID file exists for an Entry at startup and then when \fBready\fR create a PID file, display error on PID file already exists or on failure and then fail.
+    For \fBready\fR, when \fBready\fR create a PID file, display error on failure and then fail (does not check if PID file exists).
+
+  \- The \fBpid_file\fR setting:
+    When \fBpid\fR is not disabled this represents the path to the PID file.
+    If \fB\-p\fR or \fB\-\-pid\fR is passed to the controller program, then this value is ignored in favor of the value passed along the command line.
+
+  \- The \fBsession\fR setting:
+    Represents the default way in which child processes are executed.
+    This default can be overridden by individual Rules.
+    For \fBnew\fR, Execute Rule processes in a new session setting the process group to the executed process' id (making the executed process a \fBcontrolling terminal\fR).
+    For \fBsame\fR, Execute Rule processes in the same session where the process group is set to the parent process id.
+
+  \- The \fBshow\fR setting:
+    Represents the way Entry processing presents information to the screen.
+    This applies only to the Entry and Rule processing itself and does not handle the output of programs and scripts being executed by some Entry or Rule.
+    The following show options are supported: \fBnormal\fR and \fBinit\fR.
+    For \fBnormal\fR, will not report the start or stop of some Entry or Rule execution but will report any errors or warnings as appropriate.
+    For \fBinit\fR, will report when starting programs and may include reporting success and failure status.
+
+  \- The \fBtimeout\fR setting:
+    Represents the default timeouts for the Entry.
+    See the \fBtimeout\fR Action below for details.
+
+\- The \fBmain\fR item Object:
+  Each \fBitem\fR supports the following Action Names: \fBconsider\fR, \fBexecute\fR, \fBfailsafe\fR, \fBfreeze\fR, \fBitem\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBready\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBtimeout\fR.
+  Of those types, the following are considered a \fBrule\fR Action: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBthaw\fR.
+
+  \- The \fBconsider\fR Item Action:
+    A special case of a \fBrule\fR Action.
+    All Action Parameters are the same as with the \fBrule\fR Action Parameters.
+    The difference is that \fBconsider\fR is only processed (instead of being processed and executed) and when some \fBrule\fR Action designates that this consideration is required (via \fBneed\fR), wanted (via \fBwant\fR), or wished for (via \fBwish\fR) from the within the Rule file.
+    If this is determined to be executed, then this is immediately executed when needed, wanted or wished for and applies all properties as appropriate (such as \fBasynchronous\fR, for example).
+    If this is determined not to be executed, then this \fBconsider\fR is ignored as if it was never there in the first place.
+
+  \- The \fBexecute\fR Item Action:
+    Execute into the specified program.
+    On successful execution, the controller program will no longer be running and will be replaced with the designated program.
+    This Item Action is only supported when operating in \fBprogram\fR mode.
+
+  \- The \fBfailsafe\fR Item Action:
+    Accepts only a valid Item Name in which will be executed when a failure is detected.
+    Only a single \fBfailsafe\fR Item Action may function at a time.
+    Each successive \fBfailsafe\fR Item Action specified replaces the previously defined \fBfailsafe\fR Item Action (in a top\-down manner).
+    When operating in \fBfailsafe\fR, the \fBrequire\fR Item Action is ignored (given that it is meaningless once operating in \fBfailsafe\fR mode).
+
+  \- The \fBfreeze\fR Item Action:
+    A \fBrule\fR Action for freezing some Control Group.
+    This Item Action will process the \fBfreeze\fR inner Content of the named Rule.
+    This is specific to Control Groups and is not yet fully implemented.
+    Once implemented this documentation will need to be updated and clarified.
+
+  \- The \fBitem\fR Item Action:
+    Accepts only a valid Item Name in which will be immediately executed.
+    Any valid Item Name, except for the reserved \fBmain\fR, may be used.
+
+  \- The \fBkill\fR Item Action:
+    A \fBrule\fR Action for forcibly terminating some process.
+    This Item Action will process the \fBkill\fR inner Content of the named Rule.
+
+  \- The \fBpause\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBpause\fR inner Content of the named Rule.
+
+  \- The \fBreload\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBreload\fR inner Content of the named Rule.
+
+  \- The \fBrestart\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBrestart\fR inner Content of the named Rule.
+
+  \- The \fBresume\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBresume\fR inner Content of the named Rule.
+
+  \- The \fBready\fR Item Action:
+    Instructs the controller program when it is safe to perform normal tasks, such as creating the PID file.
+    When not specified, the state is always assumed to be ready.
+    For example, the controller program may be used as a full blown \fBinit\fR replacement and therefore may need to mount the /var/run/ directory.
+    If the PID file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready.
+    This could be a problem, such as on a read\-only file system the PID creation fails and controller bails out on error.
+    Adding \fBready\fR essentially specifies a point in time in the Entry in which things are expected to be safe for such basic operations.
+    When the optional \fBwait\fR is provided, then \fBready\fR will wait for all currently started asynchronous processes to complete before operating.
+
+  \- The \fBstart\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBstart\fR inner Content of the named Rule.
+
+  \- The \fBstop\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBstop\fR inner Content of the named Rule.
+
+  \- The \fBthaw\fR Item Action:
+    A \fBrule\fR Action for unfreezing some Control Group.
+    This Item Action will process the \fBthaw\fR inner Content of the named Rule.
+    This is specific to Control Groups and is not yet fully implemented.
+    Once implemented this documentation will need to be updated and clarified.
+
+  \- The \fBtimeout\fR Item Action:
+    (This is not currently fully implemented, only \fBexit\fR is implemented.)
+    Provides default global settings for each of the four special situations: \fBexit\fR, \fBkill\fR, \fBstart\fR, and \fBstop\fR.
+    Each of these may only have a single one exist at a time (one \fBexit\fR, one \fBkill\fR, one \fBstart\fR, and one \fBstop\fR).
+    Each successive \fBtimeout\fR Item Action, specific to each Action Name (such as \fBstart\fR), specified replaces the previously defined \fBtimeout\fR Action (in a top\-down manner).
+    The second Content for each of these, when specified, may be a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+    For \fBkill\fR, this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule).
+    For \fBstart\fR, this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed.
+    For \fBstop\fR, this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed.
+    If the second Content is not specified, then this disables the type (prevents the specified timeout action).
+    For \fBexit\fR, this represents the number of MegaTime to wait when the Controller program is exiting (such as having received a terminate signal).
+    In this case, a terminate signal is sent to all child processes.
+    The \fBexit\fR timeout represents the amount of time to wait after sending the terminate signal before sending a kill signal to each child process still running.
+    When disabled, the program will not send a kill signal will continue running until all child processes to terminate.
+    The \fBexit\fR timeout does not get applied to any Rule.
+.SH SPECIFICATION
+.PP
+The Entry files follow the \fBFSS\-0005 (Somewhat Basic List)\fR format.
+
+An Entry file name is expected to have the file extension \fB.entry\fR.
+
+For each Entry file:
+  \- The outer most part is a \fBFSS\-0002 (Basic List)\fR.
+  \- The Basic List Object is considered the \fBItem\fR.
+  \- The Basic List Content are considered the \fBActions\fR.
+  \- The \fBActions\fR are \fBFSS\-0001 (Extended)\fR.
+  \- Each Action Object is the \fBAction Name\fR.
+  \- Each Action Content are the \fBAction Parameters\fR.
+
+The Items:
+  \- \fBmain\fR: required.
+
+  \- \fBsettings\fR: optional, Actions may be one of:
+    \- \fBcontrol\fR: One to two Content.
+      The first Content is a relative or absolute path to a socket file.
+      The second Content an optional \fBreadonly\fR.
+    \- \fBcontrol_group\fR: Exactly one Content that is a group name or group id.
+    \- \fBcontrol_mode\fR: Exactly one Content that is a valid file mode.
+    \- \fBcontrol_user\fR: Exactly one Content that is a user name or user id.
+    \- \fBdefine\fR: Two Content, the first Content must be a case\-sensitive valid environment variable name (alpha\-numeric or underscore, but no leading digits).
+    \- \fBmode\fR: Exactly one Content that is one of \fBprogram\fR or \fBservice\fR.
+    \- \fBparameter\fR: Two Content, the first Content must be a case\-sensitive valid IKI name and the second being an IKI value.
+    \- \fBpid\fR: Exactly one Content that is one of \fBdisable\fR, \fBrequire\fR, or \fBready\fR.
+    \- \fBpid_file\fR: Exactly one Content that is a relative or absolute path to a pid file.
+    \- \fBsession\fR: Exactly one Content that is one of \fBnew\fR or \fBsame\fR.
+    \- \fBshow\fR: Exactly one Content that is one of \fBnormal\fR or \fBinit\fR.
+    \- \fBtimeout\fR: One or two content with the first being one of \fBexit\fR, \fBstart\fR, \fBstop\fR, or \fBkill\fR and the (optional) second Content being a positive whole number or 0.
+
+  The Entry file may have any other valid Item Objects, but only the above are reserved.
+
+  The Actions:
+    \- \fBconsider\fR: One or more Content.
+      The first Content is the relative file path (without any leading/trailing slashes and without file extension).
+      The second Content is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBexecute\fR: One or more Content.
+      The first Content is the program name or full path to the program (the program may be a script).
+      All remaining Content are passed as parameters to the program being executed.
+
+    \- \fBfailsafe\fR: One Content that is a valid Object name, except for the reserved \fBmain\fR.
+
+    \- \fBfreeze\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBitem\fR: One Content that is a valid Object name, except for the reserved \fBmain\fR.
+
+    \- \fBkill\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBpause\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBready\fR: Zero or One Content.
+      The first may only be one of:
+      \- \fBwait\fR
+
+    \- \fBreload\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBrestart\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBresume\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBstart\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBstop\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBthaw\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBtimeout\fR: One or two Content.
+      The first being one of:
+        \- \fBexit\fR
+        \- \fBstart\fR
+        \- \fBstop\fR
+        \- \fBkill\fR
+      The (optional) second Content being a positive whole number or 0.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-packet\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/data/documentation/man/man5/controller-exit.5 b/data/documentation/man/man5/controller-exit.5
new file mode 100644 (file)
index 0000000..a4969ea
--- /dev/null
@@ -0,0 +1,283 @@
+.TH controller-rule "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "rule" file.
+.SH SYNOPSIS
+.B rule
+.SH DESCRIPTION
+.PP
+This describes the intent and purpose of an Exit file.
+
+An Exit file, such as \fBdefault.exit\fR, is intended to store a set of rules in which the controller will process on execution.
+These are used to run some set of commands, such as shutting down a system.
+
+An Exit is a special variation or subset of an Entry.
+
+\- The \fBsettings\fR Item Object:
+  Represents Exit settings and is not an \fBitem\fR that can be executed.
+  A number of settings are supported, but if this Item Object is not specified, then defaults are used.
+  The following settings are available: \fBpid\fR and \fBshow\fR.
+
+  \- The \fBdefine\fR setting:
+    Use this to define an environment variable (this overwrites any existing environment variable with this name).
+    A define is both exported as an environment variable as well as exposed as an IKI variable.
+    Example IKI variable substitution: for \fBdefine PATH /bin:/sbin\fR, the associated IKI variable would look like: PATH.
+
+    All environment variables, including those defined using this, must be in the \fBenvironment\fR list in any given Rule to be exported to the executed process.
+    Environment variables added here that are not added to the environment are still exposed as an IKI variable.
+
+    This is only expanded within any Rule operated on by this Exit.
+
+  \- The \fBparameter\fR setting:
+    Use this to define an IKI variable name and value.
+    These do not conflict with environment variables and are not exposed as environment variables.
+    Example IKI variable substitution: for \fBparameter hello world\fR, the associated IKI variable would look like: hello.
+
+    This is only expanded within any Rule operated on by this Exit.
+
+  \- The \fBpid\fR setting:
+    Represents how the Exit PID file is generated or not.
+    The following modes are supported: \fBdisable\fR, \fBrequire\fR, and \fBready\fR.
+    For \fBdisable\fR, not PID file representing the Exit is created.
+    For \fBrequire\fR, check to see if the PID file exists for an Exit at startup and then when \fBready\fR create a PID file, display error on PID file already exists or on failure and then fail.
+    For \fBready\fR, when \fBready\fR create a PID file, display error on failure and then fail (does not check if PID file exists).
+
+  \- The \fBshow\fR setting:
+    Represents the way Exit processing presents information to the screen.
+    This applies only to the Exit and Rule processing itself and does not handle the output of programs and scripts being executed by some Exit or Rule.
+    The following show options are supported: \fBnormal\fR and \fBinit\fR.
+    For \fBnormal\fR, will not report the start or stop of some Exit or Rule execution but will report any errors or warnings as appropriate.
+    For \fBinit\fR, will report when starting programs and may include reporting success and failure status.
+
+  \- The \fBtimeout\fR setting:
+    Represents the default timeouts for the Exit.
+    See the \fBtimeout\fR Action below for details.
+
+\- The \fBmain\fR Item Object:
+  Is always executed first (Therefore \fBmain\fR is both reserved and required).
+  All other Basic List Objects are not executed unless either an \fBitem\fR or a \fBfailsafe\fR specifies a valid Item name.
+  Execution of all Items are top\-down.
+
+  Each \fBitem\fR supports the following Action Names: \fBconsider\fR, \fBexecute\fR, \fBfailsafe\fR, \fBfreeze\fR, \fBitem\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBready\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBtimeout\fR.
+  Of those types, the following are considered a \fBrule\fR Action: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBthaw\fR.
+
+  \- The \fBconsider\fR Item Action:
+    A special case of a \fBrule\fR Action.
+    All Action Parameters are the same as with the \fBrule\fR Action Parameters.
+    The difference is that \fBconsider\fR is only processed (instead of being processed and executed) and when some \fBrule\fR Action designates that this consideration is required (via \fBneed\fR), wanted (via \fBwant\fR), or wished for (via \fBwish\fR) from the within the Rule file.
+    If this is determined to be executed, then this is immediately executed when needed, wanted or wished for and applies all properties as appropriate (such as \fBasynchronous\fR, for example).
+    If this is determined not to be executed, then this \fBconsider\fR is ignored as if it was never there in the first place.
+
+  \- The \fBexecute\fR Item Action:
+    Execute into the specified program.
+    On successful execution, the controller program will no longer be running and will be replaced with the designated program.
+    This Item Action is only supported when operating in \fBprogram\fR mode.
+
+  \- The \fBfailsafe\fR Item Action:
+    Accepts only a valid Item Name in which will be executed when a failure is detected.
+    Only a single \fBfailsafe\fR Item Action may function at a time.
+    Each successive \fBfailsafe\fR Item Action specified replaces the previously defined \fBfailsafe\fR Item Action (in a top\-down manner).
+    When operating in \fBfailsafe\fR, the \fBrequire\fR Item Action is ignored (given that it is meaningless once operating in \fBfailsafe\fR mode).
+
+  \- The \fBfreeze\fR Item Action:
+    A \fBrule\fR Action for freezing some Control Group.
+    This Item Action will process the \fBfreeze\fR inner Content of the named Rule.
+    This is specific to Control Groups and is not yet fully implemented.
+    Once implemented this documentation will need to be updated and clarified.
+
+  \- The \fBitem\fR Item Action:
+    Accepts only a valid Item Name in which will be immediately executed.
+    Any valid Item Name, except for the reserved \fBmain\fR, may be used.
+
+  \- The \fBkill\fR Item Action:
+    A \fBrule\fR Action for forcibly terminating some process.
+    This Item Action will process the \fBkill\fR inner Content of the named Rule.
+
+  \- The \fBpause\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBpause\fR inner Content of the named Rule.
+
+  \- The \fBreload\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBreload\fR inner Content of the named Rule.
+
+  \- The \fBrestart\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBrestart\fR inner Content of the named Rule.
+
+  \- The \fBresume\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBresume\fR inner Content of the named Rule.
+
+  \- The \fBready\fR Action:
+    Instructs the controller program when it is safe to perform normal tasks, such as creating the PID file.
+    When not specified, the state is always assumed to be ready.
+    For example, the controller program may be used as a full blown \fBinit\fR replacement and therefore may need to mount the /var/run/ directory.
+    If the PID file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready.
+    This could be a problem, such as on a read\-only file system the PID creation fails and controller bails out on error.
+    Adding \fBready\fR essentially specifies a point in time in the Exit in which things are expected to be safe for such basic operations.
+    When the optional \fBwait\fR is provided, then \fBready\fR will wait for all currently started asynchronous processes to complete before operating.
+
+  \- The \fBstart\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBstart\fR inner Content of the named Rule.
+
+  \- The \fBstop\fR Item Action:
+    A \fBrule\fR Action for pausing some process.
+    This Item Action will process the \fBstop\fR inner Content of the named Rule.
+
+  \- The \fBthaw\fR Item Action:
+    A \fBrule\fR Action for unfreezing some Control Group.
+    This Item Action will process the \fBthaw\fR inner Content of the named Rule.
+    This is specific to Control Groups and is not yet fully implemented.
+    Once implemented this documentation will need to be updated and clarified.
+
+  \- The \fBtimeout\fR Item Action:
+    (This is not currently fully implemented, only \fBexit\fR is implemented.)
+    Provides default global settings for each of the four special situations: \fBexit\fR, \fBkill\fR, \fBstart\fR, and \fBstop\fR.
+    Each of these may only have a single one exist at a time (one \fBexit\fR, one \fBkill\fR, one \fBstart\fR, and one \fBstop\fR).
+    Each successive \fBtimeout\fR Item Action, specific to each Action Name (such as \fBstart\fR), specified replaces the previously defined \fBtimeout\fR Action (in a top\-down manner).
+    The second Content for each of these, when specified, may be a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+    For \fBkill\fR, this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule).
+    For \fBstart\fR, this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed.
+    For \fBstop\fR, this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed.
+    If the second Content is not specified, then this disables the type (prevents the specified timeout action).
+
+    For \fBexit\fR, this represents the number of MegaTime to wait when the Controller program is exiting (such as having received a terminate signal).
+    In this case, a terminate signal is sent to all child processes.
+    The \fBexit\fR timeout represents the amount of time to wait after sending the terminate signal before sending a kill signal to each child process still running.
+    When disabled, the program will not send a kill signal will continue running until all child processes to terminate.
+    The \fBexit\fR timeout does not get applied to any Rule.
+.SH SPECIFICATION
+.PP
+The Exit files follow the \fBFSS\-0005 (Somewhat Basic List)\fR format.
+
+An Exit file name is expected to have the file extension \fB.exit\fR.
+
+For each Exit file:
+  \- The outer most part is a \fBFSS\-0002 (Basic List)\fR.
+  \- The Basic List Object is considered the \fBItem\fR.
+  \- The Basic List Content are considered the \fBActions\fR.
+  \- The \fBActions\fR are \fBFSS\-0001 (Extended)\fR.
+  \- Each Action Object is the \fBAction Name\fR.
+  \- Each Action Content are the \fBAction Parameters\fR.
+
+The Items:
+  \- \fBmain\fR: required.
+
+  \- \fBsettings\fR: optional, Actions may be one of:
+    \- \fBpid\fR: Exactly one Content that is one of \fBdisable\fR, \fBrequire\fR, or \fBready\fR.
+    \- \fBsession\fR: Exactly one Content that is one of  \fBnew\fR or \fBsame\fR.
+    \- \fBshow\fR: Exactly one Content that is one of  \fBnormal\fR or \fBinit\fR.
+    \- \fBtimeout\fR: One or Two content with the first being one of \fBexit\fR, \fBstart\fR, \fBstop\fR, or \fBkill\fR and the (optional) second Content being a positive whole number or 0.
+
+  The Exit file may have any other valid Item Objects, but only the above are reserved.
+
+  The Actions:
+    \- \fBconsider\fR: One or more Content.
+      The first Content that is the relative file path (without any leading/trailing slashes and without file extension).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBfailsafe\fR: One Content that is a valid Object name, except for the reserved \fBmain\fR.
+
+    \- \fBfreeze\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBitem\fR: One Content that is a valid Object name, except for the reserved \fBmain\fR.
+
+    \- \fBkill\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBpause\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBready\fR: Zero or One Content.
+      The first may only be one of:
+      \- \fBwait\fR
+
+    \- \fBreload\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBrestart\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBresume\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBstart\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBstop\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBthaw\fR: Two or more Content.
+      The first Content that is the relative directory path (without any leading/trailing slashes).
+      The second Content that is the basename for a rule file.
+      The third and beyond may only be one of:
+        \- \fBasynchronous\fR
+        \- \fBrequire\fR
+        \- \fBwait\fR
+
+    \- \fBtimeout\fR: Two Content.
+      The first being one of:
+        \- \fBexit\fR
+        \- \fBstart\fR
+        \- \fBstop\fR
+        \- \fBkill\fR
+      The (optional) second Content being a positive whole number or 0.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-packet\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/data/documentation/man/man5/controller-packet.5 b/data/documentation/man/man5/controller-packet.5
new file mode 100644 (file)
index 0000000..c62cc93
--- /dev/null
@@ -0,0 +1,140 @@
+.TH controller-rule "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "rule" file.
+.SH SYNOPSIS
+.B rule
+.SH DESCRIPTION
+.PP
+Describes how a packet is designed and intended to be used.
+
+The \fBpacket\fR is the general category in which multiple types of packets belong.
+This describes the different packets based on their \fBtype\fR.
+
+Each packet begins with a control block and a size block followed by a payload block.
+
+  The control block:
+    The leading bit (starting from the left) designates the the format of the payload, which is 0 for string and 1 for binary.
+    The second bit (starting from the left) designates the the byte order for the rest of the packet, which 0 is for little endian and 1 is for big endian.
+    The remaining 6\-bits are reserved for future use.
+
+  The size block:
+    The size block represents the size of the entire packet (the control block, the size blocks, and the payload block).
+    This number is a single 32\-bit unsigned integer.
+
+    Example packet structure:
+
+      [ Control Block ] [ Size Block                                  ] [ Payload Block         ]
+      [ 0b10000000    ] [ 0b00000000 0b00000000 0b00000100 0b11010010 ] [ size: 1229 (1234 \- 5) ]
+
+
+  The payload block:
+    This block is represented by the \fBFSS\-000E (Payload)\fR specification and its structure ad use is described in the next sections.
+
+    The following types of payload are received or sent:
+    1) controller payload.
+    2) error payload.
+    3) init payload.
+
+The controller payload:
+  Commands being sent to the controller and their respective responses utilize a \fBcontroller\fR payload.
+  These are pre\-defined commands to rules or the controller program itself.
+  Commands such as starting or stopping some rule, for example.
+  A controller payload is also sent in response to a controller payload request to represent a success.
+
+    The \fBnow\fR condition designates that the kexec, reboot, or shutdown is to begin immediately.
+    The \fBat\fR condition designates that the kexec, reboot, or shutdown is to begin once a specific date and time is reached by the system clock.
+    The \fBin\fR condition designates that the kexec, reboot, or shutdown is to begin once a specific amount of time is passed by the system clock since the execution of this command started.
+
+  For these \fBtime\fR conditions, different units of time should be supported, such as \fBseconds\fR, \fBdays\fR, \fByears\fR as standard time, Time, or UNIX Time (Epoch Time).
+
+  The normal \fBcontroller\fR payload commands are any valid Rule Action that performs some action.
+  This does not include Actions that provide some setting or configuration (such as \fBwith_pid\fR).
+  Some of the supported commands are: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrerun\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, or \fBthaw\fR.
+  Multiple commands may be sent multiple \fBaction\fR headers.
+  The \fBaction\fR headers are order sensitive, executing from top to bottom, and one does not start until the previous successfully completes.
+
+  Multiple \fBstatus\fR headers may exist in the response so long as they each match an \fBaction\fR in the request.
+
+  The \fBpayload\fR is expected to be empty and have a length of 0 for a request.
+  The \fBpayload\fR may have an \fBFSS\-0000 (Basic)\fR format containing a single Object \fBmessage\fR to represent a message associated with an action.
+  Multiple \fBmessage\fR may exist in the response so long as they each match an \fBaction\fR in the request.
+
+The error payload:
+  The error payload is intended to communicate some sort of failure.
+  The error payload is only sent in response to some request (and not in response to another response).
+  The control (the client) is not expected to send error payloads and the controller (the service) should send an error in response to an error payload or ignore it entirely.
+  The \fBstatus\fR from the \fBheader\fR designates the status code as either a status code name string or a status code number (where a number may have error and warning bits).
+  The \fBpayload\fR will contain a NULL terminated string representing the message used to describe the error.
+
+The init payload:
+  The init payload is intended exclusively for the \fBinit\fR operation mode and is expected to only be available when running as \fBinit\fR.
+  This is used to provide special actions, namely \fBkexec\fR, \fBreboot\fR, and \fBshutdown\fR.
+
+  The \fBkexec\fR is for booting into another kernel, which may effectively be the same as a \fBreboot\fR ("kexec" is currently neither supported nor implemented).
+  The \fBreboot\fR is for rebooting the machine (currently not implemented).
+  The \fBshutdown\fR is for shutting down the machine (currently not implemented).
+  These three commands are configurable to fire off based on conditions.
+.SH SPECIFICATION
+.PP
+The controller program communicates use the \fBFSS\-000F (Packet)\fR.
+This specification declares how the Payload Block, which is in \fBFSS\-000E (Payload)\fR format, is required to be used.
+
+Only a single \fBheader\fR is allowed.
+Only a single \fBpayload\fR is allowed.
+
+Packet Structure:
+  Packet is grouped into the following blocks:
+    \- \fBcontrol\fR: A single 1\-byte block representing control codes.
+    \- \fBsize\fR: A single 4\-byte block representing the size of the entire packet, including the control block.
+
+The \fBheader\fR Object contains the following \fBFSS\-0001 (Extended)\fR Objects (depending on \fBtype\fR):
+  \- \fBaction\fR: A valid action type: \fBfreeze\fR, \fBkexec\fR, \fBkill\fR, \fBpause\fR, \fBreboot\fR, \fBreload\fR, \fBrerun\fR, \fBrestart\fR, \fBresume\fR, \fBshutdown\fR, \fBstart\fR, \fBstop\fR, or \fBthaw\fR.
+  \- \fBlength\fR: A positive whole number inclusively between 0 and 4294965248 representing the length of the \fBpayload\fR (may be in binary, octal, decimal, duodecimal, or hexidecimal).
+  \- \fBstatus\fR: The status code name or number representing an FSS status code, such as F_okay, F_failure, or 200 (where a number may have error and warning bits and may be in binary, octal, decimal, duodecimal, or hexidecimal).
+  \- \fBtype\fR: The packet type that is one of \fBcontroller\fR, \fBerror\fR, or \fBinit\fR.
+
+When there are multiple Objects of the same name inside the \fBheader\fR:
+  \- \fBaction\fR: The order represents the order in which the actions are performed.
+  \- \fBlength\fR: There may only be one length Object, all others after the first are ignored (may be in binary, octal, decimal, duodecimal, or hexidecimal).
+  \- \fBstatus\fR: A status for each action, in the same order as the order of the action, such as F_okay, F_failure, or 200 (where a number may have error and warning bits and may be in binary, octal, decimal, duodecimal, or hexidecimal).
+  \- \fBtype\fR: The first represent the type and all others represents a sub\-type.
+
+There are different headers and payload properties based on the \fBtype\fR.
+
+The \fBcontroller\fR type:
+  Supports the following headers: \fBaction\fR, \fBlength\fR, \fBstatus\fR, and \fBtype\fR.
+
+  Only a single \fBaction\fR may be provided and must exist for request and response packets.
+  Only a single \fBstatus\fR may be provided and must exist for response packets.
+
+  The \fBpayload\fR is dependent on the \fBaction\fR.
+
+The \fBerror\fR type:
+  Supports the following headers: \fBlength\fR, \fBstatus\fR, and \fBtype\fR.
+
+  Only a single \fBstatus\fR may be provided and must exist for request and response packets.
+
+  The \fBpayload\fR is a NULL terminated string whose length is defined by the \fBlength\fR \fBheader\fR Content.
+
+There are different headers and payload properties based on the \fBtype\fR.
+
+The \fBinit\fR type:
+  Supports the following headers: \fBaction\fR, \fBlength\fR, \fBstatus\fR, and \fBtype\fR.
+
+  Only a single \fBaction\fR may be provided and must exist for request and response packets.
+  Only a single \fBstatus\fR may be provided and must exist for response packets.
+
+  The \fBpayload\fR is dependent on the \fBaction\fR.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-rule\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/data/documentation/man/man5/controller-rule.5 b/data/documentation/man/man5/controller-rule.5
new file mode 100644 (file)
index 0000000..47b81b5
--- /dev/null
@@ -0,0 +1,245 @@
+.TH controller-rule "5" "January 2023" "Controller 0.7.0" "File Formats"
+.SH NAME
+Controller \- "rule" file.
+.SH SYNOPSIS
+.B rule
+.SH DESCRIPTION
+.PP
+This describes the intent and purpose of a Rule file.
+
+A Rule file, such as \fBssh.rule\fR, is intended to designate what to execute.
+
+The rule file is read top\-down, except for the outer most list \fBsettings\fR, which is intended to store setting data for this rule.
+Multiple outer most list Objects may be specified and they are executed as provided, in a top\-down manner.
+
+\- The \fBsettings\fR Rule Type has the following \fBFSS\-0001 (Extended)\fR Content:
+  \- \fBaffinity\fR: Define one or more processors to restrict this rule by with each number representing a specific processor by its id (starting at 0).
+  \- \fBcapability\fR: Define a set of capabilities in which to use, using the capability \fBtext\fR format (such as \fB= cap_chown+ep\fR).
+  \- \fBcgroup\fR: Define a cgroup (control group) in which everything within this rule executes under.
+  \- \fBdefine\fR: A single environment variable name and its associated value that is automatically exposed to processes executed within this rule.
+  \- \fBengine\fR: An executable name of a script, such as \fBbash\fR, to use for the \fBscript\fR Rule Type (which likely defaults to \fBbash\fR if not specified).
+  \- \fBenvironment\fR: A set of environment variables to expose to the processes executed within this rule (PATH is always exposed).
+  \- \fBgroup\fR: A set of group names or IDs to execute as with the first group being the primary group and all remaining being supplementary groups.
+  \- \fBlimit\fR: Define a resource limit to use (multiple limits may be specified, but only once for each type).
+  \- \fBname\fR: A name used to represent this rule, which is printed to the user, screen, logs, etc...
+  \- \fBnice\fR: A single niceness value to run all processes executed within this rule as (\-20 gets to be greediest in CPU usage and 19 being the nicest in CPU usage).
+  \- \fBon\fR: Define a Rule Action in which a specified dependency is needed, wanted, or wished for.
+  \- \fBparameter\fR: An IKI name and its associated value for use in this rule file.
+  \- \fBpath\fR: A single Content used to set a custom PATH environment variable value.
+  \- \fBscheduler\fR: A valid name of a scheduler to use followed by an optional priority number.
+  \- \fBtimeout\fR: A set of timeouts to wait for in which to perform a set action or to consider failure.
+  \- \fBuser\fR: A single user name or ID to execute as.
+
+\- The \fBcapability\fR setting:
+  If the user the controller program is run as does not have the desired capabilities already, they cannot be added.
+  This essentially maintains or reduces the capabilities already available.
+  Due to capabilities only being a draft in the POSIX standard, one may expect \fBcapabilities\fR support may not be available and in such a case this setting will do nothing.
+  If the dependent project (f_capability) does not have libcap support enabled, then capabilities will be unsupported by the compilation of this project.
+
+\- The \fBcontrol\fR setting:
+  The first argument is either \fBexisting\fR or \fBnew\fR, where for \fBexisting\fR the process is run inside the existing control used by the parent and when \fBnew\fR the process is executed within a new control group namespace entirely.
+
+\- The \fBdefine\fR setting:
+  Use this to define an environment variable (this overwrites any existing environment variable with this name).
+  A define is both exported as an environment variable as well as exposed as an IKI variable.
+  Example IKI variable substitution: for \fBdefine PATH /bin:/sbin\fR, the associated IKI variable would look like: PATH.
+
+  All environment variables, including those defined using this, must be in the \fBenvironment\fR list to be exported to the executed process.
+  Environment variables added here that are not added to the environment are still exposed as an IKI variable.
+
+\- The \fBengine\fR setting:
+  This engine is used for both \fBscript\fR and \fButility\fR Rule Types.
+  The program that engine refers to must accept a standard input pipe to be supported.
+  Additional parameters may be passed to the engine.
+
+\- The \fBgroup\fR and \fBuser\fR settings:
+  Only users and groups that the user the controller program is being run as is allowed to use may be used.
+
+\- The \fBlimit\fR setting:
+  The first parameter must be one of: \fBas\fR, \fBcore\fR, \fBcpu\fR, \fBdata\fR, \fBfsize\fR, \fBlocks\fR, \fBmemlock\fR, \fBmsgqueue\fR, \fBnice\fR, \fBnofile\fR, \fBnproc\fR, \fBrss\fR, \fBrtprio\fR, \fBrttime\fR, \fBsigpending\fR, or \fBstack\fR.
+  The second parameter represents the soft limit.
+  The third parameter represents the hard limit.
+  This may be specified multiply times, but only once for each type.
+
+\- The \fBon\fR setting:
+  The first parameter represents the Action the dependency exists under and must be one of: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, or \fBthaw\fR.
+  The second parameter represents how the dependency is required and must be one of: \fBneed\fR, \fBwant\fR, or \fBwish\fR.
+  The third parameter is a partial path to the rule file.
+  The fourth parameter represents the name of the rule file.
+
+  \- In the case of the second parameter:
+    \- A \fBneed\fR designates that the dependent rule is required to be executed (must exist and must succeed).
+    \- A \fBwant\fR designates that the dependent rule is to be executed (may exist and if it does, then it must succeed).
+    \- A \fBwish\fR designates that the dependent rule is to be executed (may exist and if it does, but it does not need to succeed).
+
+    In the case of \fBwant\fR and \fBwish\fR, if the desired rule is either not found or is otherwise disabled, then this will not fail or otherwise block the wanting or wishing rule.
+
+\- The \fBpath\fR setting:
+  When specified, the \fBPATH\fR environment variable is automatically added to the \fBenvironment\fR setting.
+
+\- The \fBparameter\fR setting:
+  Use this to define an IKI variable name and value.
+  These do not conflict with environment variables and are not exposed as environment variables.
+  Example IKI variable substitution: for \fBparameter hello world\fR, the associated IKI variable would look like: hello.
+
+\- The \fBscheduler\fR setting:
+  The valid range of the priority number is dependent on the scheduler.
+  For example, non\-real\-time schedulers (such as \fBidle\fR) only support a value of 0 whereas real\-time schedulers (such as \fBfifo\fR) only support an inclusive range of 1 to 99.
+  Supported non\-real\-time schedulers are: \fBbatch\fR, \fBidle\fR, and \fBother\fR (aka: normal/default).
+  Supported real\-time schedulers are: \fBdeadline\fR, \fBfifo\fR, \fBround_robin\fR.
+
+\- The \fBtimeout\fR setting:
+  (This is not currently implemented.)
+  Provides settings for each of the three special situations: \fBkill\fR, \fBstart\fR, and \fBstop\fR.
+  Each of these may only have a single one exist at a time (one \fBkill\fR, one \fBstart\fR, and one \fBstop\fR).
+  Each successive \fBtimeout\fR Item Action, specific to each Action Name (such as \fBstart\fR), specified replaces the previously defined \fBtimeout\fR Action (in a top\-down manner).
+  The second Content for each of these, when specified, may be a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+  For \fBkill\fR, this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule).
+  For \fBstart\fR, this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed.
+  For \fBstop\fR, this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed.
+  If the second Content is not specified, then this disables the type (prevents the specified timeout action).
+
+There are four available Rule Types to choose from: \fBcommand\fR, \fBservice\fR, \fBscript\fR, and \fButility\fR.
+
+The \fBcommand\fR Rule Type provides a simple command to run under the different circumstances: \fBstart\fR, \fBstop\fR, \fBrestart\fR, and \fBreload\fR.
+A \fBcommand\fR always operates in the foreground.
+
+The \fBservice\fR Rule Type provides a \fBcommand\fR accompanied with a PID file (Process Identifier file).
+
+The \fBscript\fR Rule Type provides a series of lines to be executed by some engine, such as GNU Bash.
+This \fBscript\fR operates in the foreground, but individual things done within the script may operate in foreground or background.
+The last return state is treated as an error, so be sure to finish the script with a return code of 0 to designate no error and any other whole number, such a 1, to designate an error.
+Therefore passing \fBexit 1\fR would return as an error and passing \fBexit 0\fR would return as a success.
+A \fBscript\fR is assumed to be in GNU Bash, which is the default expected behavior, but the specification does not explicitly require this.
+Another scripting language can be used but changing this incurs the responsibility to ensure all rules are updated to the appropriate scripting language.
+
+The \fButility\fR Rule Type provides a \fBscript\fR accompanied with a PID file (Process Identifier file).
+
+There are nine Rule Actions used to execute ("freeze", \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBthaw\fR):
+  When \fBrestart\fR Object's Content is not provided, then \fBstart\fR and \fBstop\fR is called when the rule is executed using the restart Action, if both \fBstart\fR and \fBstop\fR are provided.
+  When \fBreload\fR, \fBstart\fR, or \fBstop\fR Object's Content are not provided, then no respective Action is performed.
+
+  Commands are conditionally available depending on the presence of these, such as if \fBstop\fR is not provided then \fBstop\fR (and \fBrestart\fR) will not be available for the \fBcontrol\fR program(s) to use.
+
+Thee are additional Rule Actions not used to execute ("pid_file", \fBrerun\fR, and \fBwith\fR):
+  \- The \fBpid_file\fR Object's Content designates the path to the PID file created by the called program.
+
+  \- The \fBrerun\fR Object's Content designates how to re\-run a given execution Rule type.
+    \- The first Content represents the execution type, which may be one of: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, and \fBthaw\fR.
+
+    \- The second Content represents when to run this re\-run is triggered, which is either \fBsuccess\fR (return code of 0) or \fBfailure\fR (return code is not 0).
+
+    \- The third Content and more represent additional options for fine tuning how the re\-run is Performed:
+      When \fBdelay\fR, followed by a number of MegaTime (MT) (equivalent to milliseconds) in which to wait before attempting the re\-run.
+      When \fBmax\fR, followed by a positive number or the number 0 designating the maximum number of re\-runs to perform.
+      When \fBreset\fR, the \fBmax\fR re\-run counter is reset for the opposite re\-run when this re\-run is triggered, such as:
+        A \fBrerun start success reset\fR and a \fBrerun failure max 10\fR, the failure counter would reset to 0 when the \fBsuccess\fR re\-run is performed and not when the \fBfailure\fR re\-run is performed.
+
+      A \fBmax\fR of 0 designates that the re\-run will happen infinitely.
+
+  \- The \fBwith\fR Object's Content designates special flags designating very specific behavior to be applied to any single Rule Type.
+.SH SPECIFICATION
+.PP
+The Rule files follow the \fBFSS\-000D (Basic Rule)\fR format with IKI\-0000 (Unrestricted).
+
+A Rule file name is expected to have the file extension \fB.rule\fR.
+
+For each Rule file:
+  \- The outer most part is a \fBFSS\-0002 (Basic List)\fR.
+  \- The Basic List Object is considered the \fBRule Type\fR.
+  \- The Basic List Content is determined by the specific \fBRule Type\fR.
+  \- The Content for each \fBRule Type\fR is called the \fBItem\fR.
+  \- Each Item Object is the \fBItem Name\fR.
+  \- Each Item Content is either the \fBAction\fR or the \fBSetting\fR.
+  \- Each Action Object is the \fBAction Name\fR.
+  \- Each Action Content are the \fBAction Parameters\fR.
+  \- Each Setting Object is the \fBSetting Name\fR.
+  \- Each Setting Content are the \fBSetting Values\fR.
+
+The Rule Types:
+  \- \fBcommand\fR: Follows either \fBFSS\-0003 (Extended List)\fR or \fBFSS\-0001 (Extended)\fR.
+  \- \fBscript\fR: Follows either \fBFSS\-0003 (Extended List)\fR or \fBFSS\-0001 (Extended)\fR.
+  \- \fBservice\fR: Follows either \fBFSS\-0003 (Extended List)\fR or \fBFSS\-0001 (Extended)\fR.
+  \- \fBsettings\fR: Is required and follows either  \fBFSS\-0001 (Extended)\fR.
+  \- \fButility\fR: Follows either \fBFSS\-0003 (Extended List)\fR or \fBFSS\-0001 (Extended)\fR.
+
+For the above Rule Types, \fBsettings\fR may be specified only once whereas the others may be specifed multiple times.
+The \fBsettings\fR Rule Type is always processed first, regardless of position.
+The other Rule Types are processed top\-down.
+
+The \fBsettings\fR Rule Type has the following \fBFSS\-0001 (Extended)\fR:
+  \- \fBaffinity\fR: One or more Content, each must be a 0 or greater whole number.
+  \- \fBcapability\fR: One Content representing capabilities.
+  \- \fBcgroup\fR: Two or more Content, the first Content being either \fBexisting\fR or \fBnew\fR and the remaining representing a valid cgroup (control group) name, must have at least 1 graph character (non white space printing character) (leading and trailing white space are trimmed off).
+  \- \fBdefine\fR: Two Content, the first Content must be a case\-sensitive valid environment variable name (alpha\-numeric or underscore, but no leading digits).
+  \- \fBengine\fR: One or more Content representing a valid program name or path (such as \fBbash\fR or \fB/bin/bash\fR) and any optional arguments.
+  \- \fBenvironment\fR: Zero or more Content, each must be a case\-sensitive valid environment variable name (alpha\-numeric or underscore, but no leading digits).
+  \- \fBgroup\fR: One or more Content representing group names or group ids.
+  \- \fBlimit\fR: Three Content, with the first representing a valid resource type and the second and third being a valid resource limit number (positive whole number or 0).
+  \- \fBname\fR: One Content, must have at least 1 graph character (non white space printing character) (leading and trailing white space are trimmed off).
+  \- \fBnice\fR: One Content, must be a valid number for process \fBniceness\fR (Any whole number inclusively between \-20 to 19).
+  \- \fBon\fR: Four Content, the first being a Rule Action, the second being \fBneed\fR, \fBwant\fR, or \fBwish\fR, the third being a partial path, and the fourth being a Rule file name without \fB.rule\fR extension.
+  \- \fBparameter\fR: Two Content, the first Content must be a case\-sensitive valid IKI name and the second being an IKI value.
+  \- \fBpath\fR: One Content representing a valid \fBPATH\fR environment string (such as \fB/bin:/sbin:/usr/bin\fR).
+  \- \fBscheduler\fR: One or two Content representing a scheduler name and the optional numeric priority (Any whole number inclusively between 0 and 99).
+  \- \fBtimeout\fR: One or two content with the first being one of \fBexit\fR, \fBstart\fR, \fBstop\fR, or \fBkill\fR and the (optional) second Content being a positive whole number or 0.
+  \- \fBuser\fR: One Content representing a user name or user id.
+
+The \fBcommand\fR and \fBscript\fR Rule Types allow the following the \fBFSS\-0001 (Extended)\fR:
+  \- \fBfreeze\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBkill\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBpause\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBreload\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBrerun\fR: Two or more Content representing a Rule type that executes and its properties.
+  \- \fBrestart\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBresume\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBstart\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBstop\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBthaw\fR: One or more Content representing a program being executed and its arguments.
+  \- \fBwith\fR: One or more Content representing special options for the Rule Type.
+
+The \fBservice\fR and \fButility\fR Rule Types allow the following the \fBFSS\-0001 (Extended)\fR:
+  \- \fBpid_file\fR: One Content representing the path to a PID file.
+  \- \fBrerun\fR: Two or more Content representing a Rule type that executes and its properties.
+  \- \fBwith\fR: One or more Content being one of \fBfull_path\fR, \fBsession_new\fR, or \fBsession_same\fR.
+
+The \fBcommand\fR and \fBservice\fR Rule Types allow the following the \fBFSS\-0003 (Extended List)\fR:
+  \- \fBfreeze\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBkill\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBpause\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBreload\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBrestart\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBresume\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBstart\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBstop\fR: A list repesenting multiple programs and their respective arguments to execute.
+  \- \fBthaw\fR: A list repesenting multiple programs and their respective arguments to execute.
+
+The \fBscript\fR and \fButility\fR Rule Types allow the following the \fBFSS\-0003 (Extended List)\fR:
+  \- \fBfreeze\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBkill\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBpause\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBreload\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBrestart\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBresume\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBstart\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBstop\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+  \- \fBthaw\fR: A list repesenting the contents of a script, such as a GNU Bash shell.
+
+The \fBrerun\fR Rule Type Content has the following structure:
+  The first Content represents one of: \fBfreeze\fR, \fBkill\fR, \fBpause\fR, \fBreload\fR, \fBrestart\fR, \fBresume\fR, \fBstart\fR, \fBstop\fR, or \fBthaw\fR.
+  The second Content represents one of: \fBsuccess\fR or \fBfailure\fR.
+  The third and more Content represents one of: \fBdelay\fR, \fBmax\fR, or \fBreset\fR.
+  Where \fBdelay\fR and \fBmax\fR must be followed by a positive number or the number 0.
+.SH SEE ALSO
+.PP
+\fBcontrol\fR(1),
+\fBcontroller\fR(1),
+\fBcontroller\-actions\fR(5),
+\fBcontroller\-entry\fR(5),
+\fBcontroller\-exit\fR(5),
+\fBcontroller\-packet\fR(5)
+.SH AUTHOR
+Written by Kevin Day.
+.SH COPYRIGHT
+.PP
+Copyright \(co 2007-2023 Kevin Day, Open Standard License 1.0 or later.
diff --git a/documents/actions.txt b/documents/actions.txt
new file mode 100644 (file)
index 0000000..bbe70f5
--- /dev/null
@@ -0,0 +1,83 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named actions.txt) can be more easily read using the following iki_read commands:
+#   iki_read actions.txt +Q -w -W code '"' '"'
+#
+# To read the "Actions Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read actions.txt +Q -cn "Actions Documentation" | iki_read +Q -w -W code '"' '"'
+#
+
+Actions Documentation:
+  This describes the intent and purpose of the actions provided for individual Rules (or things related to a Rule).
+
+  Each Action represents a specific intent and purpose but many of these actions are customizable via the rule file.
+  One should expect an Action to operate as described here but the system administrator or distributor is fully capable of doing something different.
+  For those doing something different, appropriate documentation is suggested.
+
+  These actions should be usable by any code:"control" program that communicates with this code:"controller" program.
+  Should any code:"control" or code:"controller" program implementation not support any particular Action for any reason, one should report that the Action is unsupported.
+
+  - Freeze Action\:
+    The Freeze Action is an extension of a Control Group.
+    This is internal to the code:"controller" program and is not customizable via any Rule file.
+    For a customizable code:"freeze"-like capability, look into the Pause and Resume Actions.
+    This is the complement of the Thaw Action.
+
+    This designates that a processes Control Group is to be frozen.
+    All Rules (or any process not controlled by the code:"controller") that is within the same Control Group will be frozen.
+    (@todo consider instead designing this around the Control Groups instead of a code:"rule".)
+    (This documentation will likely change with consideration to the above @todo once this gets implemented.)
+
+    This must not attempt to freeze (or unfreeze) the Control Group that the code:"controller" belongs to.
+    Therefore, if a Rule does not specify a Control Group, then it is likely that the Freeze Action will be unsupported for that Rule/Control Group.
+
+  - Kill Action\:
+    Forcefully terminate some process controlled by the code:"controller".
+    This action cannot be blocked and it is recommended to use a Stop Action instead for a more proper termination.
+
+  - Pause Action\:
+    The Pause Action will pause (or freeze) the process controlled by the Rule.
+    Although similar to the Freeze Action, this is intended to communicate to an individual process and inform to Pause.
+    This is complemented by the Resume Action.
+
+  - Restart Action\:
+    The Restart Action will either perform a Stop Action and then a Restart Action or it will perform the Restart Action designated in some Rule file.
+    Ideally this should inform some process to perform its own restart routines.
+
+  - Resume Action\:
+    The Resume Action will unpause (or unfreeze) the process controlled by the Rule.
+    Although similar to the Thaw Action, this is intended to communicate to an individual process and inform to Resume.
+    This is complemented by the Pause Action.
+
+  - Reload Action\:
+    The Reload Action will perform the Reload Action designated in some Rule file.
+    Ideally this should inform some process to perform its own reload routines.
+    Many programs often differentiate the concept code:"reload" from the concept "restart" in that the program remains running during a code:"reload".
+
+  - Start Action\:
+    The Start Action will perform the Start Action designated in some Rule file.
+    This action should be used to start some program or script.
+    This is the action called by Entry file.
+    This is complemented by the Stop Action.
+
+  - Stop Action\:
+    The Stop Action will perform the Stop Action designated in some Rule file.
+    This action should be used to stop some program or script.
+    This is the action called for all running controlled processes on shutdown.
+    This is complemented by the Start Action.
+
+  - Thaw Action\:
+    The Thaw Action is an extension of a Control Group.
+    This is internal to the code:"controller" program and is not customizable via any Rule file.
+    For a customizable code:"thaw"-like capability, look into the code:"pause" and code:"resume" Actions.
+    This is complemented by the Freeze Action.
+
+    This designates that a processes Control Group is to be unfrozen.
+    All Rules (or any process not controlled by the code:"controller") that is within the same Control Group will be unfrozen.
+    (@todo consider instead designing this around the Control Groups instead of a code:"rule".)
+    (This documentation will likely change with consideration to the above @todo once this gets implemented.)
+
+    This must not attempt to thaw (or unthaw) the Control Group that the code:"controller" belongs to.
+    Therefore, if a Rule does not specify a Control Group, then it is likely that the Thaw Action will be unsupported for that Rule/Control Group.
diff --git a/documents/entry.txt b/documents/entry.txt
new file mode 100644 (file)
index 0000000..394fd95
--- /dev/null
@@ -0,0 +1,233 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named entry.txt) can be more easily read using the following iki_read commands:
+#   iki_read entry.txt +Q -r PID PID -w -WW code '"' '"'
+#
+# To read the "Entry Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read entry.txt +Q -cn "Entry Documentation" | iki_read +Q -r PID PID -w -W code '"' '"'
+#
+
+Entry Documentation:
+  This describes the intent and purpose of an Entry file.
+
+  An Entry file, such as code:"default.entry", is intended to store a set of rules in which the controller will process on execution.
+  These are used to run some set of commands, such as booting a system.
+
+  The code:"main" Item Object is always executed first (Therefore code:"main" is both reserved and required).
+  All other Basic List Objects are not executed unless either an code:"item" or a code:"failsafe" specifies a valid Item name.
+  Execution of all Items is top-down.
+
+  - The code:"settings" item Object\:
+    Represents Entry settings and is not an code:"item" that can be executed.
+    A number of settings are supported, but if this Item Object is not specified, then defaults are used.
+    The following settings are available: code:"control", code:"control_group", code:"control_mode", code:"control_user", code:"define", code:"mode", code:"parameter", code:"pid", code:"pid_file", code:"session", code:"show".
+
+    - The code:"control" setting\:
+      Represents the path to the socket file in which the Controller uses to communicate over with clients such as a Control program.
+      A relative path is relative to the Controller PID:"Process Identifier" directory.
+      An absolute path is treated exactly as the path given.
+      If no socket setting is specified, then no socket will be made available.
+      This socket file is only created once code:"ready" mode is achieved.
+
+      Providing code:"readonly" after the socket path instructs the Controller program not to create or delete the Socket file because the file system is assumed to be readonly.
+      The socket file itself must therefore already exist.
+      This should be possible in the cases of file systems that have pre-created a socket file at the designated path.
+      When code:"readonly", the group, mode, and user are also not processed effectively resulting in the code:"control_group", code:"control_mode", and code:"control_user" settings being ignored.
+
+      Future versions might expand this into supporting network addresses in addition to socket files.
+
+    - The code:"control_group" setting\:
+      Represents the group name or group ID to assign to the socket file as the group.
+
+    - The code:"control_mode" setting\:
+      Represents the file mode assigned to the socket file.
+      This could either be the string version that might look like code:"u+rw-x,g+r-wx,o-rwx" or a numeric value like code:"0750".
+
+    - The code:"control_user" setting\:
+      Represents the user name or user ID to assign to the socket file as the owner.
+
+    - The code:"define" setting\:
+      Use this to define an environment variable (this overwrites any existing environment variable with this name).
+      A define is both exported as an environment variable as well as exposed as an IKI variable.
+      Example IKI variable substitution: for code:"define PATH /bin:/sbin", the associated IKI variable would look like: define:"PATH".
+
+      All environment variables, including those defined using this, must be in the code:"environment" list in any given Rule to be exported to the executed process.
+      Environment variables added here that are not added to the environment are still exposed as an IKI variable.
+
+      This is only expanded within any Rule operated on by this Entry.
+
+    - The code:"mode" setting\:
+      Represents the mode in which the Entry is operating in.
+      The following modes are supported: code:"helper", code:"program", and code:"service".
+
+      - The code:"helper" mode\:
+        Designates that the Entry operates as a helper for starting programs or performing actions and exits when complete.
+        On exit, any background (asynchronous) processes are not cancelled.
+        If terminated, the foreground (synchronous) process is cancelled.
+        Will call the code:"exit" with the same name as this Entry, but with the extension code:"exit", such as code:"default.exit".
+        Supports the Item Action code:"execute" to execute a program (switching the code:"controller" program entirely with the executed process).
+
+      - The code:"program" mode\:
+        Designates that the Entry operates as a program and exits when complete.
+        On exit, any background (asynchronous) processes are also cancelled.
+        If terminated, the foreground (synchronous) process is cancelled.
+        Will call the code:"exit" with the same name as this Entry, but with the extension code:"exit", such as code:"default.exit".
+        Supports the Item Action code:"execute" to execute a program (switching the code:"controller" program entirely with the executed process).
+
+      - The code:"service" mode\:
+        Designates that the Entry operates as a service and will sit and wait for control commands when complete.
+        Will call the code:"exit" with the same name as this Entry, but with the extension code:"exit", such as code:"default.exit".
+        Does not support the Item Action code:"execute".
+        This is the default mode.
+
+    - The code:"parameter" setting\:
+      Use this to define an IKI variable name and value.
+      These do not conflict with environment variables and are not exposed as environment variables.
+      Example IKI variable substitution: for code:"parameter hello world", the associated IKI variable would look like: parameter:"hello".
+
+      This is only expanded within any Rule operated on by this Entry.
+
+    - The code:"pid" setting\:
+      Represents how the Entry PID:"Process Identifier" file is generated or not.
+      The following modes are supported: code:"disable", code:"require", and code:"ready".
+      For code:"disable", not PID:"Process Identifier" file representing the Entry is created.
+      For code:"require", check to see if the PID:"Process Identifier" file exists for an Entry at startup and then when code:"ready" create a PID:"Process Identifier" file, display error on PID:"Process Identifier" file already exists or on failure and then fail.
+      For code:"ready", when code:"ready" create a PID:"Process Identifier" file, display error on failure and then fail (does not check if PID:"Process Identifier" file exists).
+
+    - The code:"pid_file" setting\:
+      When code:"pid" is not disabled this represents the path to the PID:"Process Identifier" file.
+      If code:"-p" or code:"--pid" is passed to the controller program, then this value is ignored in favor of the value passed along the command line.
+
+    - The code:"session" setting\:
+      Represents the default way in which child processes are executed.
+      This default can be overridden by individual Rules.
+      For code:"new", Execute Rule processes in a new session setting the process group to the executed process' id (making the executed process a code:"controlling terminal").
+      For code:"same", Execute Rule processes in the same session where the process group is set to the parent process id.
+
+    - The code:"show" setting\:
+      Represents the way Entry processing presents information to the screen.
+      This applies only to the Entry and Rule processing itself and does not handle the output of programs and scripts being executed by some Entry or Rule.
+      The following show options are supported: code:"normal" and code:"init".
+      For code:"normal", will not report the start or stop of some Entry or Rule execution but will report any errors or warnings as appropriate.
+      For code:"init", will report when starting programs and may include reporting success and failure status.
+
+    - The code:"timeout" setting\:
+      Represents the default timeouts for the Entry.
+      See the code:"timeout" Action below for details.
+
+  - The code:"main" item Object\:
+    Each code:"item" supports the following Action Names: code:"consider", code:"execute", code:"failsafe", code:"freeze", code:"item", code:"kill", code:"pause", code:"reload", code:"restart", code:"ready", code:"resume", code:"start", code:"stop", and code:"timeout".
+    Of those types, the following are considered a code:"rule" Action: code:"freeze", code:"kill", code:"pause", code:"reload", code:"restart", code:"resume", code:"start", code:"stop", and code:"thaw".
+
+    - The code:"consider" Item Action\:
+      A special case of a code:"rule" Action.
+      All Action Parameters are the same as with the code:"rule" Action Parameters.
+      The difference is that code:"consider" is only processed (instead of being processed and executed) and when some code:"rule" Action designates that this consideration is required (via code:"need"), wanted (via code:"want"), or wished for (via code:"wish") from the within the Rule file.
+      If this is determined to be executed, then this is immediately executed when needed, wanted or wished for and applies all properties as appropriate (such as code:"asynchronous", for example).
+      If this is determined not to be executed, then this code:"consider" is ignored as if it was never there in the first place.
+
+    - The code:"execute" Item Action\:
+      Execute into the specified program.
+      On successful execution, the controller program will no longer be running and will be replaced with the designated program.
+      This Item Action is only supported when operating in code:"program" mode.
+
+    - The code:"failsafe" Item Action\:
+      Accepts only a valid Item Name in which will be executed when a failure is detected.
+      Only a single code:"failsafe" Item Action may function at a time.
+      Each successive code:"failsafe" Item Action specified replaces the previously defined code:"failsafe" Item Action (in a top-down manner).
+      When operating in code:"failsafe", the code:"require" Item Action is ignored (given that it is meaningless once operating in code:"failsafe" mode).
+
+    - The code:"freeze" Item Action\:
+      A code:"rule" Action for freezing some Control Group.
+      This Item Action will process the code:"freeze" inner Content of the named Rule.
+      This is specific to Control Groups and is not yet fully implemented.
+      Once implemented this documentation will need to be updated and clarified.
+
+    - The code:"item" Item Action\:
+      Accepts only a valid Item Name in which will be immediately executed.
+      Any valid Item Name, except for the reserved code:"main", may be used.
+
+    - The code:"kill" Item Action\:
+      A code:"rule" Action for forcibly terminating some process.
+      This Item Action will process the code:"kill" inner Content of the named Rule.
+
+    - The code:"pause" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"pause" inner Content of the named Rule.
+
+    - The code:"reload" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"reload" inner Content of the named Rule.
+
+    - The code:"restart" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"restart" inner Content of the named Rule.
+
+    - The code:"resume" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"resume" inner Content of the named Rule.
+
+    - The code:"ready" Item Action\:
+      Instructs the controller program when it is safe to perform normal tasks, such as creating the PID:"Process Identifier" file.
+      When not specified, the state is always assumed to be ready.
+      For example, the controller program may be used as a full blown code:"init" replacement and therefore may need to mount the /var/run/ directory.
+      If the PID:"Process Identifier" file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready.
+      This could be a problem, such as on a read-only file system the PID:"Process Identifier" creation fails and controller bails out on error.
+      Adding code:"ready" essentially specifies a point in time in the Entry in which things are expected to be safe for such basic operations.
+      When the optional code:"wait" is provided, then code:"ready" will wait for all currently started asynchronous processes to complete before operating.
+
+    - The code:"start" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"start" inner Content of the named Rule.
+
+    - The code:"stop" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"stop" inner Content of the named Rule.
+
+    - The code:"thaw" Item Action\:
+      A code:"rule" Action for unfreezing some Control Group.
+      This Item Action will process the code:"thaw" inner Content of the named Rule.
+      This is specific to Control Groups and is not yet fully implemented.
+      Once implemented this documentation will need to be updated and clarified.
+
+    - The code:"timeout" Item Action\:
+      (This is not currently fully implemented, only code:"exit" is implemented.)
+      Provides default global settings for each of the four special situations: code:"exit", code:"kill", code:"start", and code:"stop".
+      Each of these may only have a single one exist at a time (one code:"exit", one code:"kill", one code:"start", and one code:"stop").
+      Each successive code:"timeout" Item Action, specific to each Action Name (such as code:"start"), specified replaces the previously defined code:"timeout" Action (in a top-down manner).
+      The second Content for each of these, when specified, may be a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+      For code:"kill", this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule).
+      For code:"start", this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed.
+      For code:"stop", this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed.
+      If the second Content is not specified, then this disables the type (prevents the specified timeout action).
+      For code:"exit", this represents the number of MegaTime to wait when the Controller program is exiting (such as having received a terminate signal).
+      In this case, a terminate signal is sent to all child processes.
+      The code:"exit" timeout represents the amount of time to wait after sending the terminate signal before sending a kill signal to each child process still running.
+      When disabled, the program will not send a kill signal will continue running until all child processes to terminate.
+      The code:"exit" timeout does not get applied to any Rule.
+
+Entry Rule Documentation:
+  There are multiple Entry Actions that are considered code:"rule" Actions.
+  These are: code:"freeze", code:"kill", code:"pause", code:"reload", code:"restart", code:"resume", code:"start", code:"stop", and code:"thaw".
+
+  The code:"rule" Actions immediately execute a named Rule file.
+    - The first Action Parameter represents the Rule directory, which is a relative directory path the Rule file is to be found.
+      - Do not include leading or trailing slashes.
+      - This is relative to the settings rules directory.
+
+    - The second Action Parameter represents the base name for the Rule file, without the file extension.
+      - This must not have any directory paths.
+
+    - The remaining Action Parameters may be specified in any order\:
+      - code:"asynchronous": Designates that execution will not block (wait).
+      - code:"require": Designates that this Rule must succeed or trigger execution of failsafe.
+      - code:"wait": Designates that this Rule will not execute until all other Actions before this (including code:"asynchronous" ones) finish executing (in a top-down manner).
+
+  The full path to the code:"rule" is relative to the settings, such that if the controller Rule settings are found in code:"/etc/controller/rules/", then for a directory called code:"[directory]" and a Rule base name of code:"[base_name]", the resulting path would be: code:"/etc/controller/rules/[directory]/[base_name].rule".
+
+  It is important to note that for any given code:"rule", execution within that code:"rule" may be internally asynchronous (even if the code:"rule" is synchronous).
+  For example, a service that is often called a daemon will execute in the background.
+  Until that execution succeeds and the daemon goes into the background the representing Rule will block.
+  After the daemon goes into the background, then the representing Rule will no longer block and be fully executed.
diff --git a/documents/exit.txt b/documents/exit.txt
new file mode 100644 (file)
index 0000000..bfa4372
--- /dev/null
@@ -0,0 +1,178 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named exit.txt) can be more easily read using the following iki_read commands:
+#   iki_read exit.txt +Q -w -r PID PID -w -W code '"' '"'
+#
+# To read the "Exit Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read exit.txt +Q -cn "Exit Documentation" | iki_read +Q -r PID PID -w -W code '"' '"'
+#
+
+Exit Documentation:
+  This describes the intent and purpose of an Exit file.
+
+  An Exit file, such as code:"default.exit", is intended to store a set of rules in which the controller will process on execution.
+  These are used to run some set of commands, such as shutting down a system.
+
+  An Exit is a special variation or subset of an Entry.
+
+  - The code:"settings" Item Object\:
+    Represents Exit settings and is not an code:"item" that can be executed.
+    A number of settings are supported, but if this Item Object is not specified, then defaults are used.
+    The following settings are available: code:"pid" and code:"show".
+
+    - The code:"define" setting\:
+      Use this to define an environment variable (this overwrites any existing environment variable with this name).
+      A define is both exported as an environment variable as well as exposed as an IKI variable.
+      Example IKI variable substitution: for code:"define PATH /bin:/sbin", the associated IKI variable would look like: define:"PATH".
+
+      All environment variables, including those defined using this, must be in the code:"environment" list in any given Rule to be exported to the executed process.
+      Environment variables added here that are not added to the environment are still exposed as an IKI variable.
+
+      This is only expanded within any Rule operated on by this Exit.
+
+    - The code:"parameter" setting\:
+      Use this to define an IKI variable name and value.
+      These do not conflict with environment variables and are not exposed as environment variables.
+      Example IKI variable substitution: for code:"parameter hello world", the associated IKI variable would look like: parameter:"hello".
+
+      This is only expanded within any Rule operated on by this Exit.
+
+    - The code:"pid" setting\:
+      Represents how the Exit PID:"Process Identifier" file is generated or not.
+      The following modes are supported: code:"disable", code:"require", and code:"ready".
+      For code:"disable", not PID:"Process Identifier" file representing the Exit is created.
+      For code:"require", check to see if the PID:"Process Identifier" file exists for an Exit at startup and then when code:"ready" create a PID:"Process Identifier" file, display error on PID:"Process Identifier" file already exists or on failure and then fail.
+      For code:"ready", when code:"ready" create a PID:"Process Identifier" file, display error on failure and then fail (does not check if PID:"Process Identifier" file exists).
+
+    - The code:"show" setting\:
+      Represents the way Exit processing presents information to the screen.
+      This applies only to the Exit and Rule processing itself and does not handle the output of programs and scripts being executed by some Exit or Rule.
+      The following show options are supported: code:"normal" and code:"init".
+      For code:"normal", will not report the start or stop of some Exit or Rule execution but will report any errors or warnings as appropriate.
+      For code:"init", will report when starting programs and may include reporting success and failure status.
+
+    - The code:"timeout" setting\:
+      Represents the default timeouts for the Exit.
+      See the code:"timeout" Action below for details.
+
+  - The code:"main" Item Object\:
+    Is always executed first (Therefore code:"main" is both reserved and required).
+    All other Basic List Objects are not executed unless either an code:"item" or a code:"failsafe" specifies a valid Item name.
+    Execution of all Items are top-down.
+
+    Each code:"item" supports the following Action Names: code:"consider", code:"execute", code:"failsafe", code:"freeze", code:"item", code:"kill", code:"pause", code:"reload", code:"restart", code:"ready", code:"resume", code:"start", code:"stop", and code:"timeout".
+    Of those types, the following are considered a code:"rule" Action: code:"freeze", code:"kill", code:"pause", code:"reload", code:"restart", code:"resume", code:"start", code:"stop", and code:"thaw".
+
+    - The code:"consider" Item Action\:
+      A special case of a code:"rule" Action.
+      All Action Parameters are the same as with the code:"rule" Action Parameters.
+      The difference is that code:"consider" is only processed (instead of being processed and executed) and when some code:"rule" Action designates that this consideration is required (via code:"need"), wanted (via code:"want"), or wished for (via code:"wish") from the within the Rule file.
+      If this is determined to be executed, then this is immediately executed when needed, wanted or wished for and applies all properties as appropriate (such as code:"asynchronous", for example).
+      If this is determined not to be executed, then this code:"consider" is ignored as if it was never there in the first place.
+
+    - The code:"execute" Item Action\:
+      Execute into the specified program.
+      On successful execution, the controller program will no longer be running and will be replaced with the designated program.
+      This Item Action is only supported when operating in code:"program" mode.
+
+    - The code:"failsafe" Item Action\:
+      Accepts only a valid Item Name in which will be executed when a failure is detected.
+      Only a single code:"failsafe" Item Action may function at a time.
+      Each successive code:"failsafe" Item Action specified replaces the previously defined code:"failsafe" Item Action (in a top-down manner).
+      When operating in code:"failsafe", the code:"require" Item Action is ignored (given that it is meaningless once operating in code:"failsafe" mode).
+
+    - The code:"freeze" Item Action\:
+      A code:"rule" Action for freezing some Control Group.
+      This Item Action will process the code:"freeze" inner Content of the named Rule.
+      This is specific to Control Groups and is not yet fully implemented.
+      Once implemented this documentation will need to be updated and clarified.
+
+    - The code:"item" Item Action\:
+      Accepts only a valid Item Name in which will be immediately executed.
+      Any valid Item Name, except for the reserved code:"main", may be used.
+
+    - The code:"kill" Item Action\:
+      A code:"rule" Action for forcibly terminating some process.
+      This Item Action will process the code:"kill" inner Content of the named Rule.
+
+    - The code:"pause" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"pause" inner Content of the named Rule.
+
+    - The code:"reload" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"reload" inner Content of the named Rule.
+
+    - The code:"restart" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"restart" inner Content of the named Rule.
+
+    - The code:"resume" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"resume" inner Content of the named Rule.
+
+    - The code:"ready" Action\:
+      Instructs the controller program when it is safe to perform normal tasks, such as creating the PID:"Process Identifier" file.
+      When not specified, the state is always assumed to be ready.
+      For example, the controller program may be used as a full blown code:"init" replacement and therefore may need to mount the /var/run/ directory.
+      If the PID:"Process Identifier" file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready.
+      This could be a problem, such as on a read-only file system the PID:"Process Identifier" creation fails and controller bails out on error.
+      Adding code:"ready" essentially specifies a point in time in the Exit in which things are expected to be safe for such basic operations.
+      When the optional code:"wait" is provided, then code:"ready" will wait for all currently started asynchronous processes to complete before operating.
+
+    - The code:"start" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"start" inner Content of the named Rule.
+
+    - The code:"stop" Item Action\:
+      A code:"rule" Action for pausing some process.
+      This Item Action will process the code:"stop" inner Content of the named Rule.
+
+    - The code:"thaw" Item Action\:
+      A code:"rule" Action for unfreezing some Control Group.
+      This Item Action will process the code:"thaw" inner Content of the named Rule.
+      This is specific to Control Groups and is not yet fully implemented.
+      Once implemented this documentation will need to be updated and clarified.
+
+    - The code:"timeout" Item Action\:
+      (This is not currently fully implemented, only code:"exit" is implemented.)
+      Provides default global settings for each of the four special situations: code:"exit", code:"kill", code:"start", and code:"stop".
+      Each of these may only have a single one exist at a time (one code:"exit", one code:"kill", one code:"start", and one code:"stop").
+      Each successive code:"timeout" Item Action, specific to each Action Name (such as code:"start"), specified replaces the previously defined code:"timeout" Action (in a top-down manner).
+      The second Content for each of these, when specified, may be a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+      For code:"kill", this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule).
+      For code:"start", this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed.
+      For code:"stop", this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed.
+      If the second Content is not specified, then this disables the type (prevents the specified timeout action).
+
+      For code:"exit", this represents the number of MegaTime to wait when the Controller program is exiting (such as having received a terminate signal).
+      In this case, a terminate signal is sent to all child processes.
+      The code:"exit" timeout represents the amount of time to wait after sending the terminate signal before sending a kill signal to each child process still running.
+      When disabled, the program will not send a kill signal will continue running until all child processes to terminate.
+      The code:"exit" timeout does not get applied to any Rule.
+
+Exit Rule Documentation:
+  There are multiple Exit Actions that are considered code:"rule" Actions.
+  These are: code:"freeze", code:"kill", code:"pause", code:"reload", code:"restart", code:"resume", code:"start", code:"stop", and code:"thaw".
+
+  The code:"rule" Actions immediately execute a named Rule file.
+    - The first Action Parameter represents the Rule directory, which is a relative directory path the Rule file is to be found.
+      - Do not include leading or trailing slashes.
+      - This is relative to the settings rules directory.
+
+    - The second Action Parameter represents the base name for the Rule file, without the file extension.
+      - This must not have any directory paths.
+
+    - The remaining Action Parameters may be specified in any order\:
+      - code:"asynchronous": Designates that execution will not block (wait).
+      - code:"require": Designates that this Rule must succeed or trigger execution of failsafe.
+      - code:"wait": Designates that this Rule will not execute until all other Actions before this (including code:"asynchronous" ones) finish executing (in a top-down manner).
+
+  The full path to the code:"rule" is relative to the settings, such that if the controller Rule settings are found in code:"/etc/controller/rules/", then for a directory called code:"[directory]" and a Rule base name of code:"[base_name]", the resulting path would be: code:"/etc/controller/rules/[directory]/[base_name].rule"
+
+  It is important to note that for any given code:"rule", execution within that code:"rule" may be internally asynchronous (even if the code:"rule" is synchronous).
+  For example, a service that is often called a daemon will execute in the background.
+  Until that execution succeeds and the daemon goes into the background the representing Rule will block.
+  After the daemon goes into the background, then the representing Rule will no longer block and be fully executed.
diff --git a/documents/packet.txt b/documents/packet.txt
new file mode 100644 (file)
index 0000000..3a0038d
--- /dev/null
@@ -0,0 +1,81 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named packet.txt) can be more easily read using the following iki_read commands:
+#   iki_read packet.txt +Q -w -W code '"' '"'
+#
+# To read the "Packet Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read packet.txt +Q -cn "Packet Documentation" | iki_read +Q -w -W code '"' '"'
+#
+
+Packet Documentation:
+  Describes how a packet is designed and intended to be used.
+
+  The code:"packet" is the general category in which multiple types of packets belong.
+  This describes the different packets based on their code:"type".
+
+  Each packet begins with a control block and a size block followed by a payload block.
+
+    The control block\:
+      The leading bit (starting from the left) designates the the format of the payload, which is 0 for string and 1 for binary.
+      The second bit (starting from the left) designates the the byte order for the rest of the packet, which 0 is for little endian and 1 is for big endian.
+      The remaining 6-bits are reserved for future use.
+
+    The size block\:
+      The size block represents the size of the entire packet (the control block, the size blocks, and the payload block).
+      This number is a single 32-bit unsigned integer.
+
+      Example packet structure\:
+      block:"
+        [ Control Block ] [ Size Block                                  ] [ Payload Block         ]
+        [ 0b10000000    ] [ 0b00000000 0b00000000 0b00000100 0b11010010 ] [ size: 1229 (1234 - 5) ]
+      "
+
+    The payload block\:
+      This block is represented by the code:"FSS-000E (Payload)" specification and its structure ad use is described in the next sections.
+
+      The following types of payload are received or sent\:
+      1) controller payload.
+      2) error payload.
+      3) init payload.
+
+  The controller payload\:
+    Commands being sent to the controller and their respective responses utilize a code:"controller" payload.
+    These are pre-defined commands to rules or the controller program itself.
+    Commands such as starting or stopping some rule, for example.
+    A controller payload is also sent in response to a controller payload request to represent a success.
+
+      The code:"now" condition designates that the kexec, reboot, or shutdown is to begin immediately.
+      The code:"at" condition designates that the kexec, reboot, or shutdown is to begin once a specific date and time is reached by the system clock.
+      The code:"in" condition designates that the kexec, reboot, or shutdown is to begin once a specific amount of time is passed by the system clock since the execution of this command started.
+
+    For these code:"time" conditions, different units of time should be supported, such as code:"seconds", code:"days", code:"years" as standard time, Time, or UNIX Time (Epoch Time).
+
+    The normal code:"controller" payload commands are any valid Rule Action that performs some action.
+    This does not include Actions that provide some setting or configuration (such as code:"with_pid").
+    Some of the supported commands are: code:"freeze", code:"kill", code:"pause", code:"reload", code:"rerun", code:"restart", code:"resume", code:"start", code:"stop", or code:"thaw".
+    Multiple commands may be sent multiple code:"action" headers.
+    The code:"action" headers are order sensitive, executing from top to bottom, and one does not start until the previous successfully completes.
+
+    Multiple code:"status" headers may exist in the response so long as they each match an code:"action" in the request.
+
+    The code:"payload" is expected to be empty and have a length of 0 for a request.
+    The code:"payload" may have an code:"FSS-0000 (Basic)" format containing a single Object code:"message" to represent a message associated with an action.
+    Multiple code:"message" may exist in the response so long as they each match an code:"action" in the request.
+
+  The error payload\:
+    The error payload is intended to communicate some sort of failure.
+    The error payload is only sent in response to some request (and not in response to another response).
+    The control (the client) is not expected to send error payloads and the controller (the service) should send an error in response to an error payload or ignore it entirely.
+    The code:"status" from the code:"header" designates the status code as either a status code name string or a status code number (where a number may have error and warning bits).
+    The code:"payload" will contain a NULL terminated string representing the message used to describe the error.
+
+  The init payload\:
+    The init payload is intended exclusively for the code:"init" operation mode and is expected to only be available when running as code:"init".
+    This is used to provide special actions, namely code:"kexec", code:"reboot", and code:"shutdown".
+
+    The code:"kexec" is for booting into another kernel, which may effectively be the same as a code:"reboot" ("kexec" is currently neither supported nor implemented).
+    The code:"reboot" is for rebooting the machine (currently not implemented).
+    The code:"shutdown" is for shutting down the machine (currently not implemented).
+    These three commands are configurable to fire off based on conditions.
diff --git a/documents/readme.bootstrap.txt b/documents/readme.bootstrap.txt
new file mode 100644 (file)
index 0000000..d437c7d
--- /dev/null
@@ -0,0 +1,137 @@
+# fss-0002 iki-0000
+#
+# license: cc-by-sa-4.0
+#
+# This file (assumed to be named readme.bootstrap.txt) can be more easily read using the following iki_read commands:
+#   iki_read readme.bootstrap.txt +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"'
+#
+# To read the "Bootstrap Readme Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read readme.bootstrap.txt +Q -cn "Bootstrap Readme Documentation" | iki_read +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"'
+#
+
+Bootstrap Readme Documentation:
+  The FLL:"Featureless Linux Library" provides a special bootstrap script in case the bold:"Featureless Make" is not currently installed.
+
+  The bold:"GNU Bash" scripts, called file:"bootstrap.sh" and file:"install.sh", are provided to perform this bootstrap process.
+
+  The syntax for file:"bootstrap.sh" is\:
+    code:"bootstrap.sh <operation> [options]"
+    - where operation is one of the following: code:"build" or code:"clean".
+    - No code:"install" command is provided, all of the files to install may be found in the file:"build/" directory after the build command is executed.
+    - To install, either copy the files in the build directory to their appropriate destination or use the file:"install.sh" bold:"GNU Bash" script.
+    - For all operations and options, get help from the bootstrap script by appending the code:"--help" to the script, such as: code:"./bootstrap.sh --help".
+    - The monolithic build process is the simplest, which can be generated like the following: code:"./bootstrap.sh build -m monolithic".
+    - When during development, consider using a work directory, such as: code:"./bootstrap.sh --work /tmp/work".
+
+  The syntax for file:"install.sh" is\:
+    code:"install.sh [options]"
+    - This defaults to code:"/usr/local/" paths commonly found in bold:"GNU Linux" systems.
+    - Accepts options for specifying specific install directory paths, such as a custom bin directory: code:"./install.sh --bindir /custom/program".
+    - This is a simple installer and is not intended to be an all-solution.
+    - For more powerful installation: manually install, use custom scripts, or use an appropriate build/install system.
+    - When during development, consider using a work directory, such as: code:"./install.sh --work /tmp/work".
+    - The code:"--work" parameter in file:"install.sh" is similar to the code:"--prefix" parameter, except that it is used for easier development scripting and also for communicating intent and has a different directory structure.
+    - The bold:"Featureless Make" is a build system only and not an install system, the file:"install.sh" script may still be needed to install when using the bold:"Featureless Make".
+
+  Build Example\:
+    code:"./bootstrap.sh build"
+
+  Install Example\:
+    code:"./install.sh"
+
+  Manual Install Example\:
+    code:"cp -vR build/includes/* /usr/include/"
+    code:"cp -vR build/libaries/shared/* /usr/lib/"
+    code:"cp -vR build/programs/shared/* /usr/bin/"
+    code:"cp -vR build/settings/* /etc/"
+
+  If one of the build sub-directories, such as includes, libraries, programs, and settings, is empty or missing after a successful build, then there are no files of that type to install.
+
+  Build Tree Structure Example (using the FLL:"Featureless Linux Library" code:"status_code-0.7.0" project)\:
+    block:"
+      build/
+      â”œâ”€â”€ documents
+      â”œâ”€â”€ includes
+      â”‚   â””── program
+      â”‚       â””── status_code
+      â”‚           â”œâ”€â”€ fss
+      â”‚           â”‚   â”œâ”€â”€ common.h
+      â”‚           â”‚   â””── status_code.h
+      â”‚           â””── main
+      â”‚               â”œâ”€â”€ common.h
+      â”‚               â”œâ”€â”€ common-print.h
+      â”‚               â”œâ”€â”€ print.h
+      â”‚               â””── status_code.h
+      â”œâ”€â”€ libraries
+      â”‚   â”œâ”€â”€ script
+      â”‚   â”œâ”€â”€ shared
+      â”‚   â”‚   â”œâ”€â”€ libstatus_code.so -> libstatus_code.so.0
+      â”‚   â”‚   â”œâ”€â”€ libstatus_code.so.0 -> libstatus_code.so.0.7
+      â”‚   â”‚   â”œâ”€â”€ libstatus_code.so.0.7 -> libstatus_code.so.0.7.0
+      â”‚   â”‚   â””── libstatus_code.so.0.7.0
+      â”‚   â””── static
+      â”‚       â””── libstatus_code.a
+      â”œâ”€â”€ objects
+      â”‚   â”œâ”€â”€ config.o
+      â”‚   â”œâ”€â”€ fss
+      â”‚   â”‚   â”œâ”€â”€ common.o
+      â”‚   â”‚   â””── status_code.o
+      â”‚   â”œâ”€â”€ main
+      â”‚   â”‚   â”œâ”€â”€ common.o
+      â”‚   â”‚   â”œâ”€â”€ common-print.o
+      â”‚   â”‚   â”œâ”€â”€ print.o
+      â”‚   â”‚   â”œâ”€â”€ private-status_code.o
+      â”‚   â”‚   â””── status_code.o
+      â”‚   â”œâ”€â”€ script
+      â”‚   â”œâ”€â”€ shared
+      â”‚   â””── static
+      â”œâ”€â”€ programs
+      â”‚   â”œâ”€â”€ script
+      â”‚   â”œâ”€â”€ shared
+      â”‚   â”‚   â”œâ”€â”€ fss_status_code
+      â”‚   â”‚   â””── status_code
+      â”‚   â””── static
+      â”‚       â”œâ”€â”€ fss_status_code
+      â”‚       â””── status_code
+      â”œâ”€â”€ settings
+      â””── stage
+          â”œâ”€â”€ library_shared-settings.built
+          â”œâ”€â”€ library_static-settings.built
+          â”œâ”€â”€ objects_static-settings.built
+          â”œâ”€â”€ program_shared-settings.fss.built
+          â”œâ”€â”€ program_shared-settings.main.built
+          â”œâ”€â”€ skeleton-settings.built
+          â”œâ”€â”€ skeleton-settings.fss.built
+          â”œâ”€â”€ skeleton-settings.main.built
+          â”œâ”€â”€ sources_headers-settings.built
+          â”œâ”€â”€ sources_script-settings.built
+          â”œâ”€â”€ sources_script-settings.fss.built
+          â”œâ”€â”€ sources_script-settings.main.built
+          â”œâ”€â”€ sources_settings-settings.built
+          â”œâ”€â”€ sources_settings-settings.fss.built
+          â””── sources_settings-settings.main.built
+    "
+
+  Work Tree Sructure Example at file:"/tmp/work" (using the FLL:"Featureless Linux Library" code:"status_code-0.7.0" project)\:
+    block:"
+      /tmp/work/
+      â”œâ”€â”€ includes
+      â”‚   â””── program
+      â”‚       â””── status_code
+      â”‚           â”œâ”€â”€ fss
+      â”‚           â”‚   â”œâ”€â”€ common.h
+      â”‚           â”‚   â””── status_code.h
+      â”‚           â””── main
+      â”‚               â”œâ”€â”€ common.h
+      â”‚               â”œâ”€â”€ common-print.h
+      â”‚               â”œâ”€â”€ print.h
+      â”‚               â””── status_code.h
+      â””── libraries
+          â”œâ”€â”€ shared
+          â”‚   â”œâ”€â”€ libstatus_code.so -> libstatus_code.so.0
+          â”‚   â”œâ”€â”€ libstatus_code.so.0 -> libstatus_code.so.0.7
+          â”‚   â”œâ”€â”€ libstatus_code.so.0.7 -> libstatus_code.so.0.7.0
+          â”‚   â””── libstatus_code.so.0.7.0
+          â””── static
+              â””── libstatus_code.a
+    "
diff --git a/documents/readme.build.txt b/documents/readme.build.txt
new file mode 100644 (file)
index 0000000..a58d596
--- /dev/null
@@ -0,0 +1,109 @@
+# fss-0002 iki-0000
+#
+# license: cc-by-sa-4.0
+#
+# This file (assumed to be named readme.build.txt) can be more easily read using the following iki_read commands:
+#   iki_read readme.build.txt +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"'
+#
+# To read the "Build Readme Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read readme.build.txt +Q -cn "Build Readme Documentation" | iki_read +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"'
+#
+
+Build Readme Documentation:
+  The bold:"Featureless Make", or code:"fake", is a build system opposing the bold:"GNU Make" build (and install) system.
+
+  The bold:"GNU Make" system is powerful, but introduces too much unecessary functionality.
+  In opposition to parts of how bold:"GNU Make" works but also in honor of the success of the bold:"GNU Make" system, the bold:"Featureless Make" system follows the following concepts\:
+  - A build system is just that, a build system. Do not attempt to install, leave that to the distributor or individual installer.
+  - A build system should not be trying to guess what is or is not on the system, instead, allow the distributor or individual installer to just specify what they want.
+  - Provide a simple configuration design by using the bold:"Featureless Settings Specification".
+  - Provide advanced functionality to provide flexibility with different system designs.
+  - Userspace execution calling is expensive, attempt to avoid such overhead by providing built-in functionality where reasonably possible.
+  - There should never need to be a code:"configure" script, like bold:"GNU Autoconf".
+
+  The code:"fake" is designed to specifically build the FLL:"Featureless Linux Library" and encourages the use of code:"fake" to build FLL:"Featureless Linux Library".
+
+  The code:"fake" provides two main build operations\:
+  - code:"build": a lean purely FSS:"Featureless Settings Specification" based build process, designed around specific but simple project designs (explicitly used by FLL:"Featureless Linux Library").
+  - code:"make": a more powerful build process design to be more akin to bold:"GNU Make".
+
+  The code:"fake" supports custom development environments using the file:"work" directory concept, such as code:"fake build -w /tmp/work".
+  The file:"work" directory structure is identical to the build directory structure.
+
+  Build Example, Using code:"build"\:
+    code:"fake build"
+
+  Build Example, Using code:"make"\:
+    code:"fake"
+
+  Build Example, Explicitly Using code:"make"\:
+    code:"fake make"
+
+  Build Tree Structure Example (using the FLL:"Featureless Linux Library" code:"status_code-0.7.0" project)\:
+    block:"
+      build/
+      â”œâ”€â”€ documents
+      â”œâ”€â”€ includes
+      â”‚   â””── program
+      â”‚       â””── status_code
+      â”‚           â”œâ”€â”€ fss
+      â”‚           â”‚   â”œâ”€â”€ common.h
+      â”‚           â”‚   â””── status_code.h
+      â”‚           â””── main
+      â”‚               â”œâ”€â”€ common.h
+      â”‚               â”œâ”€â”€ common-print.h
+      â”‚               â”œâ”€â”€ print.h
+      â”‚               â””── status_code.h
+      â”œâ”€â”€ libraries
+      â”‚   â”œâ”€â”€ script
+      â”‚   â”œâ”€â”€ shared
+      â”‚   â”‚   â”œâ”€â”€ libstatus_code.so -> libstatus_code.so.0
+      â”‚   â”‚   â”œâ”€â”€ libstatus_code.so.0 -> libstatus_code.so.0.7
+      â”‚   â”‚   â”œâ”€â”€ libstatus_code.so.0.7 -> libstatus_code.so.0.7.0
+      â”‚   â”‚   â””── libstatus_code.so.0.7.0
+      â”‚   â””── static
+      â”‚       â””── libstatus_code.a
+      â”œâ”€â”€ objects
+      â”‚   â”œâ”€â”€ config.o
+      â”‚   â”œâ”€â”€ fss
+      â”‚   â”‚   â”œâ”€â”€ common.o
+      â”‚   â”‚   â””── status_code.o
+      â”‚   â”œâ”€â”€ main
+      â”‚   â”‚   â”œâ”€â”€ common.o
+      â”‚   â”‚   â”œâ”€â”€ common-print.o
+      â”‚   â”‚   â”œâ”€â”€ print.o
+      â”‚   â”‚   â”œâ”€â”€ private-status_code.o
+      â”‚   â”‚   â””── status_code.o
+      â”‚   â”œâ”€â”€ script
+      â”‚   â”œâ”€â”€ shared
+      â”‚   â””── static
+      â”œâ”€â”€ programs
+      â”‚   â”œâ”€â”€ script
+      â”‚   â”œâ”€â”€ shared
+      â”‚   â”‚   â”œâ”€â”€ fss_status_code
+      â”‚   â”‚   â””── status_code
+      â”‚   â””── static
+      â”‚       â”œâ”€â”€ fss_status_code
+      â”‚       â””── status_code
+      â”œâ”€â”€ settings
+      â””── stage
+          â”œâ”€â”€ library_shared-settings.built
+          â”œâ”€â”€ library_static-settings.built
+          â”œâ”€â”€ objects_static-settings.built
+          â”œâ”€â”€ program_shared-settings.fss.built
+          â”œâ”€â”€ program_shared-settings.main.built
+          â”œâ”€â”€ skeleton-settings.built
+          â”œâ”€â”€ skeleton-settings.fss.built
+          â”œâ”€â”€ skeleton-settings.main.built
+          â”œâ”€â”€ sources_headers-settings.built
+          â”œâ”€â”€ sources_script-settings.built
+          â”œâ”€â”€ sources_script-settings.fss.built
+          â”œâ”€â”€ sources_script-settings.main.built
+          â”œâ”€â”€ sources_settings-settings.built
+          â”œâ”€â”€ sources_settings-settings.fss.built
+          â””── sources_settings-settings.main.built
+    "
+
+  See: FLL:"Featureless Linux Library" code:"fake" project documents for further details on how to use the bold:"Featureless Make" system.
+  See: FLL:"Featureless Linux Library" code:"fake" project specifications for how to configure the build FSS:"Featureless Settings Specification" files and make FSS:"Featureless Settings Specification" files.
+  See: file:"readme.bootstrap.txt" for notes on installing.
diff --git a/documents/readme.txt b/documents/readme.txt
new file mode 100644 (file)
index 0000000..8d26cdc
--- /dev/null
@@ -0,0 +1,62 @@
+# fss-0002 iki-0000
+#
+# license: cc-by-sa-4.0
+#
+# This file (assumed to be named readme.build.txt) can be more easily read using the following iki_read commands:
+#   iki_read readme.txt +Q -w -rrrr API API FLL FLL FSS FSS KISS KISS -WW character "'" "'" code '"' '"'
+#
+# To read the "Readme Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read readme.txt +Q -cn "Readme Documentation" | iki_read +Q -w -rrrr API API FLL FLL FSS FSS KISS KISS -WW character "'" "'" code '"' '"'
+#
+
+Readme Documentation:
+  The FLL:"Featureless Linux Library" is a set of projects designed to be used for bold:"Linux" programming.
+
+  The FLL:"Featureless Linux Library" is design around the following concepts\:
+  - API:"Application Programming Interface" designed around communicating to the programmer and maintaining unchanging consistency.
+  - Hacker friendly, promote changing the project via its designed methodologies, implementations, standards, practices, and licenses.
+  - Add freedom back to computing, via the bold:"LGPL" license, because a library is a library.
+  - A standard is not a true standard if it is not freely available and cannot be freely used or followed.
+  - Avoid the bold:"feature" trap where projects keep adding things.
+  - Provide an explicit versioning system that is more than a number, it communicates the status in a very simple manner.
+  - Continue mantaining major versions, a project should be able to last 20, 30, or even 60 years without breaking changes.
+  - Follow the KISS:"Keep It Simple Stupid", principles.
+  - Can be broken up into individual projects, and then further fine-tuned via custom define macros, so that only what is needed for specific situations need be used.
+
+  The FLL:"Featureless Linux Library" versioning system has three parts: code:"major.minor.micro".
+  - The bold:"Major" is the primary API:"Application Programming Interface" specification, changes to this number represent massive breaking changes and for all intents and purposes is a different project.
+  - The bold:"Minor" represents potential breaking changes, where odd numbers represent bold:"development status" and even numbers represent bold:"stable status".
+  - The bold:"Micro" represents bug fixes and security fixes, these should never introduce neither API:"Application Programming Interface" breaking changes nor new functionality.
+
+  Development releases (as specified by bold:"Minor" version part) may introduce breaking changes and new functionality.
+  Stable releases (as specified by the bold:"Minor" version part) may not introduce breaking change, unless forced by some security or other difficult situation, and must not add new functionality.
+
+  The FLL:"Featureless Linux Library" project is broken up into 3 different levels: code:"level_0", code:"level_1", and code:"level_2".
+  A third pseudo-level also exists for common programs built using this project, called code:"level_3".
+
+  With an exception of a few projects within code:"level_0", each level should only depend on a project from a lower level.
+  Therefore, a code:"level_1" project can only depend on code:"level_0" projects and a code:"level_2" project can depend on only code:"level_0" and code:"level_1" projects.
+  This does not technically apply to the pseudo-level, code:"level_3", projects, but the pattern is generally followed.
+
+  A few projects in code:"level_0" are essentially required by everything and are depended on by virtually all projects, regardless of the level.
+  These code:"level_0" projects are\:
+  - code:"f_type": Provides core type definitions, code:"#define", and similar structures for the entire set of FLL:"Featureless Linux Library" projects.
+  - code:"f_status": provides status codes and other status codes to be used by the entire set of FLL:"Featureless Linux Library" projects.
+  - code:"f_memory": provides common memory allocation or deallocation to be used by the entire set of FLL:"Featureless Linux Library" projects.
+  - code:"f_type_array": provides an extension on code:"f_type" that requires linking to code:"f_memory" to be used by the entire set of FLL:"Featureless Linux Library" projects.
+  - code:"f_string": provides common string management to be used by the entire set of the FLL:"Featureless Linux Library" projects.
+  - code:"f_utf": provides common UTF-8 related string management to be used by the entire set of the FLL:"Featureless Linux Library" projects.
+
+  The above projects should be installed first, and in the provided order (code:"f_type", then code:"f_status", then code:"f_memory", then code:"f_type_array", then code:"f_string", and finally code:"f_utf").
+  No other code:"level_0" project should depend on another and can be installed in any order.
+
+  To facilitate building of this project, two different build systems are provided\:
+  - The bootstrap, via the file:"bootstrap.sh" script.
+  - The bold:"Featureless Make", which is a level_3 project provided by FLL:"Featureless Linux Library".
+
+  An example bootstrap script is provided (file:"build/scripts/bootstrap-example.sh") is provided for to show how to build the FLL:"Featureless Linux Library" directly from source.
+  Use it as an example or explicitly call it (such as: code:"bash build/scripts/bootstrap-example.sh monolithic 0.7.0").
+
+  See: file:"dependencies" for specific dependencies of this project.
+  See: file:"readme.bootstrap.txt" for bootstrap compiling (or just regular compiling) any part of the FLL:"Featureless Linux Library" and notes on installing.
+  See: file:"readme.build.txt" for bold:"Featureless Make" compiling and notes on installing.
diff --git a/documents/rule.txt b/documents/rule.txt
new file mode 100644 (file)
index 0000000..8d9e1c5
--- /dev/null
@@ -0,0 +1,238 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named rule.txt) can be more easily read using the following iki_read commands:
+#   iki_read rule.txt +Q -r PID PID -w -W code '"' '"'
+#
+# To read the "Rule Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read rule.txt +Q -cn "Rule Documentation" | iki_read +Q -r PID PID -w -W code '"' '"'
+#
+
+Rule Documentation:
+  This describes the intent and purpose of a Rule file.
+
+  A Rule file, such as code:"ssh.rule", is intended to designate what to execute.
+
+  The rule file is read top-down, except for the outer most list code:"settings", which is intended to store setting data for this rule.
+  Multiple outer most list Objects may be specified and they are executed as provided, in a top-down manner.
+
+  - The code:"settings" Rule Type has the following code:"FSS-0001 (Extended)" Content\:
+    - code:"affinity": Define one or more processors to restrict this rule by with each number representing a specific processor by its id (starting at 0).
+    - code:"capability": Define a set of capabilities in which to use, using the capability code:"text" format (such as code:"= cap_chown+ep").
+    - code:"cgroup": Define a cgroup (control group) in which everything within this rule executes under.
+    - code:"define": A single environment variable name and its associated value that is automatically exposed to processes executed within this rule.
+    - code:"engine": An executable name of a script, such as code:"bash", to use for the code:"script" Rule Type (which likely defaults to code:"bash" if not specified).
+    - code:"environment": A set of environment variables to expose to the processes executed within this rule (PATH is always exposed).
+    - code:"group": A set of group names or IDs to execute as with the first group being the primary group and all remaining being supplementary groups.
+    - code:"limit": Define a resource limit to use (multiple limits may be specified, but only once for each type).
+    - code:"name": A name used to represent this rule, which is printed to the user, screen, logs, etc...
+    - code:"nice": A single niceness value to run all processes executed within this rule as (-20 gets to be greediest in CPU usage and 19 being the nicest in CPU usage).
+    - code:"on": Define a Rule Action in which a specified dependency is needed, wanted, or wished for.
+    - code:"parameter": An IKI name and its associated value for use in this rule file.
+    - code:"path": A single Content used to set a custom PATH environment variable value.
+    - code:"scheduler": A valid name of a scheduler to use followed by an optional priority number.
+    - code:"timeout": A set of timeouts to wait for in which to perform a set action or to consider failure.
+    - code:"user": A single user name or ID to execute as.
+
+  - The code:"capability" setting\:
+    If the user the controller program is run as does not have the desired capabilities already, they cannot be added.
+    This essentially maintains or reduces the capabilities already available.
+    Due to capabilities only being a draft in the POSIX standard, one may expect code:"capabilities" support may not be available and in such a case this setting will do nothing.
+    If the dependent project (f_capability) does not have libcap support enabled, then capabilities will be unsupported by the compilation of this project.
+
+  - The code:"control" setting\:
+    The first argument is either code:"existing" or code:"new", where for code:"existing" the process is run inside the existing control used by the parent and when code:"new" the process is executed within a new control group namespace entirely.
+
+  - The code:"define" setting\:
+    Use this to define an environment variable (this overwrites any existing environment variable with this name).
+    A define is both exported as an environment variable as well as exposed as an IKI variable.
+    Example IKI variable substitution: for code:"define PATH /bin:/sbin", the associated IKI variable would look like: define:"PATH".
+
+    All environment variables, including those defined using this, must be in the code:"environment" list to be exported to the executed process.
+    Environment variables added here that are not added to the environment are still exposed as an IKI variable.
+
+  - The code:"engine" setting\:
+    This engine is used for both code:"script" and code:"utility" Rule Types.
+    The program that engine refers to must accept a standard input pipe to be supported.
+    Additional parameters may be passed to the engine.
+
+  - The code:"group" and code:"user" settings\:
+    Only users and groups that the user the controller program is being run as is allowed to use may be used.
+
+  - The code:"limit" setting\:
+    The first parameter must be one of: code:"as", code:"core", code:"cpu", code:"data", code:"fsize", code:"locks", code:"memlock", code:"msgqueue", code:"nice", code:"nofile", code:"nproc", code:"rss", code:"rtprio", code:"rttime", code:"sigpending", or code:"stack".
+    The second parameter represents the soft limit.
+    The third parameter represents the hard limit.
+    This may be specified multiply times, but only once for each type.
+
+  - The code:"on" setting\:
+    The first parameter represents the Action the dependency exists under and must be one of: code:"freeze", code:"kill", code:"pause", code:"reload", code:"restart", code:"resume", code:"start", code:"stop", or code:"thaw".
+    The second parameter represents how the dependency is required and must be one of: code:"need", code:"want", or code:"wish".
+    The third parameter is a partial path to the rule file.
+    The fourth parameter represents the name of the rule file.
+
+    - In the case of the second parameter\:
+      - A code:"need" designates that the dependent rule is required to be executed (must exist and must succeed).
+      - A code:"want" designates that the dependent rule is to be executed (may exist and if it does, then it must succeed).
+      - A code:"wish" designates that the dependent rule is to be executed (may exist and if it does, but it does not need to succeed).
+
+      In the case of code:"want" and code:"wish", if the desired rule is either not found or is otherwise disabled, then this will not fail or otherwise block the wanting or wishing rule.
+
+  - The code:"path" setting\:
+    When specified, the code:"PATH" environment variable is automatically added to the code:"environment" setting.
+
+  - The code:"parameter" setting\:
+    Use this to define an IKI variable name and value.
+    These do not conflict with environment variables and are not exposed as environment variables.
+    Example IKI variable substitution: for code:"parameter hello world", the associated IKI variable would look like: parameter:"hello".
+
+  - The code:"scheduler" setting\:
+    The valid range of the priority number is dependent on the scheduler.
+    For example, non-real-time schedulers (such as code:"idle") only support a value of 0 whereas real-time schedulers (such as code:"fifo") only support an inclusive range of 1 to 99.
+    Supported non-real-time schedulers are: code:"batch", code:"idle", and code:"other" (aka: normal/default).
+    Supported real-time schedulers are: code:"deadline", code:"fifo", code:"round_robin".
+
+  - The code:"timeout" setting\:
+    (This is not currently implemented.)
+    Provides settings for each of the three special situations: code:"kill", code:"start", and code:"stop".
+    Each of these may only have a single one exist at a time (one code:"kill", one code:"start", and one code:"stop").
+    Each successive code:"timeout" Item Action, specific to each Action Name (such as code:"start"), specified replaces the previously defined code:"timeout" Action (in a top-down manner).
+    The second Content for each of these, when specified, may be a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
+    For code:"kill", this represents the number of MegaTime to wait after stopping some Rule and that Rule has not yet stopped to forcefully stop the Rule (aka kill the Rule).
+    For code:"start", this represents the number of MegaTime to wait after starting some Rule before assuming something went wrong and the Rule is returned as failed.
+    For code:"stop", this represents the number of MegaTime to wait after stopping some Rule before assuming something went wrong and the Rule is returned as failed.
+    If the second Content is not specified, then this disables the type (prevents the specified timeout action).
+
+  There are four available Rule Types to choose from: code:"command", code:"service", code:"script", and code:"utility".
+
+  The code:"command" Rule Type provides a simple command to run under the different circumstances: code:"start", code:"stop", code:"restart", and code:"reload".
+  A code:"command" always operates in the foreground.
+
+  The code:"service" Rule Type provides a code:"command" accompanied with a PID:"Process Identifier" file (Process Identifier file).
+
+  The code:"script" Rule Type provides a series of lines to be executed by some engine, such as GNU Bash.
+  This code:"script" operates in the foreground, but individual things done within the script may operate in foreground or background.
+  The last return state is treated as an error, so be sure to finish the script with a return code of 0 to designate no error and any other whole number, such a 1, to designate an error.
+  Therefore passing code:"exit 1" would return as an error and passing code:"exit 0" would return as a success.
+  A code:"script" is assumed to be in GNU Bash, which is the default expected behavior, but the specification does not explicitly require this.
+  Another scripting language can be used but changing this incurs the responsibility to ensure all rules are updated to the appropriate scripting language.
+
+  The code:"utility" Rule Type provides a code:"script" accompanied with a PID:"Process Identifier" file (Process Identifier file).
+
+  There are nine Rule Actions used to execute ("freeze", code:"kill", code:"pause", code:"reload", code:"restart", code:"resume", code:"start", code:"stop", and code:"thaw")\:
+    When code:"restart" Object's Content is not provided, then code:"start" and code:"stop" is called when the rule is executed using the restart Action, if both code:"start" and code:"stop" are provided.
+    When code:"reload", code:"start", or code:"stop" Object's Content are not provided, then no respective Action is performed.
+
+    Commands are conditionally available depending on the presence of these, such as if code:"stop" is not provided then code:"stop" (and code:"restart") will not be available for the code:"control" program(s) to use.
+
+  Thee are additional Rule Actions not used to execute ("pid_file", code:"rerun", and code:"with")\:
+    - The code:"pid_file" Object's Content designates the path to the PID:"Process Identifier" file created by the called program.
+
+    - The code:"rerun" Object's Content designates how to re-run a given execution Rule type.
+      - The first Content represents the execution type, which may be one of: code:"freeze", code:"kill", code:"pause", code:"reload", code:"restart", code:"resume", code:"start", code:"stop", and code:"thaw".
+
+      - The second Content represents when to run this re-run is triggered, which is either code:"success" (return code of 0) or code:"failure" (return code is not 0).
+
+      - The third Content and more represent additional options for fine tuning how the re-run is Performed\:
+        When code:"delay", followed by a number of MegaTime (MT) (equivalent to milliseconds) in which to wait before attempting the re-run.
+        When code:"max", followed by a positive number or the number 0 designating the maximum number of re-runs to perform.
+        When code:"reset", the code:"max" re-run counter is reset for the opposite re-run when this re-run is triggered, such as\:
+          A code:"rerun start success reset" and a code:"rerun failure max 10", the failure counter would reset to 0 when the code:"success" re-run is performed and not when the code:"failure" re-run is performed.
+
+        A code:"max" of 0 designates that the re-run will happen infinitely.
+
+    - The code:"with" Object's Content designates special flags designating very specific behavior to be applied to any single Rule Type.
+      The following flags are supported:
+        - code:"full_path": Used only by Rule Types that execute something, wherein the entire full path is used for execution and is assigned as argument[0] (such as code:"/bin/bash").
+                       When not specified, the path provided is used and the argument[0] will be the base name (such as code:"bash").
+        - code:"session_new": Execute in a new session setting the process group to the executed process' id (making the executed process a code:"controlling terminal").
+        - code:"session_same": Execute in the same session where the process group is set to the parent process id.
+
+  IKI Variables\:
+    All Rule Actions support IKI variable substitution.
+    The Rule Settings do not support IKI variable substitution.
+
+    The following IKI variable names are supported\:
+    - define
+    - parameter
+    - program
+
+    The code:"define" IKI variables, such as define:"PATH", expand environment variables.
+
+    The code:"parameter" IKI variables, such as parameter:"hello", expand IKI variables defined using the code:"parameter" Setting Rule Type.
+
+    The code:"program" IKI variables, such as program:"verbose:option", expand program arguments (where code:"verbose:option" might expand into code:"-v" ).
+
+    Only the following code:"program" IKI variables are supported\:
+      - dark\:
+        This variable holds the code:"dark" program parameters, such as code:"+d".
+        This supports code:":option".
+
+      - light\:
+        This variable holds the code:"light" program parameters, such as code:"+l".
+        This supports code:":option".
+
+      - no_color\:
+        This variable holds the code:"no_color" program parameters, such as code:"+n".
+        This supports code:":option".
+
+      - quiet\:
+        This variable holds the code:"quiet" program parameters, such as code:"+Q".
+        This supports code:":option".
+
+      - error\:
+        This variable holds the code:"error" program parameters, such as code:"+E".
+        This supports code:":option".
+
+      - normal\:
+        This variable holds the code:"normal" program parameters, such as code:"+N".
+        This supports code:":option".
+
+      - verbose\:
+        This variable holds the code:"verbose" program parameters, such as code:"+V".
+        This supports code:":option".
+
+      - debug\:
+        This variable holds the code:"debug" program parameters, such as code:"+D".
+        This supports code:":option".
+
+      - cgroup\:
+        This variable holds the code:"cgroup" program parameters, such as code:"-c /sys/fs/cgroup/".
+        This supports both code:":option" and code:":value".
+
+      - daemon\:
+        This variable holds the code:"daemon" program parameters, such as code:"-d".
+        This supports code:":option".
+
+      - init\:
+        This variable holds the code:"init" program parameters, such as code:"-I".
+        This supports code:":option".
+
+      - interruptible\:
+        This variable holds the code:"interruptible" program parameters, such as code:"-i".
+        This supports code:":option".
+
+      - pid\:
+        This variable holds the code:"pid" program parameters, such as code:"-p controller/run/default.pid".
+        This supports both code:":option" and code:":value".
+
+      - settings\:
+        This variable holds the code:"settings" program parameters, such as code:"-s controller/".
+        This supports both code:":option" and code:":value".
+
+      - simulate\:
+        This variable holds the code:"simulate" program parameters, such as code:"-S".
+        This supports code:":option".
+
+      - socket\:
+        This variable holds the code:"socket" program parameters, such as code:"-k controller/run/default.socket".
+        This supports both code:":option" and code:":value".
+
+      - uninterruptible\:
+        This variable holds the code:"uninterruptible" program parameters, such as code:"-U".
+        This supports code:":option".
+
+      - validate\:
+        This variable holds the code:"validate" program parameters, such as code:"-v".
+        This supports code:":option".
diff --git a/documents/simulate.txt b/documents/simulate.txt
new file mode 100644 (file)
index 0000000..2dae70d
--- /dev/null
@@ -0,0 +1,35 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named simulate.txt) can be more easily read using the following iki_read commands:
+#   iki_read simulate.txt +Q -w -W code '"' '"'
+#
+# To read the "Simulate Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read simulate.txt +Q -cn "Simulate Documentation" | iki_read +Q -w -W code '"' '"'
+#
+
+Simulate Documentation:
+  This describes the intent and purpose of the simulation and validation parameters.
+
+  The code:"controller" program is designed to support being run as an alternative to an init program (such as Sysvinit or SystemD).
+  To help prevent problems, simulation and validation functionality is provided.
+
+  - The code:"validate" functionality\:
+    By itself will simply check the syntax of the Entry and Rule files (for Rule files specified in the Entry or Exit file).
+    Errors are reported and nothing is executed.
+    The code:"controller" program will return 0 on validation success and 1 on validation failure.
+
+  - The code:"simulate" functionality\:
+    By itself will perform a simulated execution of all Rules designated by an Entry or Exit file.
+    The simulation is not a true simulation in that no program is ever called to perform any operations.
+    Furthermore, any code:"script" specified inside a Rule is only simulated as a whole and not its individual parts.
+    Once the Entry file is finished executing, the code:"simulate" will continue to run waiting on code:"control" commands.
+
+  - The code:"simulate" with code:"validate" functionality\:
+    Will perform similar to code:"validate" functionality except that additional information of the Rules to be executed will be printed.
+    There will be neither execution nor simulated execution of any Rule when both code:"simulate" and code:"validate" are used together.
+
+  When a Rule is simulated, an empty script command (generally defaulting to code:"bash") is executed in place of the actual program being executed for each program or script in the Rule file that is to be executed.
+  This allows for testing the designated permissions and other settings that would be applied when calling some program.
+  Control Groups are not simulated but are actually created and the simulating process will actually be placed within the Control Group.
diff --git a/documents/time.txt b/documents/time.txt
new file mode 100644 (file)
index 0000000..e7c040c
--- /dev/null
@@ -0,0 +1,51 @@
+# fss-0002 iki-0000
+#
+# license: cc-by-sa-4.0
+#
+# This file (assumed to be named time.txt) can be more easily read using the following iki_read commands:
+#   iki_read time.txt +Q -r UTC UTC -w -WW character "'" "'" code '"' '"'
+#
+# To read the "Time Documentation" section of this file, use this command sequence:
+#   fss_basic_list_read time.txt +Q -cn "Time Documentation" | iki_read +Q -r UTC UTC -w -WW character "'" "'" code '"' '"'
+#
+
+Time Documentation:
+  This documents a unit of measurement called a bold:"Time", represented with uppercase bold:"T".
+  For comparison, a unit of bold:"Time" is equivalent to a nanosecond, or 10^-9 seconds.
+  A bold:"MegaTime (MT)" is therefore equivalent to a millisecond such that a millisecond is 10^-3 seconds.
+
+  A unit of bold:"Time" is intended to represent some unit of bold:"Time" such that a single 64-bit integer may hold all units of bold:"Time" for a single calendar year.
+  This unit of bold:"Time" does not and must not include bold:"Years" (unlike bold:"Unix time").
+  To convert from bold:"Time" to bold:"Unix time", one must have a year (which could be assumed to be the current year) and then calculate all of those calendar oddities.
+
+  A unit of bold:"Time" by default is assumed to be in UTC:"Coordinated Universal Time".
+    - code:"1 (Earth) year ~= 31536000000000000 Time or 31536000 GT (GigaTime)".
+    - code:"1 (Earth) day = 86400000000000 Time or 86400 GT (GigaTime)".
+    - code:"1 (Earth) hour = 3600000000000 Time or 3600 GT (GigaTime)".
+    - code:"1 (Earth) minute = 60000000000 Time or 60 GT (GigaTime)".
+    - code:"1 (Earth) second = 1000000000 Time or 1 GT (GigaTime)".
+
+  Consequentially, 1 day is easily represented in units of bold:"Time" as code:"86.4 TT (TeraTime)".
+
+  The Time may be stored in its "year string format".
+  In this format, a Year may be prepended to the Time followed by a single colon ':' to associate a year with the Time.
+  This Year has no minimum or maximum but may not have decimals.
+  For example, "2020:86400000000000" would represent: January 02, 2020 0:00 UTC.
+  For example, "2020:86.4 TT" would represent: January 02, 2020 0:00 UTC.
+
+  A second unit of bold:"Time", called bold:"EpochTime", works the same way as bold:"Time" except it represents seconds.
+  This unit is designated code:"ET".
+  The format is similar to bold:"Time", except there are two colons: code:"1970::1620874738" would represent: code:"May 13, 2021 2:58:58 UTC".
+  When the year is not specified, then this is identical to bold:"UNIX Epoch".
+
+  A unit of bold:"EpochTime" by default is assumed to be in UTC:"Coordinated Universal Time".
+    - code:"1 (Earth) year ~= 31536000 EpochTime or 31.536 GE (GigaEpochTime)".
+    - code:"1 (Earth) day = 86400 EpochTime".
+    - code:"1 (Earth) hour = 3600 EpochTime".
+    - code:"1 (Earth) minute = 60 EpochTime".
+    - code:"1 (Earth) second = 1 EpochTime".
+    - code:"1 GT (GigaTime) = 1 EpochTime".
+
+  Consequentially, 1 day is easily represented in units of bold:"EpochTime" as code:"86.4 KE (KiloEpochTime)".
+
+  See the specification file:"time.txt" for more precise technical details.
diff --git a/install.sh b/install.sh
new file mode 100755 (executable)
index 0000000..4db64b7
--- /dev/null
@@ -0,0 +1,1020 @@
+#!/bin/bash
+# license: lgpl-2.1-or-later
+# programmer: Kevin Day
+#
+# The purpose of this script is to provide a simple installer tool to copy any part of the FLL project onto a system.
+# This assumes the destination directories already exist and does not attempt to create them.
+# Ideally, the package manager of the system should be used, but this is provided as a guide or a fallback.
+# Settings files are not copied over, but a warning will be printed to inform the installer of their existence.
+#
+# The dependencies of this script are: bash, grep, and sed.
+#
+# This script can also be run under zsh rather than bash by setting the environment variable SHELL_ENGINE to "zsh", such as:
+#   SHELL_ENGINE="zsh" zsh ./install.sh --help
+#
+
+install_main() {
+
+  if [[ ${SHELL_ENGINE} == "zsh" ]] ; then
+    emulate ksh
+  fi
+
+  local public_name="Simple FLL Project Install Script"
+  local system_name=install
+  local called_name=$(basename ${0})
+  local version=0.7.0
+
+  local grab_next=
+  local do_color=dark
+  local do_help=
+  local do_copyright=
+  local i=0
+  local p=
+  local t=0
+  local key=
+
+  local c_reset="\\033[0m"
+  local c_title="\\033[1;33m"
+  local c_error="\\033[1;31m"
+  local c_warning="\\033[0;33m"
+  local c_highlight="\\033[1;32m"
+  local c_notice="\\033[0;01m"
+  local c_important="\\033[0;32m"
+  local c_subtle="\\033[1;30m"
+  local c_prefix="\\"
+
+  local failure=0
+  local operation=
+  local operation_failure=
+  local verbosity=normal
+  local verbose=
+  local verbose_common=
+
+  local path_build=build/
+  local path_documentation=documentation/
+  local path_programs=programs/
+  local path_includes=includes/
+  local path_libraries=libraries/
+  local path_settings=settings/
+  local path_static=static/
+  local path_shared=shared/
+
+  local destination_documentation=share/
+  local destination_prefix=/usr/local/
+  local destination_programs=bin/
+  local destination_includes=include/
+  local destination_libraries=lib/
+  local destination_libraries_static=
+  local destination_libraries_shared=
+  local destination_programs_static=
+  local destination_programs_shared=
+  local destination_settings=etc/
+
+  local work=
+
+  local enable_documentation="yes"
+  local enable_settings="yes"
+  local enable_shared="yes"
+  local enable_shared_programs="yes"
+  local enable_shared_libraries="yes"
+  local enable_static="yes"
+  local enable_static_programs="yes"
+  local enable_static_libraries="yes"
+  local enable_includes="yes"
+  local print_line_first="yes"
+  local print_line_last="yes"
+
+  if [[ $# -gt 0 ]] ; then
+    t=$#
+
+    while [[ ${i} -lt ${t} ]] ; do
+      let i=${i}+1
+
+      if [[ ${SHELL_ENGINE} == "zsh" ]] ; then
+        p=${(P)i}
+      else
+        p=${!i}
+      fi
+
+      if [[ ${grab_next} == "" ]] ; then
+        if [[ ${p} == "-h" || ${p} == "--help" ]] ; then
+          do_help=yes
+        elif [[ ${p} == "+C" || ${p} == "++copyright" ]] ; then
+          do_copyright="yes"
+        elif [[ ${p} == "+d" || ${p} == "++dark" ]] ; then
+          do_color="dark"
+          context="+d"
+        elif [[ ${p} == "+l" || ${p} == "++light" ]] ; then
+          do_color="light"
+          context="+l"
+        elif [[ ${p} == "+n" || ${p} == "++no_color" ]] ; then
+          do_color=none
+          context="+n"
+        elif [[ ${p} == "+Q" || ${p} == "++quiet" ]] ; then
+          verbosity="quiet"
+          verbose="+Q"
+          verbose_common=
+        elif [[ ${p} == "+N" || ${p} == "++normal" ]] ; then
+          verbosity=
+          verbose="+N"
+          verbose_common=
+        elif [[ ${p} == "+E" || ${p} == "++error" ]] ; then
+          verbosity="error"
+          verbose="+E"
+          verbose_common=
+        elif [[ ${p} == "+V" || ${p} == "++verbose" ]] ; then
+          verbosity="verbose"
+          verbose="+V"
+          verbose_common="-v"
+        elif [[ ${p} == "+D" || ${p} == "++debug" ]] ; then
+          verbosity="debug"
+          verbose="+D"
+          verbose_common="-v"
+        elif [[ ${p} == "+F" || ${p} == "++line_first_no" ]] ; then
+          print_line_first="no"
+        elif [[ ${p} == "+L" || ${p} == "++line_last_no" ]] ; then
+          print_line_last="no"
+        elif [[ ${p} == "+v" || ${p} == "++version" ]] ; then
+          echo ${version}
+          return 0
+        elif [[ ${p} == "-b" || ${p} == "--build" ]] ; then
+          grab_next=path_build
+        elif [[ ${p} == "-P" || ${p} == "--prefix" ]] ; then
+          grab_next=prefix
+        elif [[ ${p} == "-B" || ${p} == "--bindir" ]] ; then
+          grab_next=bindir
+        elif [[ ${p} == "-D" || ${p} == "--docdir" ]] ; then
+          grab_next=docdir
+        elif [[ ${p} == "-E" || ${p} == "--etcdir" ]] ; then
+          grab_next=etcdir
+        elif [[ ${p} == "-I" || ${p} == "--includedir" ]] ; then
+          grab_next=includedir
+        elif [[ ${p} == "-L" || ${p} == "--libdir" ]] ; then
+          grab_next=libdir
+        elif [[ ${p} == "-w" || ${p} == "--work" ]] ; then
+          grab_next=work
+        elif [[ ${p} == "--enable-doc" ]] ; then
+          enable_documentation="yes"
+        elif [[ ${p} == "--disable-doc" ]] ; then
+          enable_documentation="no"
+        elif [[ ${p} == "--enable-settings" ]] ; then
+          enable_settings="yes"
+        elif [[ ${p} == "--disable-settings" ]] ; then
+          enable_settings="no"
+        elif [[ ${p} == "--enable-shared" ]] ; then
+          enable_shared="yes"
+        elif [[ ${p} == "--disable-shared" ]] ; then
+          enable_shared="no"
+        elif [[ ${p} == "--disable-shared-programs" ]] ; then
+          enable_shared_programs="no"
+        elif [[ ${p} == "--disable-shared-libraries" ]] ; then
+          enable_shared_libraries="no"
+        elif [[ ${p} == "--disable-static-programs" ]] ; then
+          enable_static_programs="no"
+        elif [[ ${p} == "--disable-static-libraries" ]] ; then
+          enable_static_libraries="no"
+        elif [[ ${p} == "--enable-static" ]] ; then
+          enable_static="yes"
+        elif [[ ${p} == "--disable-static" ]] ; then
+          enable_static="no"
+        elif [[ ${p} == "--enable-includes" ]] ; then
+          enable_includes="yes"
+        elif [[ ${p} == "--disable-includes" ]] ; then
+          enable_includes="no"
+        elif [[ ${p} == "--libraries-static" ]] ; then
+          grab_next="destination_libraries_static"
+        elif [[ ${p} == "--libraries-shared" ]] ; then
+          grab_next="destination_libraries_shared"
+        elif [[ ${p} == "--programs-static" ]] ; then
+          grab_next="destination_programs_static"
+        elif [[ ${p} == "--programs-shared" ]] ; then
+          grab_next="destination_programs_shared"
+        elif [[ ${operation_failure} == "" ]] ; then
+          operation="${p}"
+          operation_failure=fail-unsupported
+        fi
+      else
+        if [[ ${grab_next} == "path_build" ]] ; then
+          path_build=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "prefix" ]] ; then
+          destination_prefix=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "bindir" ]] ; then
+          destination_programs=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "docdir" ]] ; then
+          destination_documentation=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "etcdir" ]] ; then
+          destination_settings=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "includedir" ]] ; then
+          destination_includes=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "libdir" ]] ; then
+          destination_libraries=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "work" ]] ; then
+          work=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "destination_libraries_static" ]] ; then
+          destination_libraries_static=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "destination_libraries_shared" ]] ; then
+          destination_libraries_shared=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "destination_programs_static" ]] ; then
+          destination_programs_static=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        elif [[ ${grab_next} == "destination_programs_shared" ]] ; then
+          destination_programs_shared=$(echo ${p} | sed -e 's|^//*|/|' -e 's|/*$|/|')
+        fi
+
+        grab_next=
+      fi
+    done
+
+    p=
+  fi
+
+  if [[ ${verbosity} == "quiet" ]] ; then
+    print_line_first="no"
+    print_line_last="no"
+  fi
+
+  install_handle_colors
+
+  if [[ ${do_help} == "yes" ]] ; then
+    install_help
+    install_cleanup
+
+    return 0
+  fi
+
+  if [[ ${do_copyright} == "yes" ]] ; then
+    install_copyright
+    install_cleanup
+
+    return 0
+  fi
+
+  if [[ ${operation_failure} == "fail-unsupported" ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The operation ${c_notice}${operation}${c_error} was not recognized.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  if [[ ! -d ${path_build} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The build path ${c_notice}${path_build}${c_error} is not a valid directory.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  if [[ ${work} == "" && ${destination_prefix} != "" && ! -d ${destination_prefix} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The destination prefix ${c_notice}${destination_prefix}${c_error} is not a valid directory.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  if [[ ${destination_prefix} != "" ]] ; then
+    if [[ $(echo ${destination_documentation} | grep -o '^/') == "" ]] ; then
+      destination_documentation="${destination_prefix}${destination_documentation}"
+    fi
+
+    if [[ $(echo ${destination_programs} | grep -o '^/') == "" ]] ; then
+      destination_programs="${destination_prefix}${destination_programs}"
+    fi
+
+    if [[ $(echo ${destination_includes} | grep -o '^/') == "" ]] ; then
+      destination_includes="${destination_prefix}${destination_includes}"
+    fi
+
+    if [[ $(echo ${destination_libraries} | grep -o '^/') == "" ]] ; then
+      destination_libraries="${destination_prefix}${destination_libraries}"
+    fi
+
+    if [[ $(echo ${destination_settings} | grep -o '^/') == "" ]] ; then
+      destination_settings="${destination_prefix}${destination_settings}"
+    fi
+  fi
+
+  if [[ ${destination_libraries_static} != "" ]] ; then
+    if [[ $(echo ${destination_libraries_static} | grep -o '^/') == "" ]] ; then
+      destination_libraries_static=${destination_libraries}${destination_libraries_static}
+    fi
+  else
+    destination_libraries_static=${destination_libraries}
+  fi
+
+  if [[ ${destination_libraries_shared} != "" ]] ; then
+    if [[ $(echo ${destination_libraries_shared} | grep -o '^/') == "" ]] ; then
+      destination_libraries_shared=${destination_libraries}${destination_libraries_shared}
+    fi
+  else
+    destination_libraries_shared=${destination_libraries}
+  fi
+
+  if [[ ${destination_programs_static} != "" ]] ; then
+    if [[ $(echo ${destination_programs_static} | grep -o '^/') == "" ]] ; then
+      destination_programs_static=${destination_programs}${destination_programs_static}
+    fi
+  else
+    destination_programs_static=${destination_programs}
+  fi
+
+  if [[ ${destination_programs_shared} != "" ]] ; then
+    if [[ $(echo ${destination_programs_shared} | grep -o '^/') == "" ]] ; then
+      destination_programs_shared=${destination_programs}${destination_programs_shared}
+    fi
+  else
+    destination_programs_shared=${destination_programs}
+  fi
+
+  if [[ ${work} != "" && ! -d ${work} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The work directory ${c_notice}${work}${c_error} is not a valid directory.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  if [[ ${work} == "" && -e ${destination_programs} && ! -d ${destination_programs} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The destination bindir ${c_notice}${destination_programs}${c_error} is not a valid directory.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  if [[ ${work} == "" && -e ${destination_programs_static} && ! -d ${destination_programs_static} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The destination (${c_notice}static${c_error}) bindir ${c_notice}${destination_programs_static}${c_error} is not a valid directory.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  if [[ ${work} == "" && -e ${destination_programs_shared} && ! -d ${destination_programs_shared} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The destination (${c_notice}shared${c_error}) bindir ${c_notice}${destination_programs_shared}${c_error} is not a valid directory.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  if [[ ${work} == "" && -e ${destination_includes} && ! -d ${destination_includes} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The destination incluedir ${c_notice}${destination_includes}${c_error} is not a valid directory.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  if [[ ${work} == "" && -e ${destination_libraries_static} && ! -d ${destination_libraries_static} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The destination (${c_notice}static${c_error}) libdir ${c_notice}${destination_libraries_static}${c_error} is not a valid directory.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  if [[ ${work} == "" && -e ${destination_libraries_shared} && ! -d ${destination_libraries_shared} ]] ; then
+    if [[ ${verbosity} != "quiet" ]] ; then
+      install_print_first
+
+      echo -e "${c_error}ERROR: The destination (${c_notice}shared${c_error}) libdir ${c_notice}${destination_libraries_shared}${c_error} is not a valid directory.${c_reset}"
+
+      install_print_last
+    fi
+
+    install_cleanup
+
+    return 1
+  fi
+
+  install_perform_install
+
+  if [[ ${verbosity} != "quiet" ]] ; then
+    if [[ ${failure} -eq 1 || ${verbosity} != "error" ]] ; then
+      install_print_last
+    fi
+  fi
+
+  install_cleanup
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  return 0
+}
+
+install_handle_colors() {
+
+  if [[ ${do_color} == "light" ]] ; then
+    c_error="\\033[1;31m"
+    c_warning="\\033[0;31m"
+    c_title="\\033[1;34m"
+    c_highlight="\\033[0;34m"
+    c_notice="\\033[0;01m"
+    c_important="\\033[0;35m"
+  elif [[ ${do_color} == "none" ]] ; then
+    c_reset=
+    c_title=
+    c_error=
+    c_warning=
+    c_highlight=
+    c_notice=
+    c_important=
+    c_subtle=
+    c_prefix=
+  fi
+}
+
+install_help() {
+
+  install_print_first
+
+  echo -e "${c_title}${public_name}${c_reset}"
+  echo -e " ${c_notice}Version ${version}${c_reset}"
+  echo
+  echo -e "${c_highlight}${system_name}${c_reset} ${c_notice}[${c_reset} options ${c_notice}]${c_reset}"
+  echo
+  echo -e "${c_highlight}Options:${c_reset}"
+  echo -e " -${c_important}h${c_reset}, --${c_important}help${c_reset}           Print this help message."
+  echo -e " +${c_important}C${c_reset}, ++${c_important}copyright${c_reset}      Print the copyright."
+  echo -e " +${c_important}d${c_reset}, ++${c_important}dark${c_reset}           Output using colors that show up better on dark backgrounds."
+  echo -e " +${c_important}l${c_reset}, ++${c_important}light${c_reset}          Output using colors that show up better on light backgrounds."
+  echo -e " +${c_important}n${c_reset}, ++${c_important}no_color${c_reset}       Do not print using color."
+  echo -e " +${c_important}Q${c_reset}, ++${c_important}quiet${c_reset}          Decrease verbosity, silencing most print.to."
+  echo -e " +${c_important}E${c_reset}, ++${c_important}error${c_reset}          Decrease verbosity, using only error print.to."
+  echo -e " +${c_important}N${c_reset}, ++${c_important}normal${c_reset}         Set verbosity to normal."
+  echo -e " +${c_important}V${c_reset}, ++${c_important}verbose${c_reset}        Increase verbosity beyond normal print.to."
+  echo -e " +${c_important}D${c_reset}, ++${c_important}debug${c_reset}          Enable debugging, significantly increasing verbosity beyond normal print.to."
+  echo -e " +${c_important}v${c_reset}, ++${c_important}version${c_reset}        Print only the version number."
+  echo -e " +${c_important}F${c_reset}, ++${c_important}line_first_no${c_reset}  Disable printing of first line."
+  echo -e " +${c_important}L${c_reset}, ++${c_important}line_last_no${c_reset}   Disable printing of last line."
+  echo
+  echo -e "${c_highlight}Install Options:${c_reset}"
+  echo -e " -${c_important}b${c_reset}, --${c_important}build${c_reset}       Custom build directory."
+  echo -e " -${c_important}P${c_reset}, --${c_important}prefix${c_reset}      Custom destination prefix."
+  echo -e " -${c_important}B${c_reset}, --${c_important}bindir${c_reset}      Custom destination bin/ directory."
+  echo -e " -${c_important}D${c_reset}, --${c_important}docdir${c_reset}      Custom destination share/ directory (documentation directory)."
+  echo -e " -${c_important}E${c_reset}, --${c_important}etcdir${c_reset}      Custom destination etc/ directory (settings directory)."
+  echo -e " -${c_important}I${c_reset}, --${c_important}includedir${c_reset}  Custom destination include/ directory."
+  echo -e " -${c_important}L${c_reset}, --${c_important}libdir${c_reset}      Custom destination lib/ directory."
+  echo -e " -${c_important}w${c_reset}, --${c_important}work${c_reset}        Install to this work directory using a 'working' directory structure."
+  echo
+  echo -e "${c_highlight}Special Options:${c_reset}"
+  echo -e " --${c_important}enable-doc${c_reset}                Forcibly do install documentation files."
+  echo -e " --${c_important}disable-doc${c_reset}               Forcibly do not install documentation files."
+  echo -e " --${c_important}enable-settings${c_reset}           Forcibly do install settings files."
+  echo -e " --${c_important}disable-settings${c_reset}          Forcibly do not install settings files."
+  echo -e " --${c_important}enable-shared${c_reset}             Forcibly do install shared files."
+  echo -e " --${c_important}disable-shared${c_reset}            Forcibly do not install shared files."
+  echo -e " --${c_important}disable-shared-programs${c_reset}   Forcibly do not install shared programs."
+  echo -e " --${c_important}disable-shared-libraries${c_reset}  Forcibly do not install shared libraries."
+  echo -e " --${c_important}enable-static${c_reset}             Forcibly do install static files."
+  echo -e " --${c_important}disable-static${c_reset}            Forcibly do not install static files."
+  echo -e " --${c_important}disable-static-programs${c_reset}   Forcibly do not install shared programs."
+  echo -e " --${c_important}disable-static-libraries${c_reset}  Forcibly do not install shared libraries."
+  echo -e " --${c_important}enable-includes${c_reset}           Forcibly do not install include files."
+  echo -e " --${c_important}disable-includes${c_reset}          Forcibly do not install include files."
+  echo -e " --${c_important}libraries-static${c_reset}          Custom destination for static libraries."
+  echo -e " --${c_important}libraries-shared${c_reset}          Custom destination for shared libraries."
+  echo -e " --${c_important}programs-static${c_reset}           Custom destination for static programs."
+  echo -e " --${c_important}programs-shared${c_reset}           Custom destination for shared programs."
+
+  install_print_last
+}
+
+install_copyright() {
+
+  install_print_first
+
+  echo "Copyright Â© 2007-2023 Kevin Day."
+  echo
+  echo "Source code license lgpl-2.1-or-later."
+  echo "Standard and specification license open-standard-license-1.0."
+  echo "Documentation license cc-by-sa-4.0."
+
+  install_print_last
+}
+
+install_perform_install() {
+  local key=
+  local i=
+  local path=
+  local message=
+
+  if [[ ${enable_shared} == "no" ]] ; then
+    enable_shared_programs="no"
+    enable_shared_libraries="no"
+  fi
+
+  if [[ ${enable_static} == "no" ]] ; then
+    enable_static_programs="no"
+    enable_static_libraries="no"
+  fi
+
+  if [[ ${work} == "" ]] ; then
+    message="install destination directory"
+  else
+    message="work directory"
+    destination_prefix=${work}
+    destination_documentation=${work}documentation/
+    destination_programs=${work}programs/
+    destination_programs_static=${destination_programs}static/
+    destination_programs_shared=${destination_programs}shared/
+    destination_includes=${work}includes/
+    destination_libraries=${work}libraries/
+    destination_libraries_static=${destination_libraries}static/
+    destination_libraries_shared=${destination_libraries}shared/
+    destination_settings=${work}settings/
+  fi
+
+  if [[ ! -d ${destination_prefix} ]] ; then
+    mkdir ${verbose_common} ${destination_prefix}
+
+    if [[ ${?} -ne 0 ]] ; then
+      if [[ ${verbosity} != "quiet" ]] ; then
+        install_print_first
+
+        echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_prefix}${c_error}.${c_reset}"
+      fi
+
+      let failure=1
+    fi
+  fi
+
+  if [[ ${enable_shared_programs} == "yes" || ${enable_static_programs} == "yes" ]] ; then
+    if [[ -d ${path_build}${path_programs} && ! -d ${destination_programs} ]] ; then
+      mkdir ${verbose_common} ${destination_programs}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_programs}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+
+    if [[ ${enable_shared_programs} == "yes" && -d ${path_build}${path_programs}${path_shared} && ! -d ${destination_programs_shared} ]] ; then
+      mkdir ${verbose_common} ${destination_programs_shared}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_programs_shared}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+
+    if [[ ${enable_static_programs} == "yes" && -d ${path_build}${path_programs}${path_static} && ! -d ${destination_programs_static} ]] ; then
+      mkdir ${verbose_common} ${destination_programs_static}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_programs_static}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+  fi
+
+  if [[ ${enable_shared_libraries} == "yes" || ${enable_static_libraries} == "yes" ]] ; then
+    if [[ -d ${path_build}${path_libraries} && ! -d ${destination_libraries} ]] ; then
+      mkdir ${verbose_common} ${destination_libraries}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_libraries}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+
+    if [[ ${enable_shared_libraries} == "yes" && -d ${path_build}${path_libraries}${path_shared} && ! -d ${destination_libraries_shared} ]] ; then
+      mkdir ${verbose_common} ${destination_libraries_shared}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_libraries_shared}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+
+    if [[ ${enable_static_libraries} == "yes" && -d ${path_build}${path_libraries}${path_static} && ! -d ${destination_libraries_static} ]] ; then
+      mkdir ${verbose_common} ${destination_libraries_static}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_libraries_static}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+  fi
+
+  if [[ ${enable_includes} == "yes" ]] ; then
+    if [[ -d ${path_build}${path_includes} && ! -d ${destination_includes} ]] ; then
+      mkdir ${verbose_common} ${destination_includes}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_includes}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+  fi
+
+  if [[ ${enable_documentation} == "yes" ]] ; then
+    if [[ -d ${path_build}${path_documentation} && ! -d ${destination_documentation} ]] ; then
+      mkdir ${verbose_common} ${destination_documentation}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_documentation}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+  fi
+
+  if [[ ${enable_settings} == "yes" ]] ; then
+    if [[ -d ${path_build}${path_settings} && ! -d ${destination_settings} ]] ; then
+      mkdir ${verbose_common} ${destination_settings}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_settings}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+  fi
+
+  if [[ ${failure} -eq 0 && -d ${path_build}${path_includes} && ${enable_includes} == "yes" ]] ; then
+    for i in ${path_build}${path_includes}* ; do
+
+      file=$(echo ${i} | sed -e "s|^${path_build}${path_includes}||")
+
+      break
+    done
+
+    if [[ ${file} == "*" && ! -f "${path_build}${path_includes}*" ]] ; then
+      file=
+    fi
+
+    if [[ ${file} != "" ]] ; then
+      if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+        install_print_first_or_always
+
+        echo -e "${c_highlight}Installing Includes to: ${c_reset}${c_notice}${destination_includes}${c_reset}${c_highlight}.${c_reset}"
+      fi
+
+      cp ${verbose_common} -R ${path_build}${path_includes}* ${destination_includes}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: Failed to copy include files from ${c_notice}${path_build}${path_includes}${c_error} to ${c_notice}${destination_includes}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+  fi
+
+  if [[ ${failure} -eq 0 && -d ${path_build}${path_libraries} && ( ${enable_shared_libraries} == "yes" || ${enable_static_libraries} == "yes" ) ]] ; then
+    if [[ -d ${path_build}${path_libraries}${path_static} && ${enable_static_libraries} == "yes" ]] ; then
+      for i in ${path_build}${path_libraries}${path_static}* ; do
+
+        file=$(echo ${i} | sed -e "s|^${path_build}${path_libraries}${path_static}||")
+
+        break
+      done
+
+      if [[ ${file} == "*" && ! -f "${path_build}${path_libraries}${path_static}*" ]] ; then
+        file=
+      fi
+
+      if [[ ${file} != "" ]] ; then
+        if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+          install_print_first_or_always
+
+          echo -e "${c_highlight}Installing (${c_notice}static${c_highlight}) Libraries to: ${c_reset}${c_notice}${destination_libraries_static}${c_reset}${c_highlight}.${c_reset}"
+        fi
+
+        cp ${verbose_common} -R ${path_build}${path_libraries}${path_static}* ${destination_libraries_static}
+
+        if [[ ${?} -ne 0 ]] ; then
+          if [[ ${verbosity} != "quiet" ]] ; then
+            install_print_first
+
+            echo -e "${c_error}ERROR: Failed to copy (${c_notice}static${c_error}) library files from ${c_notice}${path_build}${path_libraries}${path_static}${c_error} to ${c_notice}${destination_libraries_static}${c_error}.${c_reset}"
+          fi
+
+          let failure=1
+        fi
+      fi
+    fi
+
+    if [[ ${failure} -eq 0 && -d ${path_build}${path_libraries}${path_shared} && ${enable_shared_libraries} == "yes" ]] ; then
+      for i in ${path_build}${path_libraries}${path_shared}* ; do
+
+        file=$(echo ${i} | sed -e "s|^${path_build}${path_libraries}${path_shared}||")
+
+        break
+      done
+
+      if [[ ${file} == "*" && ! -f "${path_build}${path_libraries}${path_shared}*" ]] ; then
+        file=
+      fi
+
+      if [[ ${file} != "" ]] ; then
+        if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+          install_print_first_or_always
+
+          echo -e "${c_highlight}Installing (${c_notice}shared${c_highlight}) Libraries to: ${c_reset}${c_notice}${destination_libraries_shared}${c_reset}${c_highlight}.${c_reset}"
+        fi
+
+        cp ${verbose_common} -R ${path_build}${path_libraries}${path_shared}* ${destination_libraries_shared}
+
+        if [[ ${?} -ne 0 ]] ; then
+          if [[ ${verbosity} != "quiet" ]] ; then
+            install_print_first
+
+            echo -e "${c_error}ERROR: Failed to copy (${c_notice}shared${c_error}) library files from ${c_notice}${path_build}${path_libraries}${path_shared}${c_error} to ${c_notice}${destination_libraries_shared}${c_error}.${c_reset}"
+          fi
+
+          let failure=1
+        fi
+      fi
+    fi
+  fi
+
+  if [[ ${failure} -eq 0 && -d ${path_build}${path_programs} && ( ${enable_shared_programs} == "yes" || ${enable_static_programs} == "yes" ) ]] ; then
+    if [[ -d ${path_build}${path_programs}${path_static} && ${enable_static_programs} == "yes" ]] ; then
+      for i in ${path_build}${path_programs}${path_static}* ; do
+
+        file=$(echo ${i} | sed -e "s|^${path_build}${path_programs}${path_static}||")
+
+        break
+      done
+
+      if [[ ${file} == "*" && ! -f "${path_build}${path_programs}${path_static}*" ]] ; then
+        file=
+      fi
+
+      if [[ ${file} != "" && ${enable_static_programs} == "yes" ]] ; then
+        if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+          install_print_first_or_always
+
+          echo -e "${c_highlight}Installing (${c_notice}static${c_highlight}) Programs to: ${c_reset}${c_notice}${destination_programs_static}${c_reset}${c_highlight}.${c_reset}"
+        fi
+
+        cp ${verbose_common} -R ${path_build}${path_programs}${path_static}* ${destination_programs_static}
+
+        if [[ ${?} -ne 0 ]] ; then
+          if [[ ${verbosity} != "quiet" ]] ; then
+            install_print_first
+
+            echo -e "${c_error}ERROR: failed to copy (${c_notice}static${c_error}) program files from ${c_notice}${path_build}${path_programs}${path_static}${c_error} to ${c_notice}${destination_programs_static}${c_error}.${c_reset}"
+          fi
+
+          let failure=1
+        fi
+      fi
+    fi
+
+    if [[ ${failure} -eq 0 && -d ${path_build}${path_programs}${path_shared} && ${enable_shared_programs} == "yes" ]] ; then
+      for i in ${path_build}${path_programs}${path_shared}* ; do
+
+        file=$(echo ${i} | sed -e "s|^${path_build}${path_programs}${path_shared}||")
+
+        break
+      done
+
+      if [[ ${file} == "*" && ! -f "${path_build}${path_programs}${path_shared}*" ]] ; then
+        file=
+      fi
+
+      if [[ ${file} != "" ]] ; then
+        if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+          install_print_first_or_always
+
+          echo -e "${c_highlight}Installing (${c_notice}shared${c_highlight}) Programs to: ${c_reset}${c_notice}${destination_programs_shared}${c_reset}${c_highlight}.${c_reset}"
+        fi
+
+        cp ${verbose_common} -R ${path_build}${path_programs}${path_shared}* ${destination_programs_shared}
+
+        if [[ ${?} -ne 0 ]] ; then
+          if [[ ${verbosity} != "quiet" ]] ; then
+            install_print_first
+
+            echo -e "${c_error}ERROR: failed to copy (${c_notice}shared${c_error}) program files from ${c_notice}${path_build}${path_programs}${path_shared}${c_error} to ${c_notice}${destination_programs_shared}${c_error}.${c_reset}"
+          fi
+
+          let failure=1
+        fi
+      fi
+    fi
+  fi
+
+  if [[ ${failure} -eq 0 && -d ${path_build}${path_settings} && ${enable_settings} == "yes" ]] ; then
+    for i in ${path_build}${path_settings}* ; do
+
+      file=$(echo ${i} | sed -e "s|^${path_build}${path_settings}||")
+
+      break
+    done
+
+    if [[ ${file} == "*" && ! -f "${path_build}${path_settings}*" ]] ; then
+      file=
+    fi
+
+    if [[ ${file} != "" ]] ; then
+      if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+        install_print_first_or_always
+
+        echo -e "${c_highlight}Installing Settings to: ${c_reset}${c_notice}${destination_settings}${c_reset}${c_highlight}.${c_reset}"
+      fi
+
+      cp ${verbose_common} -R ${path_build}${path_settings}* ${destination_settings}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: failed to copy settings files from ${c_notice}${path_build}${path_settings}${c_error} to ${c_notice}${destination_settings}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+  fi
+
+  if [[ ${failure} -eq 0 && -d ${path_build}${path_documentation} && ${enable_documentation} == "yes" ]] ; then
+    for i in ${path_build}${path_documentation}* ; do
+
+      file=$(echo ${i} | sed -e "s|^${path_build}${path_documentation}||")
+
+      break
+    done
+
+    if [[ ${file} == "*" && ! -f "${path_build}${path_documentation}*" ]] ; then
+      file=
+    fi
+
+    if [[ ${file} != "" ]] ; then
+      if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then
+        install_print_first_or_always
+
+        echo -e "${c_highlight}Installing Documentation to: ${c_reset}${c_notice}${destination_documentation}${c_reset}${c_highlight}.${c_reset}"
+      fi
+
+      cp ${verbose_common} -R ${path_build}${path_documentation}* ${destination_documentation}
+
+      if [[ ${?} -ne 0 ]] ; then
+        if [[ ${verbosity} != "quiet" ]] ; then
+          install_print_first
+
+          echo -e "${c_error}ERROR: failed to copy documentation files from ${c_notice}${path_build}${path_documentation}${c_error} to ${c_notice}${destination_documentation}${c_error}.${c_reset}"
+        fi
+
+        let failure=1
+      fi
+    fi
+  fi
+
+  if [[ ${failure} -eq 1 ]] ; then
+    return 1
+  fi
+
+  return 0
+}
+
+install_print_first() {
+
+  if [[ ${print_line_first} == "yes" ]] ; then
+    echo
+
+    print_line_first=
+  fi
+}
+
+install_print_first_or_always() {
+
+  if [[ ${print_line_first} == "yes" ]] ; then
+    echo
+
+    print_line_first=
+  elif [[ ${print_line_first} == "no" ]] ; then
+    print_line_first=
+  else
+    echo
+  fi
+}
+
+install_print_last() {
+
+  if [[ ${print_line_last} == "yes" ]] ; then
+    echo
+  fi
+}
+
+install_cleanup() {
+
+  unset install_copyright
+  unset install_main
+  unset install_handle_colors
+  unset install_help
+  unset install_perform_install
+  unset install_print_first
+  unset install_print_first_or_always
+  unset install_print_last
+  unset install_cleanup
+}
+
+install_main $*
diff --git a/licenses/cc-by-sa-4.0 b/licenses/cc-by-sa-4.0
new file mode 100644 (file)
index 0000000..e672f4e
--- /dev/null
@@ -0,0 +1,4 @@
+Creative Commons Attribution Share Alike 4.0 International
+
+see: https://creativecommons.org/licenses/by-sa/4.0/
+see: https://creativecommons.org/licenses/by-sa/4.0/legalcode
diff --git a/licenses/copyrights.txt b/licenses/copyrights.txt
new file mode 100644 (file)
index 0000000..8e4d922
--- /dev/null
@@ -0,0 +1,5 @@
+ALl files within this project unless otherwise specified are Copyright Â© 2007-2023 Kevin Day.
+
+Source code and related files are under lgpl-2.1-or-later.
+Specifications and related files are under open-standard-license-1.0-or-later.
+Documentation and related files are under cc-by-sa-4.0.
diff --git a/licenses/lgpl-2.1-or-later b/licenses/lgpl-2.1-or-later
new file mode 100644 (file)
index 0000000..602bfc9
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/licenses/open-standard-license-1.0-or-later b/licenses/open-standard-license-1.0-or-later
new file mode 100644 (file)
index 0000000..d82c79d
--- /dev/null
@@ -0,0 +1,44 @@
+Open Standard License 1.0.
+  February 27, 2024.
+
+This license applies to the Standards and their Specifications and designates legal requirements on Implementations of the Standard and their respective Specifications.
+
+Terminology:
+  - Standard: A set of rules and guidelines.
+  - Specification: A specific interpretation or clarification of a Standard, such as the documentation that describes how to use or follow a Standard.
+  - Implementation: The applying of some Standard or Specification.
+  - API: Application Programming Interface*.
+  - ABI: Application Binary Interface**.
+  - Service: Any action or labor performed by one party for another party (such as one person helping another person).
+  - Protocol: In the context of computers and software, this is a Standard focused on communication between at least two parties (often referring to Internet communication) and is at the most basic level an agreement of rules between two (or more) parties.
+  - Provider: A party who provides a Service of any kind (or equivalent functionality) that utilizes a Protocol or provides a Service that Implements or follows a Standard or Specification to another party.
+
+* The API term is commonly mis-represented as Services or Protocols (such as "Web API" which in actuality should be called "Web Service" or "Web Protocol").
+  An API instructs a party, usually a programmer, on how to use a dependency when programming some software that utilizes said dependency.
+  An API is a Specification of some Implementation of a Standard be it a formally defined Standard or an informally defined Standard.
+  An API may be an Implementation of a Standard or a part of an Implementation of a Standard.
+  An API is, in effect, documentation.
+
+** The ABI term refers to an Application Binary Interface and represents the compiled Implementation of some API.
+  An ABI may not always exist for some API, such as for pure scripting languages.
+  An ABI is neither a Specification nor a Standard.
+  An ABI is an Implementation of an API making it an Implementation of a Standard or Specification.
+
+01) Principles of this license:
+  01) The Standard or Specification is and must be freely and publicly available to use and implement irrespective of any license, patent, or other restriction of any kind for any reason of some Implementation or Provider.
+  02) All patents associated are and must be royalty-free for unrestricted use and must not impose any restrictions on any third party's Implementation of this Standard in any way for any reason beyond those described in this license.
+  03) There are not and there must not be any agreements or requirements for the execution of this license grant, including but not limited to: NDA, grant, click-through, or any form of paperwork (including but not limited to all non-paper forms of paperwork, such as digital forms).
+  04) There are not and must not be any restrictions on the form of an Implementation of a Standard or Specification.
+  05) Implementations of a Standard or Specification may be under any license so long as that license:
+    a) Does not restrict, alter, or invalidate this license in any manner.
+    b) Does not impose any form of restrictions to access, to use, to implement, to extend, or to deviate from anything allowed or otherwise granted by this license.
+  06) This license shall prohibit any form of restricting any parties to access, to use, to implement, to extend, or o deviate from this Standard unless:
+    a) Restricted by this license.
+    b) Unless there is a breach of license conditions.
+  07) This license is irrevocable unless there is a breach of the license conditions.
+  08) This license does not grant any kind of warranty or liability under any circumstances to any party for any reason, be it direct, indirect, consequential, incidental, or in any other form.
+  09) This license does not restrict any party from optionally providing their own warranty or liability on any Implementation but such warranties or liabilities are completely separate and independent of this license in all circumstances for any reason, be it direct, indirect, consequential, incidental, or for any other reason.
+  10) The final and absolute determination of any terminology and intent of this license is by the original owner of this license or a party explicitly authorized by the original license owner or party, and is not in any way subject to re-interpretation or re-definition in any way for any reason by any party including but not limited to judges, juries, lawyers, attorneys, technicians, experts, or governments.
+  11) Any restriction, alteration, removal, invalidation, making illegal, or making unlawful of or against any part of this license by any party, such as but not limited to a government or judge, shall not permanently alter this license in any way for any reason. That is for example, if some court deems some part of this unlawful and then later makes it lawful, then the now re-lawfulized parts do and must immediately apply once more as if it were never made unlawful.
+  12) When at any point in time under any government any parts of this license is restricted, altered, removed, invalidated or otherwise made illegal, unlawful, or unenforceable is reversed, restored, or otherwise made legal, lawful, and enforceable again, then these parts are immediately in affect again.
+  13) If at any point in time some party, such as but not limited to a government, makes any change to this license (like those described in [01.11]) and the licensee for any reason at any time is no longer subject to a given jurisdiction, then those parts of the original license are immediately in effect as if they were never altered or restricted in the first place. For example, if a licensee leaves the jurisdiction of some government that otherwise restricted some part of this license then that otherwise restricted part is immediately in affect again now that the licensee is out of the given jurisdiction.
diff --git a/sources/c/controller/config.c b/sources/c/controller/config.c
new file mode 100644 (file)
index 0000000..1ac2545
--- /dev/null
@@ -0,0 +1 @@
+#include "config.h"
diff --git a/sources/c/controller/config.h b/sources/c/controller/config.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/sources/c/controller/controller.c b/sources/c/controller/controller.c
new file mode 100644 (file)
index 0000000..c421697
--- /dev/null
@@ -0,0 +1,56 @@
+#include "controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_controller_main_
+  void controller_controller_main(controller_main_t * const main) {
+
+    if (!main) return;
+
+    if (F_status_is_error(main->setting.state.status)) {
+      if ((main->setting.flag & controller_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+        fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+      }
+
+      return;
+    }
+
+    if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+      fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+    }
+
+    main->setting.state.status = F_okay;
+
+    if (main->setting.flag & controller_main_flag_version_copyright_help_e) {
+      if (main->setting.flag & controller_main_flag_help_e) {
+        controller_print_message_help(&main->program.message);
+      }
+      else if (main->setting.flag & controller_main_flag_version_e) {
+        fll_program_print_version(&main->program.message, controller_program_version_s);
+      }
+      else if (main->setting.flag & controller_main_flag_copyright_e) {
+        fll_program_print_copyright(&main->program.message);
+      }
+
+      if ((main->setting.flag & controller_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+        fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+      }
+
+      return;
+    }
+
+    if (main->setting.state.status == F_status_set_error(F_interrupt)) {
+      fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
+    }
+
+    if ((main->setting.flag & controller_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+      fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+    }
+  }
+#endif // _di_controller_controller_main_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/controller/controller.h b/sources/c/controller/controller.h
new file mode 100644 (file)
index 0000000..85ada23
--- /dev/null
@@ -0,0 +1,99 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * This program provides an controller base project.
+ *
+ * This program does nothing but can be used as a starting point for new program projects.
+ */
+#ifndef _controller_controller_h
+#define _controller_controller_h
+
+// Libc includes.
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// FLL-0 includes.
+#include <fll/level_0/type.h>
+#include <fll/level_0/status.h>
+#include <fll/level_0/memory.h>
+#include <fll/level_0/string.h>
+#include <fll/level_0/utf.h>
+#include <fll/level_0/color.h>
+#include <fll/level_0/compare.h>
+#include <fll/level_0/console.h>
+#include <fll/level_0/conversion.h>
+#include <fll/level_0/pipe.h>
+#include <fll/level_0/print.h>
+#include <fll/level_0/rip.h>
+#include <fll/level_0/signal.h>
+
+#ifndef _di_thread_support_
+  #include <fll/level_0/thread.h>
+#endif // _di_thread_support_
+
+// FLL-1 includes.
+#include <fll/level_1/conversion.h>
+#include <fll/level_1/print.h>
+
+// FLL-2 includes.
+#include <fll/level_2/error.h>
+#include <fll/level_2/print.h>
+#include <fll/level_2/program.h>
+
+// Controller includes.
+#include <program/controller/main/common/define.h>
+#include <program/controller/main/common/enumeration.h>
+#include <program/controller/main/common/print.h>
+#include <program/controller/main/common/string.h>
+#include <program/controller/main/common/type.h>
+#include <program/controller/main/common.h>
+#include <program/controller/main/print/data.h>
+#include <program/controller/main/print/debug.h>
+#include <program/controller/main/print/error.h>
+#include <program/controller/main/print/message.h>
+#include <program/controller/main/print/verbose.h>
+#include <program/controller/main/print/warning.h>
+#include <program/controller/main/signal.h>
+#include <program/controller/main/thread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Execute main program.
+ *
+ * If main.signal is non-zero, then this blocks and handles the following signals:
+ *   - F_signal_abort
+ *   - F_signal_broken_pipe
+ *   - F_signal_hangup
+ *   - F_signal_interrupt
+ *   - F_signal_quit
+ *   - F_signal_termination
+ *
+ * @param main
+ *   The main program data and settings.
+ *
+ *   This alters main.setting.state.status:
+ *     F_okay on success.
+ *     F_true on success when performing verification and verify passed.
+ *     F_false on success when performing verification and verify failed.
+ *     F_interrupt on (exit) signal received.
+ *
+ *     F_parameter (with error bit) if main is NULL or setting is NULL.
+ */
+#ifndef _di_controller_controller_main_
+  extern void controller_controller_main(controller_main_t * const main);
+#endif // _di_controller_controller_main_
+
+#ifdef _controller_controller_h
+} // extern "C"
+#endif
+
+#endif // _controller_h
diff --git a/sources/c/controller/main.c b/sources/c/controller/main.c
new file mode 100644 (file)
index 0000000..4919f92
--- /dev/null
@@ -0,0 +1,76 @@
+#include "controller.h"
+
+int main(const int argc, const f_string_t *argv, const f_string_t *envp) {
+
+  controller_main_t data = controller_main_t_initialize;
+
+  data.program.debug.flag |= controller_print_flag_debug_e | controller_print_flag_out_e;
+  data.program.error.flag |= controller_print_flag_error_e | controller_print_flag_out_e;
+  data.program.output.flag |= controller_print_flag_out_e;
+  data.program.message.flag |= controller_print_flag_message_e | controller_print_flag_out_e;
+  data.program.warning.flag |= controller_print_flag_warning_e | controller_print_flag_out_e;
+  data.program.error.custom = (void *) &data;
+  data.program.debug.custom = (void *) &data;
+  data.program.message.custom = (void *) &data;
+  data.program.output.custom = (void *) &data;
+  data.program.warning.custom = (void *) &data;
+
+  data.setting.program_name = &controller_program_name_s;
+  data.setting.program_name_long = &controller_program_name_long_s;
+
+  f_console_parameter_t parameters[] = controller_console_parameter_t_initialize;
+
+  data.program.parameters.array = parameters;
+  data.program.parameters.used = controller_parameter_total_d;
+  data.program.environment = envp;
+
+  if (f_pipe_input_exists()) {
+    data.program.pipe = fll_program_data_pipe_input_e;
+  }
+
+  fll_program_standard_set_up(&data.program);
+
+  f_file_umask_get(&data.program.umask);
+
+  #ifdef _di_thread_support_
+    {
+      const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
+
+      controller_setting_load(arguments, &data);
+    }
+
+    controller_main(&data);
+  #else
+    {
+      f_thread_id_t id_signal;
+
+      memset(&id_signal, 0, sizeof(f_thread_id_t));
+
+      data.setting.state.status = f_thread_create(0, &id_signal, &controller_thread_signal, (void *) &data);
+
+      if (F_status_is_error(data.setting.state.status)) {
+        controller_print_error(&data.program.error, macro_controller_f(f_thread_create));
+      }
+      else {
+        {
+          const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
+
+          controller_setting_load(arguments, &data);
+        }
+
+        if (!controller_signal_check(&data)) {
+          controller_main(&data);
+        }
+
+        f_thread_cancel(id_signal);
+        f_thread_join(id_signal, 0);
+      }
+    }
+  #endif // _di_thread_support_
+
+  controller_main_delete(&data);
+
+  fll_program_standard_set_down(&data.program);
+
+  return (F_status_is_error(data.setting.state.status) || data.setting.state.status == F_false) ? 1 : 0;
+}
diff --git a/sources/c/controller/main.h b/sources/c/controller/main.h
new file mode 100644 (file)
index 0000000..7a5afbd
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * This file is only ever included by main/main.c and should not normally be included anywhere else.
+ * Anything that wants to include this should be providing the "controller" program functionality in some manner.
+ */
+#ifndef _controller_controller_main_h
+#define _controller_controller_main_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Standard program entry point.
+ *
+ * @param argc
+ *   The number of arguments.
+ * @param argv
+ *   The array of arguments.
+ * @param envp
+ *   The array of all environment variables on program start.
+ *
+ * @return
+ *   0 on success.
+ *   1 on error.
+ */
+extern int main(const int argc, const f_string_t *argv, const f_string_t *envp);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_controller_main_h
diff --git a/sources/c/init/config.c b/sources/c/init/config.c
new file mode 100644 (file)
index 0000000..1ac2545
--- /dev/null
@@ -0,0 +1 @@
+#include "config.h"
diff --git a/sources/c/init/config.h b/sources/c/init/config.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/sources/c/init/init.c b/sources/c/init/init.c
new file mode 100644 (file)
index 0000000..9c5f4c3
--- /dev/null
@@ -0,0 +1,56 @@
+#include "init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_init_main_
+  void controller_init_main(controller_init_main_t * const main) {
+
+    if (!main) return;
+
+    if (F_status_is_error(main->setting.state.status)) {
+      if ((main->setting.flag & controller_init_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+        fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+      }
+
+      return;
+    }
+
+    if ((main->setting.flag & controller_init_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+      fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+    }
+
+    main->setting.state.status = F_okay;
+
+    if (main->setting.flag & controller_init_main_flag_version_copyright_help_e) {
+      if (main->setting.flag & controller_init_main_flag_help_e) {
+        controller_print_message_help(&main->program.message);
+      }
+      else if (main->setting.flag & controller_init_main_flag_version_e) {
+        fll_program_print_version(&main->program.message, controller_program_version_s);
+      }
+      else if (main->setting.flag & controller_init_main_flag_copyright_e) {
+        fll_program_print_copyright(&main->program.message);
+      }
+
+      if ((main->setting.flag & controller_init_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+        fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+      }
+
+      return;
+    }
+
+    if (main->setting.state.status == F_status_set_error(F_interrupt)) {
+      fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
+    }
+
+    if ((main->setting.flag & controller_init_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+      fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+    }
+  }
+#endif // _di_controller_init_main_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/init/init.h b/sources/c/init/init.h
new file mode 100644 (file)
index 0000000..2517a77
--- /dev/null
@@ -0,0 +1,99 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * This program provides an controller base project.
+ *
+ * This program does nothing but can be used as a starting point for new program projects.
+ */
+#ifndef _controller_init_h
+#define _controller_init_h
+
+// Libc includes.
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// FLL-0 includes.
+#include <fll/level_0/type.h>
+#include <fll/level_0/status.h>
+#include <fll/level_0/memory.h>
+#include <fll/level_0/string.h>
+#include <fll/level_0/utf.h>
+#include <fll/level_0/color.h>
+#include <fll/level_0/compare.h>
+#include <fll/level_0/console.h>
+#include <fll/level_0/conversion.h>
+#include <fll/level_0/pipe.h>
+#include <fll/level_0/print.h>
+#include <fll/level_0/rip.h>
+#include <fll/level_0/signal.h>
+
+#ifndef _di_thread_support_
+  #include <fll/level_0/thread.h>
+#endif // _di_thread_support_
+
+// FLL-1 includes.
+#include <fll/level_1/conversion.h>
+#include <fll/level_1/print.h>
+
+// FLL-2 includes.
+#include <fll/level_2/error.h>
+#include <fll/level_2/print.h>
+#include <fll/level_2/program.h>
+
+// Controller includes.
+#include <program/controller/main/common/define.h>
+#include <program/controller/main/common/enumeration.h>
+#include <program/controller/main/common/print.h>
+#include <program/controller/main/common/string.h>
+#include <program/controller/main/common/type.h>
+#include <program/controller/main/common.h>
+#include <program/controller/main/print/data.h>
+#include <program/controller/main/print/debug.h>
+#include <program/controller/main/print/error.h>
+#include <program/controller/main/print/message.h>
+#include <program/controller/main/print/verbose.h>
+#include <program/controller/main/print/warning.h>
+#include <program/controller/main/signal.h>
+#include <program/controller/main/thread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Execute main program.
+ *
+ * If main.signal is non-zero, then this blocks and handles the following signals:
+ *   - F_signal_abort
+ *   - F_signal_broken_pipe
+ *   - F_signal_hangup
+ *   - F_signal_interrupt
+ *   - F_signal_quit
+ *   - F_signal_termination
+ *
+ * @param main
+ *   The main program data and settings.
+ *
+ *   This alters main.setting.state.status:
+ *     F_okay on success.
+ *     F_true on success when performing verification and verify passed.
+ *     F_false on success when performing verification and verify failed.
+ *     F_interrupt on (exit) signal received.
+ *
+ *     F_parameter (with error bit) if main is NULL or setting is NULL.
+ */
+#ifndef _di_controller_init_main_
+  extern void controller_init_main(controller_init_main_t * const main);
+#endif // _di_controller_init_main_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_init_h
diff --git a/sources/c/init/main.c b/sources/c/init/main.c
new file mode 100644 (file)
index 0000000..85b214b
--- /dev/null
@@ -0,0 +1,76 @@
+#include "init.h"
+
+int main(const int argc, const f_string_t *argv, const f_string_t *envp) {
+
+  controller_main_t data = controller_main_t_initialize;
+
+  data.program.debug.flag |= controller_print_flag_debug_e | controller_print_flag_out_e;
+  data.program.error.flag |= controller_print_flag_error_e | controller_print_flag_out_e;
+  data.program.output.flag |= controller_print_flag_out_e;
+  data.program.message.flag |= controller_print_flag_message_e | controller_print_flag_out_e;
+  data.program.warning.flag |= controller_print_flag_warning_e | controller_print_flag_out_e;
+  data.program.error.custom = (void *) &data;
+  data.program.debug.custom = (void *) &data;
+  data.program.message.custom = (void *) &data;
+  data.program.output.custom = (void *) &data;
+  data.program.warning.custom = (void *) &data;
+
+  data.setting.program_name = &controller_program_name_s;
+  data.setting.program_name_long = &controller_program_name_long_s;
+
+  f_console_parameter_t parameters[] = controller_console_parameter_t_initialize;
+
+  data.program.parameters.array = parameters;
+  data.program.parameters.used = controller_parameter_total_d;
+  data.program.environment = envp;
+
+  if (f_pipe_input_exists()) {
+    data.program.pipe = fll_program_data_pipe_input_e;
+  }
+
+  fll_program_standard_set_up(&data.program);
+
+  f_file_umask_get(&data.program.umask);
+
+  #ifdef _di_thread_support_
+    {
+      const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
+
+      controller_setting_load(arguments, &data);
+    }
+
+    controller_main(&data);
+  #else
+    {
+      f_thread_id_t id_signal;
+
+      memset(&id_signal, 0, sizeof(f_thread_id_t));
+
+      data.setting.state.status = f_thread_create(0, &id_signal, &controller_thread_signal, (void *) &data);
+
+      if (F_status_is_error(data.setting.state.status)) {
+        controller_print_error(&data.program.error, macro_controller_f(f_thread_create));
+      }
+      else {
+        {
+          const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
+
+          controller_setting_load(arguments, &data);
+        }
+
+        if (!controller_signal_check(&data)) {
+          controller_main(&data);
+        }
+
+        f_thread_cancel(id_signal);
+        f_thread_join(id_signal, 0);
+      }
+    }
+  #endif // _di_thread_support_
+
+  controller_main_delete(&data);
+
+  fll_program_standard_set_down(&data.program);
+
+  return (F_status_is_error(data.setting.state.status) || data.setting.state.status == F_false) ? 1 : 0;
+}
diff --git a/sources/c/init/main.h b/sources/c/init/main.h
new file mode 100644 (file)
index 0000000..ec9da3e
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * This file is only ever included by main/main.c and should not normally be included anywhere else.
+ * Anything that wants to include this should be providing the "controller" program functionality in some manner.
+ */
+#ifndef _controller_init_main_h
+#define _controller_init_main_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Standard program entry point.
+ *
+ * @param argc
+ *   The number of arguments.
+ * @param argv
+ *   The array of arguments.
+ * @param envp
+ *   The array of all environment variables on program start.
+ *
+ * @return
+ *   0 on success.
+ *   1 on error.
+ */
+extern int main(const int argc, const f_string_t *argv, const f_string_t *envp);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_init_main_h
diff --git a/sources/c/main/common.c b/sources/c/main/common.c
new file mode 100644 (file)
index 0000000..1f0fa66
--- /dev/null
@@ -0,0 +1,95 @@
+#include "controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_main_setting_load_
+  void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main) {
+
+    if (!main) return;
+
+    main->setting.state.step_small = controller_allocation_console_d;
+
+    f_console_parameter_process(arguments, &main->program.parameters, &main->setting.state, 0);
+
+    main->setting.state.step_small = controller_allocation_small_d;
+
+    if (main->program.parameters.array[f_console_standard_parameter_line_first_no_e].result & f_console_result_found_e) {
+      main->setting.flag &= ~controller_main_flag_print_first_e;
+    }
+    else {
+      main->setting.flag |= controller_main_flag_print_first_e;
+    }
+
+    if (main->program.parameters.array[f_console_standard_parameter_line_last_no_e].result & f_console_result_found_e) {
+      main->setting.flag &= ~controller_main_flag_print_last_e;
+    }
+    else {
+      main->setting.flag |= controller_main_flag_print_last_e;
+    }
+
+    if (F_status_is_error(main->setting.state.status)) {
+      if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+        fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+      }
+
+      controller_print_error(&main->program.error, macro_controller_f(f_console_parameter_process));
+
+      return;
+    }
+
+    main->setting.state.status = fll_program_parameter_process_context_standard(F_true, &main->program);
+
+    if (F_status_is_error(main->setting.state.status)) {
+      if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+        fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+      }
+
+      controller_print_error(&main->program.error, macro_controller_f(fll_program_parameter_process_context_standard));
+
+      return;
+    }
+
+    main->setting.state.status = fll_program_parameter_process_verbosity_standard(F_true, &main->program);
+
+    if (F_status_is_error(main->setting.state.status)) {
+      if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+        fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+      }
+
+      controller_print_error(&main->program.error, macro_controller_f(fll_program_parameter_process_verbosity_standard));
+
+      return;
+    }
+
+    if (main->program.parameters.array[f_console_standard_parameter_help_e].result & f_console_result_found_e) {
+      main->setting.flag |= controller_main_flag_help_e;
+
+      return;
+    }
+
+    if (main->program.parameters.array[f_console_standard_parameter_version_e].result & f_console_result_found_e) {
+      main->setting.flag |= controller_main_flag_version_e;
+
+      return;
+    }
+
+    if (main->program.parameters.array[f_console_standard_parameter_copyright_e].result & f_console_result_found_e) {
+      main->setting.flag |= controller_main_flag_copyright_e;
+
+      return;
+    }
+
+    if (main->program.pipe & fll_program_data_pipe_input_e) {
+      main->setting.flag |= controller_main_flag_pipe_e;
+    }
+    else {
+      main->setting.flag &= ~controller_main_flag_pipe_e;
+    }
+  }
+#endif // _di_controller_main_setting_load_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/common.h b/sources/c/main/common.h
new file mode 100644 (file)
index 0000000..9d1a594
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_h
+#define _controller_main_common_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Perform the standard program setting load process.
+ *
+ * This prints error messages as appropriate.
+ *
+ * If either main or setting is NULL, then this immediately returns without doing anything.
+ *
+ * @param arguments
+ *   The parameters passed to the process (often referred to as command line arguments).
+ * @param main
+ *   The program and settings data.
+ *
+ *   This alters setting.state.status:
+ *     F_okay on success.
+ *
+ *     Errors (with error bit) from: f_console_parameter_process().
+ *     Errors (with error bit) from: fll_program_parameter_process_context().
+ *
+ * @see f_console_parameter_process()
+ * @see fll_program_parameter_process_context()
+ */
+#ifndef _di_controller_main_setting_load_
+  extern void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main);
+#endif // _di_controller_main_setting_load_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_h
diff --git a/sources/c/main/common/define.c b/sources/c/main/common/define.c
new file mode 100644 (file)
index 0000000..61f0547
--- /dev/null
@@ -0,0 +1,9 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/common/define.h b/sources/c/main/common/define.h
new file mode 100644 (file)
index 0000000..8bf7926
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common define types.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_define_h
+#define _controller_main_common_define_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The program allocation defines.
+ *
+ * controller_allocation_*_d:
+ *   - console: An allocation step used for small buffers specifically for console parameter.
+ *   - large:   An allocation step used for buffers that are anticipated to have large buffers.
+ *   - pipe:    A buffer size used for processing piped data.
+ *   - small:   An allocation step used for buffers that are anticipated to have small buffers.
+ */
+#ifndef _di_controller_allocation_d_
+  #define controller_allocation_console_d 4
+  #define controller_allocation_large_d   256
+  #define controller_allocation_pipe_d    16384
+  #define controller_allocation_small_d   16
+#endif // _di_controller_allocation_d_
+
+/**
+ * The program signal defines.
+ *
+ * controller_signal_*_d:
+ *   - check:          Number of iterations before performing signal check in non-threaded signal handling.
+ *   - check_failsafe: When using threads, how many consecutive failures to check signal before aborting (as a recursion failsafe).
+ *   - check_tiny:     The tiny check.
+ *   - check_short:    The short signal check.
+ */
+#ifndef _di_controller_signal_d_
+  #define controller_signal_check_d          500000
+  #define controller_signal_check_failsafe_d 20000
+  #define controller_signal_check_tiny_d     4
+  #define controller_signal_check_short_d    16
+#endif // _di_controller_signal_d_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_define_h
diff --git a/sources/c/main/common/enumeration.c b/sources/c/main/common/enumeration.c
new file mode 100644 (file)
index 0000000..61f0547
--- /dev/null
@@ -0,0 +1,9 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/common/enumeration.h b/sources/c/main/common/enumeration.h
new file mode 100644 (file)
index 0000000..19b272b
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common enumeration types.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_enumeration_h
+#define _controller_main_common_enumeration_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Flags passed to the main function or program.
+ *
+ * When number mode is not specified, then mode is "string" mode (there is no flag for "string" mode).
+ *
+ * controller_main_flag_*_e:
+ *   - none:                   No flags set.
+ *   - copyright:              Print copyright.
+ *   - error:                  Check if status is "error".
+ *   - fine:                   Check if status is "fine".
+ *   - help:                   Print help.
+ *   - pipe:                   Use the input pipe.
+ *   - print_first:            When set, print new line to message output on program begin after loading settings.
+ *   - print_last:             When set, print new line to message output on program end.
+ *   - version:                Print version.
+ *   - version_copyright_help: A helper flag representing version, copyright, and help flag bits being set.
+ *   - warning:                Check if status is "warning".
+ */
+#ifndef _di_controller_main_flag_e_
+  enum {
+    controller_main_flag_none_e                   = 0x0,
+    controller_main_flag_copyright_e              = 0x1,
+    controller_main_flag_error_e                  = 0x2,
+    controller_main_flag_fine_e                   = 0x4,
+    controller_main_flag_help_e                   = 0x8,
+    controller_main_flag_pipe_e                   = 0x10,
+    controller_main_flag_print_first_e            = 0x20,
+    controller_main_flag_print_last_e             = 0x40,
+    controller_main_flag_version_e                = 0x80,
+    controller_main_flag_version_copyright_help_e = 0x89,
+    controller_main_flag_warning_e                = 0x100,
+  }; // enum
+#endif // _di_controller_main_flag_e_
+
+/**
+ * The main program parameters.
+ */
+#ifndef _di_controller_parameter_e_
+  enum {
+    controller_parameter_controller_e = f_console_standard_parameter_last_e,
+  }; // enum
+
+  #define controller_console_parameter_t_initialize \
+    { \
+      macro_fll_program_console_parameter_standard_initialize, \
+      \
+      macro_f_console_parameter_t_initialize_3(controller_short_controller_s, controller_long_controller_s, 0, f_console_flag_normal_e), \
+    }
+
+  #define controller_parameter_total_d (f_console_parameter_state_type_total_d + 1)
+#endif // _di_controller_parameter_e_
+
+/**
+ * Flags for fine-tuned print control.
+ *
+ * controller_print_flag_*_e:
+ *   - none:    No flags set.
+ *   - debug:   Stream is for debug printing.
+ *   - error:   Stream is for error printing.
+ *   - in:      Stream is a source file.
+ *   - message: Stream is for message printing.
+ *   - out:     Stream is a destination file.
+ *   - warning: Stream is for warning printing.
+ */
+#ifndef _di_controller_print_flag_e_
+  enum {
+    controller_print_flag_none_e    = 0x0,
+    controller_print_flag_debug_e   = 0x1,
+    controller_print_flag_error_e   = 0x2,
+    controller_print_flag_file_e    = 0x4,
+    controller_print_flag_in_e      = 0x8,
+    controller_print_flag_out_e     = 0x10,
+    controller_print_flag_message_e = 0x20,
+    controller_print_flag_warning_e = 0x40,
+  }; // enum
+#endif // _di_controller_print_flag_e_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_enumeration_h
diff --git a/sources/c/main/common/print.c b/sources/c/main/common/print.c
new file mode 100644 (file)
index 0000000..484125e
--- /dev/null
@@ -0,0 +1,18 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_f_a_
+  const f_string_t controller_f_a[] = {
+    "f_console_parameter_process",
+    "f_thread_create",
+    "fll_program_parameter_process_context_standard",
+    "fll_program_parameter_process_verbosity_standard",
+  };
+#endif // _di_controller_f_a_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/common/print.h b/sources/c/main/common/print.h
new file mode 100644 (file)
index 0000000..3d48967
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common print functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_print_h
+#define _controller_main_common_print_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A special array of strings intended for representing funciton names.
+ *
+ * These are primarily used for printing errors with the function names.
+ *
+ * The macro macro_controller_f() is used to reference the array index by the enum name.
+ *
+ * macro_controller_f():
+ *   - name: The name of the function.
+ */
+#ifndef _di_controller_f_a_
+  extern const f_string_t controller_f_a[];
+
+  #define macro_controller_f(name) controller_f_a[controller_f_##name##_e]
+#endif // _di_controller_f_a_
+
+/**
+ * An enum representing specific indexes within the above array.
+ *
+ * This is a convenience enum used to make code slightly more readable.
+ */
+#ifndef _di_controller_f_e_
+  enum {
+    controller_f_f_console_parameter_process_e,
+    controller_f_f_thread_create_e,
+    controller_f_fll_program_parameter_process_context_standard_e,
+    controller_f_fll_program_parameter_process_verbosity_standard_e,
+  }; // enum
+#endif // _di_controller_f_e_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_print_h
diff --git a/sources/c/main/common/string.c b/sources/c/main/common/string.c
new file mode 100644 (file)
index 0000000..f69607d
--- /dev/null
@@ -0,0 +1,24 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_program_version_s_
+  const f_string_static_t controller_program_version_s = macro_f_string_static_t_initialize_1(CONTROLLER_program_version_s, 0, CONTROLLER_program_version_s_length);
+#endif // _di_controller_program_version_s_
+
+#ifndef _di_controller_program_name_s_
+  const f_string_static_t controller_program_name_s = macro_f_string_static_t_initialize_1(CONTROLLER_program_name_s, 0, CONTROLLER_program_name_s_length);
+  const f_string_static_t controller_program_name_long_s = macro_f_string_static_t_initialize_1(CONTROLLER_program_name_long_s, 0, CONTROLLER_program_name_long_s_length);
+#endif // _di_controller_program_name_s_
+
+#ifndef _di_controller_parameter_s_
+  const f_string_static_t controller_short_controller_s = macro_f_string_static_t_initialize_1(CONTROLLER_short_controller_s, 0, CONTROLLER_short_controller_s_length);
+
+  const f_string_static_t controller_long_controller_s = macro_f_string_static_t_initialize_1(CONTROLLER_long_controller_s, 0, CONTROLLER_long_controller_s_length);
+#endif // _di_controller_parameter_s_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/common/string.h b/sources/c/main/common/string.h
new file mode 100644 (file)
index 0000000..fff2a1e
--- /dev/null
@@ -0,0 +1,83 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common string structures.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_string_h
+#define _controller_main_common_string_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The program version.
+ */
+#ifndef _di_controller_program_version_s_
+  #define CONTROLLER_program_version_major_s F_string_ascii_0_s
+  #define CONTROLLER_program_version_minor_s F_string_ascii_7_s
+  #define CONTROLLER_program_version_micro_s F_string_ascii_0_s
+
+  #define CONTROLLER_program_version_major_s_length F_string_ascii_0_s_length
+  #define CONTROLLER_program_version_minor_s_length F_string_ascii_7_s_length
+  #define CONTROLLER_program_version_micro_s_length F_string_ascii_0_s_length
+
+  #if !(defined(CONTROLLER_program_version_nano_prefix_s) && defined(CONTROLLER_program_version_nano_prefix_s_length))
+    #define CONTROLLER_program_version_nano_prefix_s
+    #define CONTROLLER_program_version_nano_prefix_s_length 0
+  #endif // !(defined(CONTROLLER_program_version_nano_prefix_s) && defined(CONTROLLER_program_version_nano_prefix_s_length))
+
+  #if !(defined(CONTROLLER_program_version_nano_s) && defined(CONTROLLER_program_version_nano_s_length))
+    #define CONTROLLER_program_version_nano_s
+    #define CONTROLLER_program_version_nano_s_length 0
+  #endif // !(defined(CONTROLLER_program_version_nano_s) && defined(CONTROLLER_program_version_nano_s_length))
+
+  #define CONTROLLER_program_version_s CONTROLLER_program_version_major_s F_string_ascii_period_s CONTROLLER_program_version_minor_s F_string_ascii_period_s CONTROLLER_program_version_micro_s CONTROLLER_program_version_nano_prefix_s CONTROLLER_program_version_nano_s
+
+  #define CONTROLLER_program_version_s_length CONTROLLER_program_version_major_s_length + F_string_ascii_period_s_length + CONTROLLER_program_version_minor_s_length + F_string_ascii_period_s_length + CONTROLLER_program_version_micro_s_length + CONTROLLER_program_version_nano_prefix_s_length + CONTROLLER_program_version_nano_s_length
+
+  extern const f_string_static_t controller_program_version_s;
+#endif // _di_controller_program_version_s_
+
+/**
+ * The program name.
+ */
+#ifndef _di_controller_program_name_s_
+  #define CONTROLLER_program_name_s      "controller"
+  #define CONTROLLER_program_name_long_s "Controller"
+
+  #define CONTROLLER_program_name_s_length      10
+  #define CONTROLLER_program_name_long_s_length 10
+
+  extern const f_string_static_t controller_program_name_s;
+  extern const f_string_static_t controller_program_name_long_s;
+#endif // _di_controller_program_name_s_
+
+/**
+ * The main program parameters.
+ */
+#ifndef _di_controller_parameter_s_
+  #define CONTROLLER_short_controller_s "e"
+
+  #define CONTROLLER_long_controller_s "controller"
+
+  #define CONTROLLER_short_controller_s_length 1
+
+  #define CONTROLLER_long_controller_s_length 7
+
+  extern const f_string_static_t controller_short_controller_s;
+
+  extern const f_string_static_t controller_long_controller_s;
+#endif // _di_controller_parameter_s_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_string_h
diff --git a/sources/c/main/common/type.c b/sources/c/main/common/type.c
new file mode 100644 (file)
index 0000000..f3101a4
--- /dev/null
@@ -0,0 +1,35 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_cache_delete_
+  void controller_cache_delete(controller_cache_t * const cache) {
+
+    if (!cache) return;
+
+    f_memory_array_resize(0, sizeof(f_char_t), (void **) &cache->buffer.string, &cache->buffer.used, &cache->buffer.size);
+  }
+#endif // _di_controller_cache_delete_
+
+#ifndef _di_controller_main_delete_
+  void controller_main_delete(controller_main_t * const main) {
+
+    if (!main) return;
+
+    fll_program_data_delete(&main->program);
+    controller_setting_delete(&main->setting);
+  }
+#endif // _di_controller_main_delete_
+
+#ifndef _di_controller_setting_delete_
+  void controller_setting_delete(controller_setting_t * const setting) {
+
+    if (!setting) return;
+  }
+#endif // _di_controller_setting_delete_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/common/type.h b/sources/c/main/common/type.h
new file mode 100644 (file)
index 0000000..4a9bd23
--- /dev/null
@@ -0,0 +1,138 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common type structures.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_type_h
+#define _controller_main_common_type_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The controller main program cache.
+ *
+ * buffer: A generic buffer.
+ */
+#ifndef _di_controller_cache_t_
+  typedef struct {
+    f_string_dynamic_t buffer;
+  } controller_cache_t;
+
+  #define controller_cache_t_initialize \
+    { \
+      f_string_dynamic_t_initialize, \
+    }
+#endif // _di_controller_cache_t_
+
+/**
+ * The controller main program settings.
+ *
+ * This is passed to the program-specific main entry point to designate program settings.
+ * These program settings are often processed from the program arguments (often called the command line arguments).
+ *
+ * flag: Flags passed to the main function.
+ *
+ * status_signal: A status used eclusively by the threaded signal handler.
+ * state:         The state data used when processing the FSS data.
+ */
+#ifndef _di_controller_setting_t_
+  typedef struct {
+    uint16_t flag;
+
+    f_status_t status_signal;
+    f_state_t state;
+
+    const f_string_static_t *program_name;
+    const f_string_static_t *program_name_long;
+  } controller_setting_t;
+
+  #define controller_setting_t_initialize \
+    { \
+      controller_main_flag_none_e, \
+      F_okay, \
+      f_state_t_initialize, \
+      0, \
+      0, \
+    }
+#endif // _di_controller_setting_t_
+
+/**
+ * The main program data as a single structure.
+ *
+ * program: The main program data.
+ * setting: The settings data.
+ */
+#ifndef _di_controller_main_t_
+  typedef struct {
+    fll_program_data_t program;
+    controller_setting_t setting;
+    controller_cache_t cache;
+  } controller_main_t;
+
+  #define controller_main_t_initialize \
+    { \
+      fll_program_data_t_initialize, \
+      controller_setting_t_initialize, \
+      controller_cache_t_initialize, \
+    }
+#endif // _di_controller_main_t_
+
+/**
+ * Deallocate main program data.
+ *
+ * @param cache
+ *   The program cache.
+ *
+ *   Must not be NULL.
+ *
+ * @see f_memory_array_resize()
+ */
+#ifndef _di_controller_cache_delete_
+  extern void controller_cache_delete(controller_cache_t * const cache);
+#endif // _di_controller_cache_delete_
+
+/**
+ * Deallocate main program data.
+ *
+ * @param main
+ *   The main program data.
+ *
+ *   Must not be NULL.
+ *
+ *   This does not alter main.setting.state.status.
+ *
+ * @see controller_cache_delete()
+ * @see controller_setting_delete()
+ * @see fll_program_data_delete()
+ */
+#ifndef _di_controller_main_delete_
+  extern void controller_main_delete(controller_main_t * const main);
+#endif // _di_controller_main_delete_
+
+/**
+ * Delete the program main setting data.
+ *
+ * @param setting
+ *   The program main setting data.
+ *
+ *   Must not be NULL.
+ *
+ *   This does not alter setting.state.status.
+ */
+#ifndef _di_controller_setting_delete_
+  extern void controller_setting_delete(controller_setting_t * const setting);
+#endif // _di_controller_setting_delete_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_type_h
diff --git a/sources/c/main/controller.h b/sources/c/main/controller.h
new file mode 100644 (file)
index 0000000..16e3257
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * This program provides an controller base project.
+ *
+ * This program does nothing but can be used as a starting point for new program projects.
+ */
+#ifndef _controller_h
+#define _controller_h
+
+// Libc includes.
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// FLL-0 includes.
+#include <fll/level_0/type.h>
+#include <fll/level_0/status.h>
+#include <fll/level_0/memory.h>
+#include <fll/level_0/string.h>
+#include <fll/level_0/utf.h>
+#include <fll/level_0/color.h>
+#include <fll/level_0/compare.h>
+#include <fll/level_0/console.h>
+#include <fll/level_0/conversion.h>
+#include <fll/level_0/pipe.h>
+#include <fll/level_0/print.h>
+#include <fll/level_0/rip.h>
+#include <fll/level_0/signal.h>
+
+#ifndef _di_thread_support_
+  #include <fll/level_0/thread.h>
+#endif // _di_thread_support_
+
+// FLL-1 includes.
+#include <fll/level_1/conversion.h>
+#include <fll/level_1/print.h>
+
+// FLL-2 includes.
+#include <fll/level_2/error.h>
+#include <fll/level_2/print.h>
+#include <fll/level_2/program.h>
+
+// Controller includes.
+#include <program/controller/main/common/define.h>
+#include <program/controller/main/common/enumeration.h>
+#include <program/controller/main/common/print.h>
+#include <program/controller/main/common/string.h>
+#include <program/controller/main/common/type.h>
+#include <program/controller/main/common.h>
+#include <program/controller/main/print/data.h>
+#include <program/controller/main/print/debug.h>
+#include <program/controller/main/print/error.h>
+#include <program/controller/main/print/message.h>
+#include <program/controller/main/print/verbose.h>
+#include <program/controller/main/print/warning.h>
+#include <program/controller/main/signal.h>
+#include <program/controller/main/thread.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_h
diff --git a/sources/c/main/print/data.c b/sources/c/main/print/data.c
new file mode 100644 (file)
index 0000000..61f0547
--- /dev/null
@@ -0,0 +1,9 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/print/data.h b/sources/c/main/print/data.h
new file mode 100644 (file)
index 0000000..17ef811
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print data functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_data_h
+#define _controller_main_print_data_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_data_h
diff --git a/sources/c/main/print/debug.c b/sources/c/main/print/debug.c
new file mode 100644 (file)
index 0000000..61f0547
--- /dev/null
@@ -0,0 +1,9 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/print/debug.h b/sources/c/main/print/debug.h
new file mode 100644 (file)
index 0000000..1eb6491
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print debug functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_debug_h
+#define _controller_main_print_debug_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_debug_h
diff --git a/sources/c/main/print/error.c b/sources/c/main/print/error.c
new file mode 100644 (file)
index 0000000..23a2be1
--- /dev/null
@@ -0,0 +1,23 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_main_print_error_
+  f_status_t controller_main_print_error(fl_print_t * const print, const f_string_t function) {
+
+    if (!print || !print->custom) return F_status_set_error(F_output_not);
+    if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
+
+    controller_main_t * const main = (controller_main_t *) print->custom;
+
+    fll_error_print(print, F_status_set_fine(main->setting.state.status), function, fll_error_file_flag_fallback_e);
+
+    return F_okay;
+  }
+#endif // _di_controller_main_print_error_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/print/error.h b/sources/c/main/print/error.h
new file mode 100644 (file)
index 0000000..3f67c87
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print error functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_error_h
+#define _controller_main_print_error_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Print generic error message regarding a function failing in some way.
+ *
+ * @param print
+ *   The output structure to print to.
+ *
+ *   This does not alter print.custom.setting.state.status.
+ * @param function
+ *   The name of the function associated with the error.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_print()
+ */
+#ifndef _di_controller_main_print_error_
+  extern f_status_t controller_main_print_error(fl_print_t * const print, const f_string_t function);
+#endif // _di_controller_main_print_error_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_error_h
diff --git a/sources/c/main/print/message.c b/sources/c/main/print/message.c
new file mode 100644 (file)
index 0000000..1a2a127
--- /dev/null
@@ -0,0 +1,36 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_main_print_message_help_
+  f_status_t controller_main_print_message_help(fl_print_t * const print) {
+
+    if (!print) return F_status_set_error(F_output_not);
+
+    f_file_stream_lock(print->to);
+
+    fll_program_print_help_header(print, controller_program_name_long_s, controller_program_version_s);
+
+    fll_program_print_help_option_standard(print);
+
+    f_print_dynamic_raw(f_string_eol_s, print->to);
+
+    fll_program_print_help_option(print, controller_short_controller_s, controller_long_controller_s, f_console_symbol_short_normal_s, f_console_symbol_long_normal_s, "This is an controller program parameter.");
+
+    f_print_dynamic_raw(f_string_eol_s, print->to);
+
+    fll_program_print_help_usage(print, controller_program_name_s, f_string_empty_s);
+
+    f_file_stream_flush(print->to);
+    f_file_stream_unlock(print->to);
+
+    return F_okay;
+  }
+#endif // _di_controller_main_print_message_help_
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/print/message.h b/sources/c/main/print/message.h
new file mode 100644 (file)
index 0000000..3be5523
--- /dev/null
@@ -0,0 +1,51 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print message functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_message_h
+#define _controller_main_print_message_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Print help.
+ *
+ * @param print
+ *   The output structure to print to.
+ *
+ *   This requires print.custom to be controller_main_t.
+ *
+ *   This does not alter print.custom.setting.state.status.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see f_file_stream_flush()
+ * @see f_file_stream_lock()
+ * @see f_file_stream_unlock()
+ * @see f_print_dynamic_raw()
+ * @see fll_program_print_help_header()
+ * @see fll_program_print_help_option()
+ * @see fll_program_print_help_usage()
+ */
+#ifndef _di_controller_main_print_message_help_
+  extern f_status_t controller_main_print_message_help(fl_print_t * const print);
+#endif // _di_controller_main_print_message_help_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_message_h
diff --git a/sources/c/main/print/verbose.c b/sources/c/main/print/verbose.c
new file mode 100644 (file)
index 0000000..61f0547
--- /dev/null
@@ -0,0 +1,9 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/print/verbose.h b/sources/c/main/print/verbose.h
new file mode 100644 (file)
index 0000000..0cab65e
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print verbose functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_verbose_h
+#define _controller_main_print_verbose_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_verbose_h
diff --git a/sources/c/main/print/warning.c b/sources/c/main/print/warning.c
new file mode 100644 (file)
index 0000000..61f0547
--- /dev/null
@@ -0,0 +1,9 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/print/warning.h b/sources/c/main/print/warning.h
new file mode 100644 (file)
index 0000000..654e77f
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print warning functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_warning_h
+#define _controller_main_print_warning_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_warning_h
diff --git a/sources/c/main/signal.c b/sources/c/main/signal.c
new file mode 100644 (file)
index 0000000..00bdd7a
--- /dev/null
@@ -0,0 +1,111 @@
+#include "controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_di_controller_main_signal_check_) && defined(_di_thread_support_)
+  f_status_t controller_main_signal_check(controller_main_t * const main) {
+
+    if (!main || main->program.signal.id == -1) return F_false;
+
+    if (!((++main->program.signal_check) % controller_main_signal_check_d)) {
+      if (fll_program_standard_signal_received(&main->program)) {
+        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
+
+        main->setting.state.status = F_status_set_error(F_interrupt);
+
+        return F_true;
+      }
+
+      main->program.signal_check = 0;
+    }
+
+    return F_false;
+  }
+#endif // !defined(_di_controller_main_signal_check_) && defined(_di_thread_support_)
+
+#if !defined(_di_controller_main_signal_check_) && !defined(_di_thread_support_)
+  f_status_t controller_main_signal_check(controller_main_t * const main) {
+
+    if (!main || main->program.signal.id == -1) return F_false;
+
+    if (main->program.signal_received) {
+      fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
+
+      main->setting.state.status = F_status_set_error(F_interrupt);
+
+      return F_true;
+    }
+
+    return F_false;
+  }
+#endif // !defined(_di_controller_main_signal_check_) && !defined(_di_thread_support_)
+
+#if !defined(_di_controller_main_signal_handler_) && !defined(_di_thread_support_)
+  void controller_main_signal_handler(controller_main_t * const main) {
+
+    if (!main) return;
+
+    siginfo_t information;
+    f_number_unsigned_t failsafe = 0;
+
+    memset(&information, 0, sizeof(siginfo_t));
+
+    main->program.signal_received = 0;
+
+    f_signal_set_empty(&main->program.signal.set);
+    f_signal_set_add(F_signal_abort, &main->program.signal.set);
+    f_signal_set_add(F_signal_broken_pipe, &main->program.signal.set);
+    f_signal_set_add(F_signal_hangup, &main->program.signal.set);
+    f_signal_set_add(F_signal_interrupt, &main->program.signal.set);
+    f_signal_set_add(F_signal_quit, &main->program.signal.set);
+    f_signal_set_add(F_signal_termination, &main->program.signal.set);
+
+    if (main->program.signal.id == -1) {
+      main->setting.status_signal = f_signal_open(&main->program.signal);
+
+      if (F_status_is_error(main->setting.status_signal)) {
+        main->program.signal_received = F_signal_abort;
+
+        return;
+      }
+    }
+
+    do {
+      memset(&information, 0, sizeof(siginfo_t));
+
+      main->setting.status_signal = f_signal_wait(&main->program.signal.set, &information);
+
+      if (F_status_is_error(main->setting.status_signal) && F_status_set_fine(main->setting.status_signal) != F_interrupt) {
+        if (++failsafe >= controller_main_signal_check_failsafe_d) break;
+      }
+
+      switch (information.si_signo) {
+        case F_signal_abort:
+        case F_signal_broken_pipe:
+        case F_signal_hangup:
+        case F_signal_interrupt:
+        case F_signal_quit:
+        case F_signal_termination:
+          main->program.signal_received = information.si_signo;
+
+          break;
+      }
+
+      failsafe = 0;
+      main->setting.status_signal = F_okay;
+
+    } while (!main->program.signal_received);
+
+    f_signal_close(&main->program.signal);
+
+    if (F_status_is_error(main->setting.status_signal)) {
+      main->program.signal_received = F_signal_abort;
+    }
+  }
+#endif // !defined(_di_controller_main_signal_handler_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/signal.h b/sources/c/main/signal.h
new file mode 100644 (file)
index 0000000..404caca
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides signal functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_signal_h
+#define _controller_main_signal_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Check to see if a signal is received.
+ *
+ * If main.signal is non-zero, then this handles the following signals:
+ *   - F_signal_abort
+ *   - F_signal_broken_pipe
+ *   - F_signal_hangup
+ *   - F_signal_interrupt
+ *   - F_signal_quit
+ *   - F_signal_termination
+ *
+ * There is a threaded and a non-threaded version of this.
+ * The non-threaded version checks periodically using controller_main_signal_check_d and updates main->signal_check as needed.
+ * The threaded version checks the flag state which is set by a separate thread that is blocking until signal is received.
+ *
+ * @param main
+ *   The main program and settings data.
+ *
+ *   This does not alter main.setting.state.status.
+ *
+ * @return
+ *   F_true on signal received.
+ *   F_false otherwise.
+ *
+ * @see controller_main_signal_handler()
+ *
+ * @see fll_program_standard_signal_received()
+ */
+#ifndef _di_controller_main_signal_check_
+  extern f_status_t controller_main_signal_check(controller_main_t * const main);
+#endif // _di_controller_main_signal_check_
+
+/**
+ * Signal handler for signals/interrupts.
+ *
+ * This blocks until an expected signal is recieved.
+ * When an expected signal is received it then sets the
+ *
+ * If main.signal is non-zero, then this handles the following signals:
+ *   - F_signal_abort
+ *   - F_signal_broken_pipe
+ *   - F_signal_hangup
+ *   - F_signal_interrupt
+ *   - F_signal_quit
+ *   - F_signal_termination
+ *
+ * @param main
+ *   The main program and settings data.
+ *
+ *   This alters main.program.signal_received, setting it to a received signal.
+ *
+ *   This alters main.setting.state.status:
+ *     Errors (with error bit) from: f_signal_open()
+ *     Errors (with error bit) from: f_signal_wait()
+ *
+ * @see f_signal_close()
+ * @see f_signal_open()
+ * @see f_signal_wait()
+ */
+#if !defined(_di_controller_main_signal_handler_) && !defined(_di_thread_support_)
+  extern void controller_main_signal_handler(controller_main_t * const main);
+#endif // !defined(_di_controller_main_signal_handler_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_signal_h
diff --git a/sources/c/main/thread.c b/sources/c/main/thread.c
new file mode 100644 (file)
index 0000000..0564d20
--- /dev/null
@@ -0,0 +1,22 @@
+#include "controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
+  void * controller_main_thread_signal(void * const main) {
+
+    f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+
+    if (main) {
+      controller_signal_handler((controller_main_t *) main);
+    }
+
+    return 0;
+  }
+#endif // !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/thread.h b/sources/c/main/thread.h
new file mode 100644 (file)
index 0000000..df7fe9e
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides thread functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_thread_h
+#define _controller_main_thread_h
+
+/**
+ * Thread handler for signals/interrupts.
+ *
+ * If main.signal is non-zero, then this handles the following signals:
+ *   - F_signal_abort
+ *   - F_signal_broken_pipe
+ *   - F_signal_hangup
+ *   - F_signal_interrupt
+ *   - F_signal_quit
+ *   - F_signal_termination
+ *
+ * @param main
+ *   The program and settings data.
+ *
+ *   Must be of type controller_main_t.
+ *
+ * @return
+ *   0, always.
+ *
+ * @see f_thread_cancel_state_set()
+ *
+ * @see controller_signal_handler()
+ */
+#if !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
+  extern void * controller_main_thread_signal(void * const main);
+#endif // !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_thread_h
diff --git a/specifications/entry.txt b/specifications/entry.txt
new file mode 100644 (file)
index 0000000..92ceeea
--- /dev/null
@@ -0,0 +1,145 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named entry.txt) can be more easily read using the following iki_read commands:
+#   iki_read entry.txt +Q -w -W code '"' '"'
+#
+# To read the "Entry Specification" section of this file, use this command sequence:
+#   fss_basic_list_read entry.txt +Q -cn "Entry Specification" | iki_read +Q -w -W code '"' '"'
+#
+
+Entry Specification:
+  The Entry files follow the code:"FSS-0005 (Somewhat Basic List)" format.
+
+  An Entry file name is expected to have the file extension code:".entry".
+
+  For each Entry file\:
+    - The outer most part is a code:"FSS-0002 (Basic List)".
+    - The Basic List Object is considered the code:"Item".
+    - The Basic List Content are considered the code:"Actions".
+    - The code:"Actions" are code:"FSS-0001 (Extended)".
+    - Each Action Object is the code:"Action Name".
+    - Each Action Content are the code:"Action Parameters".
+
+  The Items\:
+    - code:"main": required.
+
+    - code:"settings": optional, Actions may be one of\:
+      - code:"control": One to two Content.
+        The first Content is a relative or absolute path to a socket file.
+        The second Content an optional code:"readonly".
+      - code:"control_group": Exactly one Content that is a group name or group id.
+      - code:"control_mode": Exactly one Content that is a valid file mode.
+      - code:"control_user": Exactly one Content that is a user name or user id.
+      - code:"define": Two Content, the first Content must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits).
+      - code:"mode": Exactly one Content that is one of code:"helper", code:"program", or code:"service".
+      - code:"parameter": Two Content, the first Content must be a case-sensitive valid IKI name and the second being an IKI value.
+      - code:"pid": Exactly one Content that is one of code:"disable", code:"require", or code:"ready".
+      - code:"pid_file": Exactly one Content that is a relative or absolute path to a pid file.
+      - code:"session": Exactly one Content that is one of code:"new" or code:"same".
+      - code:"show": Exactly one Content that is one of code:"normal" or code:"init".
+      - code:"timeout": One or two content with the first being one of code:"exit", code:"start", code:"stop", or code:"kill" and the (optional) second Content being a positive whole number or 0.
+
+    The Entry file may have any other valid Item Objects, but only the above are reserved.
+
+    The Actions\:
+      - code:"consider": One or more Content.
+        The first Content is the relative file path (without any leading/trailing slashes and without file extension).
+        The second Content is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"execute": One or more Content.
+        The first Content is the program name or full path to the program (the program may be a script).
+        All remaining Content are passed as parameters to the program being executed.
+
+      - code:"failsafe": One Content that is a valid Object name, except for the reserved code:"main".
+
+      - code:"freeze": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"item": One Content that is a valid Object name, except for the reserved code:"main".
+
+      - code:"kill": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"pause": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"ready": Zero or One Content.
+        The first may only be one of\:
+        - code:"wait"
+
+      - code:"reload": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"restart": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"resume": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"start": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"stop": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"thaw": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"timeout": One or two Content.
+        The first being one of\:
+          - code:"exit"
+          - code:"start"
+          - code:"stop"
+          - code:"kill"
+        The (optional) second Content being a positive whole number or 0.
diff --git a/specifications/exit.txt b/specifications/exit.txt
new file mode 100644 (file)
index 0000000..83ab08f
--- /dev/null
@@ -0,0 +1,131 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named exit.txt) can be more easily read using the following iki_read commands:
+#   iki_read exit.txt +Q -w -W code '"' '"'
+#
+# To read the "Exit Specification" section of this file, use this command sequence:
+#   fss_basic_list_read exit.txt +Q -cn "Exit Specification" | iki_read +Q -w -W code '"' '"'
+#
+
+Exit Specification:
+  The Exit files follow the code:"FSS-0005 (Somewhat Basic List)" format.
+
+  An Exit file name is expected to have the file extension code:".exit".
+
+  For each Exit file\:
+    - The outer most part is a code:"FSS-0002 (Basic List)".
+    - The Basic List Object is considered the code:"Item".
+    - The Basic List Content are considered the code:"Actions".
+    - The code:"Actions" are code:"FSS-0001 (Extended)".
+    - Each Action Object is the code:"Action Name".
+    - Each Action Content are the code:"Action Parameters".
+
+  The Items\:
+    - code:"main": required.
+
+    - code:"settings": optional, Actions may be one of\:
+      - code:"pid": Exactly one Content that is one of code:"disable", code:"require", or code:"ready".
+      - code:"session": Exactly one Content that is one of  code:"new" or code:"same".
+      - code:"show": Exactly one Content that is one of  code:"normal" or code:"init".
+      - code:"timeout": One or Two content with the first being one of code:"exit", code:"start", code:"stop", or code:"kill" and the (optional) second Content being a positive whole number or 0.
+
+    The Exit file may have any other valid Item Objects, but only the above are reserved.
+
+    The Actions\:
+      - code:"consider": One or more Content.
+        The first Content that is the relative file path (without any leading/trailing slashes and without file extension).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"failsafe": One Content that is a valid Object name, except for the reserved code:"main".
+
+      - code:"freeze": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"item": One Content that is a valid Object name, except for the reserved code:"main".
+
+      - code:"kill": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"pause": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"ready": Zero or One Content.
+        The first may only be one of\:
+        - code:"wait"
+
+      - code:"reload": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"restart": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"resume": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"start": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"stop": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"thaw": Two or more Content.
+        The first Content that is the relative directory path (without any leading/trailing slashes).
+        The second Content that is the basename for a rule file.
+        The third and beyond may only be one of\:
+          - code:"asynchronous"
+          - code:"require"
+          - code:"wait"
+
+      - code:"timeout": Two Content.
+        The first being one of\:
+          - code:"exit"
+          - code:"start"
+          - code:"stop"
+          - code:"kill"
+        The (optional) second Content being a positive whole number or 0.
diff --git a/specifications/packet.txt b/specifications/packet.txt
new file mode 100644 (file)
index 0000000..b76ee3e
--- /dev/null
@@ -0,0 +1,61 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named packet.txt) can be more easily read using the following iki_read commands:
+#   iki_read packet.txt +Q -w -W code '"' '"'
+#
+# To read the "Packet Specification" section of this file, use this command sequence:
+#   fss_basic_list_read packet.txt +Q -cn "Packet Specification" | iki_read +Q -w -W code '"' '"'
+#
+
+Packet Specification:
+  The controller program communicates use the code:"FSS-000F (Packet)".
+  This specification declares how the Payload Block, which is in code:"FSS-000E (Payload)" format, is required to be used.
+
+  Only a single code:"header" is allowed.
+  Only a single code:"payload" is allowed.
+
+  Packet Structure\:
+    Packet is grouped into the following blocks\:
+      - code:"control": A single 1-byte block representing control codes.
+      - code:"size": A single 4-byte block representing the size of the entire packet, including the control block.
+
+  The code:"header" Object contains the following code:"FSS-0001 (Extended)" Objects (depending on code:"type")\:
+    - code:"action": A valid action type: code:"freeze", code:"kexec", code:"kill", code:"pause", code:"reboot", code:"reload", code:"rerun", code:"restart", code:"resume", code:"shutdown", code:"start", code:"stop", or code:"thaw".
+    - code:"length": A positive whole number inclusively between 0 and 4294965248 representing the length of the code:"payload" (may be in binary, octal, decimal, duodecimal, or hexidecimal).
+    - code:"status": The status code name or number representing an FSS status code, such as F_okay, F_failure, or 200 (where a number may have error and warning bits and may be in binary, octal, decimal, duodecimal, or hexidecimal).
+    - code:"type": The packet type that is one of code:"controller", code:"error", or code:"init".
+
+  When there are multiple Objects of the same name inside the code:"header"\:
+    - code:"action": The order represents the order in which the actions are performed.
+    - code:"length": There may only be one length Object, all others after the first are ignored (may be in binary, octal, decimal, duodecimal, or hexidecimal).
+    - code:"status": A status for each action, in the same order as the order of the action, such as F_okay, F_failure, or 200 (where a number may have error and warning bits and may be in binary, octal, decimal, duodecimal, or hexidecimal).
+    - code:"type": The first represent the type and all others represents a sub-type.
+
+  There are different headers and payload properties based on the code:"type".
+
+  The code:"controller" type\:
+    Supports the following headers: code:"action", code:"length", code:"status", and code:"type".
+
+    Only a single code:"action" may be provided and must exist for request and response packets.
+    Only a single code:"status" may be provided and must exist for response packets.
+
+    The code:"payload" is dependent on the code:"action".
+
+  The code:"error" type\:
+    Supports the following headers: code:"length", code:"status", and code:"type".
+
+    Only a single code:"status" may be provided and must exist for request and response packets.
+
+    The code:"payload" is a NULL terminated string whose length is defined by the code:"length" code:"header" Content.
+
+  There are different headers and payload properties based on the code:"type".
+
+  The code:"init" type\:
+    Supports the following headers: code:"action", code:"length", code:"status", and code:"type".
+
+    Only a single code:"action" may be provided and must exist for request and response packets.
+    Only a single code:"status" may be provided and must exist for response packets.
+
+    The code:"payload" is dependent on the code:"action".
diff --git a/specifications/rule.txt b/specifications/rule.txt
new file mode 100644 (file)
index 0000000..8ea846e
--- /dev/null
@@ -0,0 +1,102 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named rule.txt) can be more easily read using the following iki_read commands:
+#   iki_read rule.txt +Q -w -W code '"' '"'
+#
+# To read the "Rule Specification" section of this file, use this command sequence:
+#   fss_basic_list_read rule.txt +Q -cn "Rule Specification" | iki_read +Q -w -W code '"' '"'
+#
+
+Rule Specification:
+  The Rule files follow the code:"FSS-000D (Basic Rule)" format with bold:"IKI-0000 (Unrestricted)".
+
+  A Rule file name is expected to have the file extension code:".rule".
+
+  For each Rule file\:
+    - The outer most part is a code:"FSS-0002 (Basic List)".
+    - The Basic List Object is considered the code:"Rule Type".
+    - The Basic List Content is determined by the specific code:"Rule Type".
+    - The Content for each code:"Rule Type" is called the code:"Item".
+    - Each Item Object is the code:"Item Name".
+    - Each Item Content is either the code:"Action" or the code:"Setting".
+    - Each Action Object is the code:"Action Name".
+    - Each Action Content are the code:"Action Parameters".
+    - Each Setting Object is the code:"Setting Name".
+    - Each Setting Content are the code:"Setting Values".
+
+  The Rule Types\:
+    - code:"command": Follows either code:"FSS-0003 (Extended List)" or code:"FSS-0001 (Extended)".
+    - code:"script": Follows either code:"FSS-0003 (Extended List)" or code:"FSS-0001 (Extended)".
+    - code:"service": Follows either code:"FSS-0003 (Extended List)" or code:"FSS-0001 (Extended)".
+    - code:"settings": Is required and follows either  code:"FSS-0001 (Extended)".
+    - code:"utility": Follows either code:"FSS-0003 (Extended List)" or code:"FSS-0001 (Extended)".
+
+  For the above Rule Types, code:"settings" may be specified only once whereas the others may be specifed multiple times.
+  The code:"settings" Rule Type is always processed first, regardless of position.
+  The other Rule Types are processed top-down.
+
+  The code:"settings" Rule Type has the following code:"FSS-0001 (Extended)"\:
+    - code:"affinity": One or more Content, each must be a 0 or greater whole number.
+    - code:"capability": One Content representing capabilities.
+    - code:"cgroup": Two or more Content, the first Content being either code:"existing" or code:"new" and the remaining representing a valid cgroup (control group) name, must have at least 1 graph character (non white space printing character) (leading and trailing white space are trimmed off).
+    - code:"define": Two Content, the first Content must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits).
+    - code:"engine": One or more Content representing a valid program name or path (such as code:"bash" or code:"/bin/bash") and any optional arguments.
+    - code:"environment": Zero or more Content, each must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits).
+    - code:"group": One or more Content representing group names or group ids.
+    - code:"limit": Three Content, with the first representing a valid resource type and the second and third being a valid resource limit number (positive whole number or 0).
+    - code:"name": One Content, must have at least 1 graph character (non white space printing character) (leading and trailing white space are trimmed off).
+    - code:"nice": One Content, must be a valid number for process code:"niceness" (Any whole number inclusively between -20 to 19).
+    - code:"on": Four Content, the first being a Rule Action, the second being code:"need", code:"want", or code:"wish", the third being a partial path, and the fourth being a Rule file name without code:".rule" extension.
+    - code:"parameter": Two Content, the first Content must be a case-sensitive valid IKI name and the second being an IKI value.
+    - code:"path": One Content representing a valid code:"PATH" environment string (such as code:"/bin:/sbin:/usr/bin").
+    - code:"scheduler": One or two Content representing a scheduler name and the optional numeric priority (Any whole number inclusively between 0 and 99).
+    - code:"timeout": One or two content with the first being one of code:"exit", code:"start", code:"stop", or code:"kill" and the (optional) second Content being a positive whole number or 0.
+    - code:"user": One Content representing a user name or user id.
+
+  The code:"command" and code:"script" Rule Types allow the following the code:"FSS-0001 (Extended)"\:
+    - code:"freeze": One or more Content representing a program being executed and its arguments.
+    - code:"kill": One or more Content representing a program being executed and its arguments.
+    - code:"pause": One or more Content representing a program being executed and its arguments.
+    - code:"reload": One or more Content representing a program being executed and its arguments.
+    - code:"rerun": Two or more Content representing a Rule type that executes and its properties.
+    - code:"restart": One or more Content representing a program being executed and its arguments.
+    - code:"resume": One or more Content representing a program being executed and its arguments.
+    - code:"start": One or more Content representing a program being executed and its arguments.
+    - code:"stop": One or more Content representing a program being executed and its arguments.
+    - code:"thaw": One or more Content representing a program being executed and its arguments.
+    - code:"with": One or more Content representing special options for the Rule Type.
+
+  The code:"service" and code:"utility" Rule Types allow the following the code:"FSS-0001 (Extended)"\:
+    - code:"pid_file": One Content representing the path to a PID file.
+    - code:"rerun": Two or more Content representing a Rule type that executes and its properties.
+    - code:"with": One or more Content being one of code:"full_path", code:"session_new", or code:"session_same".
+
+  The code:"command" and code:"service" Rule Types allow the following the code:"FSS-0003 (Extended List)"\:
+    - code:"freeze": A list repesenting multiple programs and their respective arguments to execute.
+    - code:"kill": A list repesenting multiple programs and their respective arguments to execute.
+    - code:"pause": A list repesenting multiple programs and their respective arguments to execute.
+    - code:"reload": A list repesenting multiple programs and their respective arguments to execute.
+    - code:"restart": A list repesenting multiple programs and their respective arguments to execute.
+    - code:"resume": A list repesenting multiple programs and their respective arguments to execute.
+    - code:"start": A list repesenting multiple programs and their respective arguments to execute.
+    - code:"stop": A list repesenting multiple programs and their respective arguments to execute.
+    - code:"thaw": A list repesenting multiple programs and their respective arguments to execute.
+
+  The code:"script" and code:"utility" Rule Types allow the following the code:"FSS-0003 (Extended List)"\:
+    - code:"freeze": A list repesenting the contents of a script, such as a GNU Bash shell.
+    - code:"kill": A list repesenting the contents of a script, such as a GNU Bash shell.
+    - code:"pause": A list repesenting the contents of a script, such as a GNU Bash shell.
+    - code:"reload": A list repesenting the contents of a script, such as a GNU Bash shell.
+    - code:"restart": A list repesenting the contents of a script, such as a GNU Bash shell.
+    - code:"resume": A list repesenting the contents of a script, such as a GNU Bash shell.
+    - code:"start": A list repesenting the contents of a script, such as a GNU Bash shell.
+    - code:"stop": A list repesenting the contents of a script, such as a GNU Bash shell.
+    - code:"thaw": A list repesenting the contents of a script, such as a GNU Bash shell.
+
+  The code:"rerun" Rule Type Content has the following structure\:
+    The first Content represents one of: code:"freeze", code:"kill", code:"pause", code:"reload", code:"restart", code:"resume", code:"start", code:"stop", or code:"thaw".
+    The second Content represents one of: code:"success" or code:"failure".
+    The third and more Content represents one of: code:"delay", code:"max", or code:"reset".
+    Where code:"delay" and code:"max" must be followed by a positive number or the number 0.
diff --git a/specifications/task.txt b/specifications/task.txt
new file mode 100644 (file)
index 0000000..8175aa4
--- /dev/null
@@ -0,0 +1,14 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named task.txt) can be more easily read using the following iki_read commands:
+#   iki_read task.txt +Q -w -W code '"' '"'
+#
+# To read the "Task Specification" section of this file, use this command sequence:
+#   fss_basic_list_read task.txt +Q -cn "Task Specification" | iki_read +Q -w -W code '"' '"'
+#
+# A "Task" is not fully implemented but is provided as a proposal for consideration and is subject to completion or removal.
+#
+
+Task Specification:
diff --git a/specifications/time.txt b/specifications/time.txt
new file mode 100644 (file)
index 0000000..4af3cf9
--- /dev/null
@@ -0,0 +1,155 @@
+# fss-0002 iki-0000
+#
+# license: open-standard-license-1.0
+#
+# This file (assumed to be named time.txt) can be more easily read using the following iki_read commands:
+#   iki_read time.txt +Q -r UTC UTC -w -WW character "'" "'" code '"' '"'
+#
+# To read the "Time Specification" section of this file, use this command sequence:
+#   fss_basic_list_read time.txt +Q -cn "Time Specification" | iki_read +Q -r UTC UTC -w -WW character "'" "'" code '"' '"'
+#
+
+Time Specification:
+  There are two units of bold:"Time", the first is simply called bold:"Time" and the second is called bold:"EpochTime".
+
+  Both bold:"Time" and bold:"EpochTime" are measured without the year but may contain a year to designate the point in the counting begins.
+  These are both represented by a single 64-bit (unsigned) integer.
+  The default timezone is always UTC:"Coordinated Universal Time".
+
+  The common form is intended as the non-technical form that is form common use.
+  This may have a negative value or be more than 64-bit digits long.
+  This is simply not expected to be interpreted as a unit of time on a computer (but nothing stops it from being interpreted).
+
+  The technical forms are limit to 64-bit unsigned for technical use but should technology advance to a point where larger bits are needed then this allows for that.
+  The systems should expect 64-bit and larger bits would have to become common before something larger than 64-bit is the expected or assumed default.
+  Negative signs can be allowed but they must not prevent the full use of the 64-bit.
+  The implementation of how this is done is left to the implementer except that the signs are immediately to the left of the digit.
+  For example code:"2022:-5" would be 5 units after the start of the year 2022.
+  Because the negative is allowed, so must the positive character (such as code:"2022:+5").
+  A positive value is the default interpretation when no sign is valid.
+
+  The unit of time called bold:"Time" is counted increments of a nanosecond, or 10^-9 seconds.
+  A unit of bold:"Time" is, therefore, equivalent to a nanosecond.
+  The default year for bold:"Time" is the current year.
+
+  The unit of time called bold:"EpochTime" is counted increments of a second, or 10^-9 seconds.
+  A unit of bold:"EpochTime" is, therefore, equivalent to a second.
+  The default year for bold:"EpochTime" is the bold:"UNIX Epoch", sometimes called bold:"Unix time".
+
+  The unit bold:"Time" has two technical forms and one common form, with the year and without the year.
+
+  Key\:
+    code:"\s" = White space.
+    code:"\d" = The digits used to represent time (a digit).
+    code:"*" = Zero or more occurrences.
+    code:"+" = One or more occurrences.
+    code:":" = A single colon character:":" (unicode:"U+003A").
+    code:'"' = A single double-quote character:'"' (unicode:"U+003A").
+
+  The common form of bold:"Time"\:
+
+    Before Structure\:
+      code:"".
+
+    Structure\:
+      code:"\s*\d+\s*\U*\s*".
+
+    After Structure\:
+      code:"".
+
+    Example\:
+      code:"86400".
+      code:"86400 T".
+      code:"86400 Time".
+
+  The first technical form of bold:"Time"\:
+
+    Before Structure\:
+      code:"".
+
+    Structure\:
+      code:"\s*\d+:\d+\s*\U*\s*".
+
+    After Structure\:
+      code:"".
+
+    Example\:
+      code:"2022:86400".
+      code:"2022:86400 T".
+      code:"2022:86400 Time".
+      code:"2022:86400 MT".
+      code:"2022:86400 MegaTime".
+
+  The second technical form of bold:"Time"\:
+
+    Before Structure\:
+      code:"".
+
+    Structure\:
+      code:"\s*:\d+\s*\U*\s*".
+
+    After Structure\:
+      code:"".
+
+    Example\:
+      code:":86400".
+      code:":86400 T".
+      code:":86400 Time".
+      code:":86400 MT".
+      code:":86400 MegaTime".
+
+  The unit bold:"EpochTime" has two technical forms and one common form, with the year and without the year.
+
+  The common form of bold:"Time"\:
+
+    Before Structure\:
+      code:"".
+
+    Structure\:
+      code:"\s*\d+\s*\U*\s*".
+
+    After Structure\:
+      code:"".
+
+    Example\:
+      code:"86400".
+      code:"86400 ET".
+      code:"86400 EpochTime".
+      code:"86400 MET".
+      code:"86400 MegaEpochTime".
+
+  The first technical form of bold:"EpochTime"\:
+
+    Before Structure\:
+      code:"".
+
+    Structure\:
+      code:"\s*\d+::\d+\s*\U*\s*".
+
+    After Structure\:
+      code:"".
+
+    Example\:
+      code:"2022::86400".
+      code:"2022::86400 ET".
+      code:"2022::86400 EpochTime".
+      code:"2022::86400 MET".
+      code:"2022::86400 MegaEpochTime".
+
+  The second technical form of bold:"Time"\:
+
+    Before Structure\:
+      code:"".
+
+    Structure\:
+      code:"\s*:\d+\s*\U*\s*".
+
+    After Structure\:
+      code:"".
+
+    Example\:
+      code:"::86400".
+      code:"::86400 ET".
+      code:"::86400 EpochTime".
+      code:"::86400 MET".
+      code:"::86400 MegaEpochTime".