]> Kevux Git Server - fll/commitdiff
Update: add environment functions, add static strings, and other changes
authorKevin Day <thekevinday@gmail.com>
Fri, 15 May 2020 02:42:01 +0000 (21:42 -0500)
committerKevin Day <thekevinday@gmail.com>
Fri, 15 May 2020 02:42:01 +0000 (21:42 -0500)
Add environment project and associated functions for managing environment variables.
Add execute functions for setting environment variables.
- More work is needed to search the PATH to perform fll_execute_program_environment when PATH is not to be defined.

Provide stub define build settings files for each project.

Miscellaneous minor fixes/tweaks.

70 files changed:
build/level_0/settings
build/monolithic/settings
level_0/f_color/data/build/defines [new file with mode: 0644]
level_0/f_console/c/console.h
level_0/f_console/data/build/defines [new file with mode: 0644]
level_0/f_conversion/data/build/defines [new file with mode: 0644]
level_0/f_directory/c/directory.h
level_0/f_directory/data/build/defines [new file with mode: 0644]
level_0/f_environment/c/environment.c [new file with mode: 0644]
level_0/f_environment/c/environment.h [new file with mode: 0644]
level_0/f_environment/c/private-environment.c [new file with mode: 0644]
level_0/f_environment/c/private-environment.h [new file with mode: 0644]
level_0/f_environment/data/build/defines [new file with mode: 0644]
level_0/f_environment/data/build/dependencies [new file with mode: 0644]
level_0/f_environment/data/build/settings [new file with mode: 0644]
level_0/f_file/data/build/defines [new file with mode: 0644]
level_0/f_fss/data/build/defines [new file with mode: 0644]
level_0/f_memory/data/build/defines [new file with mode: 0644]
level_0/f_path/data/build/defines [new file with mode: 0644]
level_0/f_pipe/data/build/defines [new file with mode: 0644]
level_0/f_print/data/build/defines [new file with mode: 0644]
level_0/f_serialized/data/build/defines [new file with mode: 0644]
level_0/f_socket/data/build/defines [new file with mode: 0644]
level_0/f_status/c/status.h
level_0/f_status/data/build/defines [new file with mode: 0644]
level_0/f_string/c/string.h
level_0/f_type/data/build/defines [new file with mode: 0644]
level_1/fl_color/data/build/defines [new file with mode: 0644]
level_1/fl_console/data/build/defines [new file with mode: 0644]
level_1/fl_file/data/build/defines [new file with mode: 0644]
level_1/fl_fss/data/build/defines [new file with mode: 0644]
level_1/fl_print/data/build/defines [new file with mode: 0644]
level_1/fl_serialized/data/build/defines [new file with mode: 0644]
level_1/fl_socket/data/build/defines [new file with mode: 0644]
level_1/fl_status/c/status.c
level_1/fl_status/c/status.h
level_1/fl_status/data/build/defines [new file with mode: 0644]
level_1/fl_string/data/build/defines [new file with mode: 0644]
level_1/fl_utf/data/build/defines [new file with mode: 0644]
level_1/fl_utf_file/data/build/defines [new file with mode: 0644]
level_2/fll_directory/data/build/defines [new file with mode: 0644]
level_2/fll_execute/c/execute.c
level_2/fll_execute/c/execute.h
level_2/fll_execute/data/build/defines [new file with mode: 0644]
level_2/fll_execute/data/build/dependencies
level_2/fll_execute/data/build/settings
level_2/fll_file/data/build/defines [new file with mode: 0644]
level_2/fll_fss/c/fss_basic.c
level_2/fll_fss/c/fss_basic.h
level_2/fll_fss/c/fss_basic_list.c
level_2/fll_fss/c/fss_basic_list.h
level_2/fll_fss/c/fss_extended.c
level_2/fll_fss/c/fss_extended.h
level_2/fll_fss/c/fss_extended_list.c
level_2/fll_fss/c/fss_extended_list.h
level_2/fll_fss/data/build/defines [new file with mode: 0644]
level_2/fll_program/data/build/defines [new file with mode: 0644]
level_2/fll_status/c/status.c
level_2/fll_status/data/build/defines [new file with mode: 0644]
level_3/byte_dump/data/build/defines [new file with mode: 0644]
level_3/fss_basic_list_read/data/build/defines [new file with mode: 0644]
level_3/fss_basic_list_write/data/build/defines [new file with mode: 0644]
level_3/fss_basic_read/data/build/defines [new file with mode: 0644]
level_3/fss_basic_write/data/build/defines [new file with mode: 0644]
level_3/fss_extended_list_read/data/build/defines [new file with mode: 0644]
level_3/fss_extended_read/data/build/defines [new file with mode: 0644]
level_3/fss_extended_write/data/build/defines [new file with mode: 0644]
level_3/fss_status_code/data/build/defines [new file with mode: 0644]
level_3/init/data/build/defines [new file with mode: 0644]
level_3/status_code/data/build/defines [new file with mode: 0644]

index acb13ed6faf35cfd3c28deb288c002303b804eb3..1cd482d4a32d5c868003f146a0a5257971993ab1 100644 (file)
@@ -12,9 +12,9 @@ build_linker ar
 build_libraries -lc
 build_libraries_fll
 build_libraries_fll-level
-build_sources_library console.c conversion.c directory.c private-directory.c file.c memory.c pipe.c print.c utf.c private-utf.c
+build_sources_library console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c memory.c pipe.c print.c utf.c private-utf.c
 build_sources_program
-build_sources_headers color.h console.h conversion.h directory.c file.h fss.h memory.h path_fll.h path_filesystem.h path.h pipe.h print.h serialized.h socket.h status.h string.h type.h type_array.h utf.h
+build_sources_headers color.h console.h conversion.h directory.h environment.h file.h fss.h memory.h path_fll.h path_filesystem.h path.h pipe.h print.h serialized.h socket.h status.h string.h type.h type_array.h utf.h
 build_shared yes
 build_static yes
 
index 1eace143b147aa363105f028d5a02748c8ebc358..614c23baa5c2ed81a98bce4768a7a749ba866cd9 100644 (file)
@@ -11,9 +11,9 @@ build_compiler gcc
 build_linker ar
 build_libraries -lc
 build_libraries_fll
-build_sources_library level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/file.c level_0/memory.c level_0/pipe.c level_0/print.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/file.c level_1/fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/print.c level_1/serialized.c level_1/private-serialized.c level_1/socket.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_2/directory.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/program.c level_2/status.c
+build_sources_library level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/memory.c level_0/pipe.c level_0/print.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/file.c level_1/fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/print.c level_1/serialized.c level_1/private-serialized.c level_1/socket.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_2/directory.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/program.c level_2/status.c
 build_sources_program
-build_sources_headers level_0/color.h level_0/console.h level_0/conversion.h level_0/directory.h level_0/file.h level_0/fss.h level_0/memory.h level_0/path_fll.h level_0/path_filesystem.h level_0/path.h level_0/pipe.h level_0/print.h level_0/serialized.h level_0/socket.h level_0/status.h level_0/string.h level_0/type.h level_0/type_array.h level_0/utf.h level_1/color.h level_1/console.h level_1/file.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_status.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/print.h level_1/serialized.h level_1/socket.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/directory.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/program.h level_2/status.h
+build_sources_headers level_0/color.h level_0/console.h level_0/conversion.h level_0/directory.h level_0/environment.h level_0/file.h level_0/fss.h level_0/memory.h level_0/path_fll.h level_0/path_filesystem.h level_0/path.h level_0/pipe.h level_0/print.h level_0/serialized.h level_0/socket.h level_0/status.h level_0/string.h level_0/type.h level_0/type_array.h level_0/utf.h level_1/color.h level_1/console.h level_1/file.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_status.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/print.h level_1/serialized.h level_1/socket.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/directory.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/program.h level_2/status.h
 build_sources_bash
 build_sources_settings
 build_shared yes
diff --git a/level_0/f_color/data/build/defines b/level_0/f_color/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
index 0b6316e5d56a4551d4aa3582d2c73ff9edfc1563..374e4dee6296e9d95615fcdc700746331f46905a 100644 (file)
@@ -86,6 +86,13 @@ extern "C" {
  * - light: Do display color intended for light backgrounds when printing to the console. Other contexts may be acceptable (such as voice inflections, or lack-thereof) for audio.)
  * - no_color: Do not display color when printing to the console. Other contexts may be acceptable (such as voice inflections, or lack-thereof) for audio.)
  * - version: Should always print only the version number, no colors, but what represents the version number is undefined by this project.
+ *
+ * The following options are for special purposes:
+ * - status: Represents the return status code from another program.
+ *           Because it is associated with the status from another program, its structure is very subjective.
+ *           The only expectation is that it somehow communicates the fss status codes.
+ *           Example of complex use: "failed_program_name:error:123".
+ *           Example of simple use: "123".
  */
 #ifndef _di_f_standard_console_parameters_
   #define f_console_standard_short_dark     "d"
@@ -111,6 +118,7 @@ extern "C" {
   #define f_console_standard_long_help     "help"
   #define f_console_standard_long_light    "light"
   #define f_console_standard_long_no_color "no_color"
+  #define f_console_standard_long_status   "status"
   #define f_console_standard_long_quiet    "quiet"
   #define f_console_standard_long_verbose  "verbose"
   #define f_console_standard_long_version  "version"
@@ -120,6 +128,7 @@ extern "C" {
   #define f_console_standard_long_help_length     4
   #define f_console_standard_long_light_length    5
   #define f_console_standard_long_no_color_length 8
+  #define f_console_standard_long_status_length   6
   #define f_console_standard_long_quiet_length    5
   #define f_console_standard_long_verbose_length  7
   #define f_console_standard_long_version_length  7
diff --git a/level_0/f_console/data/build/defines b/level_0/f_console/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_conversion/data/build/defines b/level_0/f_conversion/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
index c467704267c7492392b44f2a285298440811233a..77a3215db30f2e8b7339af36bd9aadcd3cc506cb 100644 (file)
@@ -125,17 +125,17 @@ extern "C" {
 
 /**
  * A structure representing a directory.
+ *
+ * @todo review this and decide to keep and use it or just remove it.
  */
 #ifndef _di_f_directory_
   typedef struct {
     struct dirent entity;
-    int descriptor;
     f_directory_listing content;
   } f_directory;
 
   #define f_directory_initialize { \
       { 0, 0, 0, 0, 0 }, \
-      0, \
       f_directory_listing_initialize, \
     }
 #endif // _di_f_directory_
diff --git a/level_0/f_directory/data/build/defines b/level_0/f_directory/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_environment/c/environment.c b/level_0/f_environment/c/environment.c
new file mode 100644 (file)
index 0000000..5509cf9
--- /dev/null
@@ -0,0 +1,127 @@
+#include <level_0/environment.h>
+#include "private-environment.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_f_environment_clear_
+  f_return_status f_environment_clear() {
+    if (clearenv() == 0) {
+      return f_none;
+    }
+
+    return f_status_set_error(f_failure);
+  }
+#endif // _di_f_environment_clear_
+
+#ifndef _di_f_environment_get_
+  f_return_status f_environment_get(const f_string name, f_string_dynamic *value) {
+    return private_f_environment_get(name, value);
+  }
+#endif // _di_f_environment_get_
+
+#ifndef _di_f_environment_get_dynamic_
+  f_return_status f_environment_get_dynamic(const f_string_static name, f_string_dynamic *value) {
+    #ifndef _di_level_0_parameter_checking_
+      if (name.used > name.size) return f_status_set_error(f_invalid_parameter);
+      if (value->used > value->size) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (name.used == 0) return f_no_data;
+
+    if (name.string[name.used - 1] == 0) {
+      return private_f_environment_get(name.string, value);
+    }
+
+    char variable_name[name.used + 1];
+
+    memcpy(&variable_name, name.string, name.used);
+    variable_name[name.used] = 0;
+
+    return private_f_environment_get(variable_name, value);
+  }
+#endif // _di_f_environment_get_dynamic_
+
+#ifndef _di_f_environment_set_
+  f_return_status f_environment_set(const f_string name, const f_string value, const bool replace) {
+    return private_f_environment_set(name, value, replace);
+  }
+#endif // _di_f_environment_set_
+
+#ifndef _di_f_environment_set_dynamic_
+  f_return_status f_environment_set_dynamic(const f_string_static name, const f_string_static value, const bool replace) {
+    #ifndef _di_level_0_parameter_checking_
+      if (name.used > name.size) return f_status_set_error(f_invalid_parameter);
+      if (value.used > value.size) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (name.used == 0) return f_no_data;
+
+    if (name.string[name.used - 1] == 0) {
+      if (value.used > 0 && value.string[value.used - 1] == 0) {
+        return private_f_environment_set(name.string, value.string, replace);
+      }
+
+      char variable_value[value.used + 1];
+
+      if (value.used > 0) {
+        memcpy(&variable_value, value.string, value.used);
+      }
+
+      variable_value[value.used] = 0;
+
+      return private_f_environment_set(name.string, variable_value, replace);
+    }
+
+    char variable_name[name.used + 1];
+
+    memcpy(&variable_name, name.string, name.used);
+    variable_name[name.used] = 0;
+
+    if (value.used > 0 && value.string[value.used - 1] == 0) {
+      return private_f_environment_set(variable_name, value.string, replace);
+    }
+
+    char variable_value[value.used + 1];
+
+    if (value.used > 0) {
+      memcpy(&variable_value, value.string, value.used);
+    }
+
+    variable_value[value.used] = 0;
+
+    return private_f_environment_set(variable_name, variable_value, replace);
+  }
+#endif // _di_f_environment_set_dynamic_
+
+#ifndef _di_f_environment_unset_
+  f_return_status f_environment_unset(const f_string name) {
+    return private_f_environment_unset(name);
+  }
+#endif // _di_f_environment_unset_
+
+#ifndef _di_f_environment_unset_
+  f_return_status f_environment_unset_dynamic(const f_string_static name) {
+    #ifndef _di_level_0_parameter_checking_
+      if (name.used > name.size) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    if (name.used == 0) return f_no_data;
+
+    if (name.string[name.used - 1] == 0) {
+      return private_f_environment_unset(name.string);
+    }
+
+    char variable_name[name.used + 1];
+
+    memcpy(&variable_name, name.string, name.used);
+    variable_name[name.used] = 0;
+
+    return private_f_environment_unset(variable_name);
+  }
+#endif // _di_f_environment_unset_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_environment/c/environment.h b/level_0/f_environment/c/environment.h
new file mode 100644 (file)
index 0000000..bae2d02
--- /dev/null
@@ -0,0 +1,204 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides environment processing functionality, such as environment variable handling.
+ */
+#ifndef _F_environment_h
+#define _F_environment_h
+
+// libc includes
+#include <stdio.h>
+#include <sys/stat.h>
+
+// fll-0 includes
+#include <level_0/status.h>
+#include <level_0/memory.h>
+#include <level_0/string.h>
+#include <level_0/type.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Environment related defines.
+ */
+#ifndef _di_f_environment_defines_
+  #define f_environment_max_length f_string_length_size
+#endif // _di_f_environment_defines_
+
+/**
+ * Delete all environment variables.
+ *
+ * @return
+ *   f_none on success.
+ *   f_failure (with error bit) on failure.
+ *
+ * @see clearenv()
+ */
+#ifndef _di_f_environment_clear_
+  extern f_return_status f_environment_clear();
+#endif // _di_f_environment_clear_
+
+/**
+ * Get a single environment variable.
+ *
+ * The variable is copied into a new dynamically allocated string and is safe to alter.
+ *
+ * @param name
+ *   The name of the environment variable to get.
+ *   The name string must not contain the '=' character.
+ *   The name must be NULL terminated.
+ * @param value
+ *   The value associated with name.
+ *   The value will not be null terminated.
+ *   The value will be appended (set value->used to 0 to replace).
+ *
+ * @return
+ *   f_none on success.
+ *   f_does_not_exist if name does not exist.
+ *   f_string_too_large (with error bit) if appended string length is too large to store in the buffer.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see getenv()
+ */
+#ifndef _di_f_environment_get_
+  extern f_return_status f_environment_get(const f_string name, f_string_dynamic *value);
+#endif // _di_f_environment_get_
+
+/**
+ * Get a single environment variable.
+ *
+ * The variable is copied into a new dynamically allocated string and is safe to alter.
+ *
+ * @param name
+ *   The name of the environment variable to get.
+ *   The name string must not contain the '=' character.
+ *   The name need not be NULL terminated.
+ * @param value
+ *   The value associated with name.
+ *   The value will not be null terminated.
+ *   The value will be appended (set value->used to 0 to replace).
+ *
+ * @return
+ *   f_none on success.
+ *   f_does_not_exist if name does not exist.
+ *   f_no_data if name.used is 0.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_string_too_large (with error bit) if appended string length is too large to store in the buffer.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see getenv()
+ */
+#ifndef _di_f_environment_get_dynamic_
+  extern f_return_status f_environment_get_dynamic(const f_string_static name, f_string_dynamic *value);
+#endif // _di_f_environment_get_dynamic_
+
+/**
+ * Assign the given value to the named environment variable.
+ *
+ * If the name does not exist, then it is created.
+ *
+ * @param name
+ *   The name of the environment variable to set.
+ *   The name string must not contain the '=' character.
+ *   The name must be NULL terminated.
+ * @param value
+ *   The value to assign to name.
+ *   The name must be NULL terminated.
+ * @param replace
+ *   Set to TRUE to replace value if name already exists.
+ *   Set to FALSE to not replace value if name already exists.
+ *
+ * @return
+ *   f_none on success.
+ *   f_invalid (with error bit) if name is an invalid string.
+ *   f_out_of_memory (with error bit) on out of memory.
+ *   f_failure (with error bit) on any other error.
+ *
+ * @see setenv()
+ */
+#ifndef _di_f_environment_set_
+  extern f_return_status f_environment_set(const f_string name, const f_string value, const bool replace);
+#endif // _di_f_environment_set_
+
+/**
+ * Assign the given value to the named environment variable.
+ *
+ * If the name does not exist, then it is created.
+ *
+ * @param name
+ *   The name of the environment variable to set.
+ *   The name string must not contain the '=' character.
+ *   The name need not be NULL terminated.
+ * @param value
+ *   The value to assign to name.
+ *   The value need not be NULL terminated.
+ * @param replace
+ *   Set to TRUE to replace value if name already exists.
+ *   Set to FALSE to not replace value if name already exists.
+ *
+ * @return
+ *   f_none on success.
+ *   f_no_data if name.used is 0.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_invalid (with error bit) if name is an invalid string.
+ *   f_out_of_memory (with error bit) on out of memory.
+ *   f_failure (with error bit) on any other error.
+ *
+ * @see setenv()
+ */
+#ifndef _di_f_environment_set_dynamic_
+  extern f_return_status f_environment_set_dynamic(const f_string_static name, const f_string_static value, const bool replace);
+#endif // _di_f_environment_set_dynamic_
+
+/**
+ * Remove the name environment variable.
+ *
+ * @param name
+ *   The name of the environment variable to remove.
+ *   The name string must not contain the '=' character.
+ *   The name must be NULL terminated.
+ *
+ * @return
+ *   f_none on success.
+ *   f_invalid (with error bit) if name is an invalid string.
+ *   f_out_of_memory (with error bit) on out of memory.
+ *   f_failure (with error bit) on any other error.
+ *
+ * @see unsetenv()
+ */
+#ifndef _di_f_environment_unset_
+  extern f_return_status f_environment_unset(const f_string name);
+#endif // _di_f_environment_unset_
+
+/**
+ * Remove the name environment variable.
+ *
+ * @param name
+ *   The name of the environment variable to remove.
+ *   The name string must not contain the '=' character.
+ *   The name need not be NULL terminated.
+ *
+ * @return
+ *   f_none on success.
+ *   f_invalid (with error bit) if name is an invalid string.
+ *   f_out_of_memory (with error bit) on out of memory.
+ *   f_failure (with error bit) on any other error.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see unsetenv()
+ */
+#ifndef _di_f_environment_unset_dynamic_
+  extern f_return_status f_environment_unset_dynamic(const f_string_static name);
+#endif // _di_f_environment_unset_dynamic_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _F_environment_h
diff --git a/level_0/f_environment/c/private-environment.c b/level_0/f_environment/c/private-environment.c
new file mode 100644 (file)
index 0000000..67bb510
--- /dev/null
@@ -0,0 +1,77 @@
+#include <level_0/environment.h>
+#include "private-environment.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_di_f_environment_get_) || !defined(_di_f_environment_get_dynamic_)
+  f_return_status private_f_environment_get(const f_string name, f_string_dynamic *value) {
+    const f_string result = getenv(name);
+
+    if (result == 0) {
+      return f_does_not_exist;
+    }
+
+    const f_string_length size = strnlen(result, f_environment_max_length);
+
+    if (size == 0) {
+      value->used = 0;
+    }
+    else {
+      if (value->used + size > f_environment_max_length) {
+        return f_status_set_error(f_string_too_large);
+      }
+
+      if (value->used + size > value->size) {
+        f_status status = f_none;
+
+        f_macro_string_dynamic_resize(status, (*value), size);
+        if (f_status_is_error(status)) return status;
+      }
+
+      memcpy(&value->string + value->used, result, value->used + size);
+      value->used = size;
+    }
+
+    return f_none;
+  }
+#endif // !defined(_di_f_environment_get_) || !defined(_di_f_environment_get_dynamic_)
+
+#if !defined(_di_f_environment_set_) || !defined(_di_f_environment_set_dynamic_)
+  f_return_status private_f_environment_set(const f_string name, const f_string value, const bool replace) {
+    if (setenv(name, value, replace) < 0) {
+      if (errno == EINVAL) {
+        return f_status_set_error(f_invalid);
+      }
+      else if (errno == ENOMEM) {
+        return f_status_set_error(f_out_of_memory);
+      }
+
+      return f_status_set_error(f_failure);
+    }
+
+    return f_none;
+  }
+#endif // !defined(_di_f_environment_set_) || !defined(_di_f_environment_set_dynamic_)
+
+#if !defined(_di_f_environment_unset_) || !defined(_di_f_environment_unset_dynamic_)
+  f_return_status private_f_environment_unset(const f_string name) {
+    if (unsetenv(name) < 0) {
+      if (errno == EINVAL) {
+        return f_status_set_error(f_invalid);
+      }
+      else if (errno == ENOMEM) {
+        return f_status_set_error(f_out_of_memory);
+      }
+
+      return f_status_set_error(f_failure);
+    }
+
+    return f_none;
+  }
+#endif // !defined(_di_f_environment_unset_) || !defined(_di_f_environment_unset_dynamic_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_environment/c/private-environment.h b/level_0/f_environment/c/private-environment.h
new file mode 100644 (file)
index 0000000..4dc80b4
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides environment processing functionality, such as environment variable handling.
+ */
+#ifndef _PRIVATE_F_environment_h
+#define _PRIVATE_F_environment_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get a single environment variable.
+ *
+ * The variable is copied into a new dynamically allocated string and is safe to alter.
+ *
+ * @param name
+ *   The name of the environment variable to get.
+ *   The name string must not contain the '=' character.
+ *   The name must be NULL terminated.
+ * @param value
+ *   The value associated with name.
+ *   The value will not be null terminated.
+ *   The value will be appended (set value->used to 0 to replace).
+ *
+ * @return
+ *   f_none on success.
+ *   f_does_not_exist if name does not exist.
+ *   f_string_too_large (with error bit) if appended string length is too large to store in the buffer.
+ *   f_error_reallocation (with error bit) on memory reallocation error.
+ *
+ * @see f_environment_get()
+ * @see f_environment_get_dynamic()
+ */
+#if !defined(_di_f_environment_get_) || !defined(_di_f_environment_get_dynamic_)
+  extern f_return_status private_f_environment_get(const f_string name, f_string_dynamic *value) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_environment_get_) || !defined(_di_f_environment_get_dynamic_)
+
+/**
+ * Assign the given value to the named environment variable.
+ *
+ * If the name does not exist, then it is created.
+ *
+ * @param name
+ *   The name of the environment variable to set.
+ *   The name string must not contain the '=' character.
+ * @param value
+ *   The value to assign to name.
+ * @param replace
+ *   Set to TRUE to replace value if name already exists.
+ *   Set to FALSE to not replace value if name already exists.
+ *
+ * @return
+ *   f_none on success.
+ *   f_invalid (with error bit) if name is an invalid string.
+ *   f_out_of_memory (with error bit) on out of memory.
+ *   f_failure (with error bit) on any other error.
+ *
+ * @see f_environment_set()
+ * @see f_environment_set_dynamic()
+ */
+#if !defined(_di_f_environment_set_) || !defined(_di_f_environment_set_dynamic_)
+  extern f_return_status private_f_environment_set(const f_string name, const f_string value, const bool replace) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_environment_set_) || !defined(_di_f_environment_set_dynamic_)
+
+/**
+ * Remove the name environment variable.
+ *
+ * @param name
+ *   The name of the environment variable to remove.
+ *   The name string must not contain the '=' character.
+ *
+ * @return
+ *   f_none on success.
+ *   f_invalid (with error bit) if name is an invalid string.
+ *   f_out_of_memory (with error bit) on out of memory.
+ *   f_failure (with error bit) on any other error.
+ *
+ * @see f_environment_unset()
+ * @see f_environment_unset_dynamic()
+ */
+#if !defined(_di_f_environment_unset_) || !defined(_di_f_environment_unset_dynamic_)
+  extern f_return_status private_f_environment_unset(const f_string name) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_environment_unset_) || !defined(_di_f_environment_unset_dynamic_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_F_environment_h
diff --git a/level_0/f_environment/data/build/defines b/level_0/f_environment/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_environment/data/build/dependencies b/level_0/f_environment/data/build/dependencies
new file mode 100644 (file)
index 0000000..d8175f5
--- /dev/null
@@ -0,0 +1,4 @@
+f_type
+f_status
+f_memory
+f_string
diff --git a/level_0/f_environment/data/build/settings b/level_0/f_environment/data/build/settings
new file mode 100644 (file)
index 0000000..f12b79e
--- /dev/null
@@ -0,0 +1,30 @@
+# fss-0000
+
+project_name f_environment
+project_level 0
+
+version_major 0
+version_minor 5
+version_micro 0
+
+build_compiler gcc
+build_linker ar
+build_libraries -lc 
+build_libraries_fll -lf_memory
+build_sources_library environment.c private-environment.c
+build_sources_program 
+build_sources_headers environment.h
+build_sources_bash
+build_sources_settings
+build_shared yes
+build_static yes
+
+defines_all
+defines_static
+defines_shared
+
+flags_all -z now -g
+flags_shared
+flags_static
+flags_library -fPIC
+flags_program -fPIE
diff --git a/level_0/f_file/data/build/defines b/level_0/f_file/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_fss/data/build/defines b/level_0/f_fss/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_memory/data/build/defines b/level_0/f_memory/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_path/data/build/defines b/level_0/f_path/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_pipe/data/build/defines b/level_0/f_pipe/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_print/data/build/defines b/level_0/f_print/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_serialized/data/build/defines b/level_0/f_serialized/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_0/f_socket/data/build/defines b/level_0/f_socket/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
index 5376b61c547578365521107152367cec721a32e6..1902e772773c614854dd6a0172ec80e9dbf7c2f0 100644 (file)
@@ -311,10 +311,8 @@ extern "C" {
       f_filesystem_quota_reached,
     #endif // _di_f_status_filesystem_
 
-    // Most of these are a guess until I get around to researching & implementing linux directory I/O.
     #ifndef _di_f_status_directory_
       f_directory_error,
-      f_directory_error_allocation,
       f_directory_error_close,
       f_directory_error_descriptor,
       f_directory_error_flush,
@@ -322,7 +320,6 @@ extern "C" {
       f_directory_error_open,
       f_directory_error_purge,
       f_directory_error_read,
-      f_directory_error_reallocation,
       f_directory_error_stream,
       f_directory_error_synchronize,
       f_directory_error_unsupported,
diff --git a/level_0/f_status/data/build/defines b/level_0/f_status/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
index e8bb990bc0e77396f96da4433461ade2950d8136..e6fabd78acf04b8371cf3c07e42aa92326c2bbb9 100644 (file)
@@ -295,6 +295,29 @@ extern "C" {
 #endif // _di_f_string_dynamic_
 
 /**
+ * An array of static strings.
+ *
+ * array: the array of static strings.
+ * size: total amount of space available.
+ * used: total number of space used.
+ */
+#ifndef _di_f_string_statics_
+  typedef struct {
+    f_string_static *array;
+
+    f_string_length size;
+    f_string_length used;
+  } f_string_statics;
+
+  #define f_string_statics_initialize { 0, 0, 0 }
+
+  #define f_macro_string_statics_clear(statics) \
+    statics.array = 0; \
+    statics.size = 0; \
+    statics.used = 0;
+#endif // _di_f_string_statics_
+
+/**
  * An array of dynamic strings.
  *
  * array: the array of dynamic strings.
@@ -302,19 +325,11 @@ extern "C" {
  * used: total number of allocated spaces used.
  */
 #ifndef _di_f_string_dynamics_
-  typedef struct {
-    f_string_dynamic *array;
-
-    f_string_length size;
-    f_string_length used;
-  } f_string_dynamics;
+  typedef f_string_statics f_string_dynamics;
 
-  #define f_string_dynamics_initialize { 0, 0, 0 }
+  #define f_string_dynamics_initialize f_string_statics_initialize
 
-  #define f_macro_string_dynamics_clear(dynamics) \
-    dynamics.array = 0; \
-    dynamics.size = 0; \
-    dynamics.used = 0;
+  #define f_macro_string_dynamics_clear(dynamics) f_macro_string_statics_clear(dynamics)
 
   #define f_macro_string_dynamics_new(status, dynamics, length) \
     f_macro_string_dynamics_clear(dynamics) \
diff --git a/level_0/f_type/data/build/defines b/level_0/f_type/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_color/data/build/defines b/level_1/fl_color/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_console/data/build/defines b/level_1/fl_console/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_file/data/build/defines b/level_1/fl_file/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_fss/data/build/defines b/level_1/fl_fss/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_print/data/build/defines b/level_1/fl_print/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_serialized/data/build/defines b/level_1/fl_serialized/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_socket/data/build/defines b/level_1/fl_socket/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
index bdbb5fb3221ca6f5cde09c5d0177d58511f0c692..f8250073bcea768ccfe78556430781e954867ad0 100644 (file)
@@ -729,12 +729,6 @@ extern "C" {
         case f_directory_not_open:
           *string = fl_status_string_directory_not_open;
           break;
-        case f_directory_error_allocation:
-          *string = fl_status_string_directory_allocation_error;
-          break;
-        case f_directory_error_reallocation:
-          *string = fl_status_string_directory_reallocation_error;
-          break;
         case f_directory_error:
           *string = fl_status_string_directory_error;
           break;
index 9de5fc423d62ffb110dc9e2b9632d0736ad96719..938f0b815bd3dd213bd4d8b677c926f0cfc326d3 100644 (file)
@@ -730,12 +730,6 @@ extern "C" {
     #define fl_status_string_directory_not_open "f_directory_not_open"
     #define fl_status_string_directory_not_open_length 20
 
-    #define fl_status_string_directory_allocation_error "f_directory_error_allocation"
-    #define fl_status_string_directory_allocation_error_length 28
-
-    #define fl_status_string_directory_reallocation_error "f_directory_error_reallocation"
-    #define fl_status_string_directory_reallocation_error_length 30
-
     #define fl_status_string_directory_error "f_directory_error"
     #define fl_status_string_directory_error_length 17
 
diff --git a/level_1/fl_status/data/build/defines b/level_1/fl_status/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_string/data/build/defines b/level_1/fl_string/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_utf/data/build/defines b/level_1/fl_utf/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_1/fl_utf_file/data/build/defines b/level_1/fl_utf_file/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_2/fll_directory/data/build/defines b/level_2/fll_directory/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
index a606b66a525a4429b99342d6c379c48e246def62..609037ec446c98085f17093affb1dc06d5677f31 100644 (file)
@@ -186,7 +186,7 @@ extern "C" {
 #endif // _di_fll_execute_arguments_dynamic_add_set_
 
 #ifndef _di_fll_execute_path_
-  f_return_status fll_execute_path(const f_string program_path, const f_string_dynamics arguments, int *result) {
+  f_return_status fll_execute_path(const f_string program_path, const f_string_statics arguments, int *result) {
     #ifndef _di_level_2_parameter_checking_
       if (result == 0) return f_status_set_error(f_invalid_parameter);
       if (arguments.used > arguments.size) return f_status_set_error(f_invalid_parameter);
@@ -287,8 +287,119 @@ extern "C" {
   }
 #endif // _di_fll_execute_path_
 
+#ifndef _di_fll_execute_path_environment_
+  f_return_status fll_execute_path_environment(const f_string program_path, const f_string_statics arguments, const f_string_statics names, const f_string_statics values, int *result) {
+    #ifndef _di_level_2_parameter_checking_
+      if (result == 0) return f_status_set_error(f_invalid_parameter);
+      if (arguments.used > arguments.size) return f_status_set_error(f_invalid_parameter);
+      if (names.used > names.size) return f_status_set_error(f_invalid_parameter);
+      if (values.used > values.size) return f_status_set_error(f_invalid_parameter);
+      if (names.used > values.used) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_2_parameter_checking_
+
+    // create a string array that is compatible with execv() calls.
+    f_string fixed_arguments[arguments.used + 2];
+
+    f_string last_slash = f_string_initialize;
+    f_string program_name = f_string_initialize;
+
+    f_string_length name_size = 0;
+
+    f_status status = f_none;
+
+    memset(&fixed_arguments, 0, sizeof(f_string) * (arguments.used + 2));
+
+    last_slash = strrchr(program_path, '/');
+
+    if (last_slash != 0) {
+      name_size = strnlen(last_slash, PATH_MAX);
+
+      if (name_size > 1) {
+        f_macro_string_new(status, program_name, name_size + 1);
+
+        if (f_status_is_error(status)) return status;
+
+        memcpy(program_name, last_slash + 1, sizeof(f_string_length) * name_size);
+        memset(program_name, name_size, 0);
+      }
+      else {
+        name_size = 0;
+      }
+    }
+
+    if (name_size == 0) {
+      fixed_arguments[0] = f_string_eos;
+    }
+    else {
+      fixed_arguments[0] = program_name;
+    }
+
+    for (f_string_length i = 0; i < arguments.used; i++) {
+      f_macro_string_new(status, fixed_arguments[i + 1], arguments.array[i].used + 1);
+
+      if (f_status_is_error(status)) {
+        if (name_size > 0) f_macro_string_delete_simple(program_name, name_size);
+
+        for (f_string_length j = 0; j < i; j++) {
+          f_macro_string_delete_simple(fixed_arguments[i + 1], arguments.array[j].used + 1);
+        } // for
+
+        return status;
+      }
+
+      memcpy(fixed_arguments[i + 1], arguments.array[i].string, arguments.array[i].used);
+      fixed_arguments[i + 1][arguments.array[i].used] = f_string_eos;
+    } // for
+
+    // insert the required array terminated
+    fixed_arguments[arguments.used + 2] = 0;
+
+    // @todo validate that the file at program_path actually exists before attempting to fork and execute
+    int process_id = 0;
+
+    process_id = vfork();
+
+    if (process_id < 0) {
+      if (name_size > 0) f_macro_string_delete_simple(program_name, name_size);
+
+      for (f_string_length i = 0; i < arguments.used; i++) {
+        f_macro_string_delete_simple(fixed_arguments[i + 1], arguments.array[i].used + 1);
+      } // for
+
+      return f_status_set_error(f_fork_failed);
+    }
+
+    // child
+    if (process_id == 0) {
+      clearenv();
+
+      for (f_array_length i = 0; i < names.used; i++) {
+        f_environment_set_dynamic(names.array[i], values.array[i], true);
+      }
+
+      execv(program_path, fixed_arguments);
+
+      // according to manpages, calling _exit() is safer and should be called here instead of exit()
+      _exit(-1);
+    }
+
+    // have the parent wait for the child process to finish
+    waitpid(process_id, result, 0);
+
+    if (name_size > 0) f_macro_string_delete_simple(program_name, name_size);
+
+    for (f_string_length i = 0; i < arguments.used; i++) {
+      f_macro_string_delete_simple(fixed_arguments[i + 1], arguments.array[i].used + 1);
+    } // for
+
+    if (*result != 0) return f_status_set_error(f_failure);
+
+    return f_none;
+  }
+#endif // _di_fll_execute_path_environment_
+
 #ifndef _di_fll_execute_program_
-  f_return_status fll_execute_program(const f_string program_name, const f_string_dynamics arguments, int *result) {
+  f_return_status fll_execute_program(const f_string program_name, const f_string_statics arguments, int *result) {
     #ifndef _di_level_2_parameter_checking_
       if (result == 0) return f_status_set_error(f_invalid_parameter);
       if (arguments.used > arguments.size) return f_status_set_error(f_invalid_parameter);
@@ -354,6 +465,82 @@ extern "C" {
   }
 #endif // _di_fll_execute_program_
 
+#ifndef _di_fll_execute_program_environment_
+  f_return_status fll_execute_program_environment(const f_string program_name, const f_string_statics arguments, const f_string_statics names, const f_string_statics values, int *result) {
+    #ifndef _di_level_2_parameter_checking_
+      if (result == 0) return f_status_set_error(f_invalid_parameter);
+      if (arguments.used > arguments.size) return f_status_set_error(f_invalid_parameter);
+      if (names.used > names.size) return f_status_set_error(f_invalid_parameter);
+      if (values.used > values.size) return f_status_set_error(f_invalid_parameter);
+      if (names.used > values.used) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_2_parameter_checking_
+
+    // create a string array that is compatible with execv() calls.
+    f_string fixed_arguments[arguments.used + 2];
+
+    memset(&fixed_arguments, 0, sizeof(f_string) * (arguments.used + 2));
+    fixed_arguments[0] = program_name;
+
+    f_status status = f_none;
+
+    for (f_string_length i = 0; i < arguments.used; i++) {
+      f_macro_string_new(status, fixed_arguments[i + 1], arguments.array[i].used + 1);
+
+      if (f_status_is_error(status)) {
+        for (f_string_length j = 0; j < i; j++) {
+          f_macro_string_delete_simple(fixed_arguments[i + 1], arguments.array[j].used + 1);
+        } // for
+
+        return status;
+      }
+
+      memcpy(fixed_arguments[i + 1], arguments.array[i].string, arguments.array[i].used);
+      fixed_arguments[i + 1][arguments.array[i].used] = f_string_eos;
+    } // for
+
+    // insert the required array terminated
+    fixed_arguments[arguments.used + 2] = 0;
+
+    // @todo validate that the file at program_path actually exists before attempting to fork and execute
+    int process_id = 0;
+
+    process_id = vfork();
+
+    if (process_id < 0) {
+      for (f_string_length i = 0; i < arguments.used; i++) {
+        f_macro_string_delete_simple(fixed_arguments[i + 1], arguments.array[i].used + 1);
+      } // for
+
+      return f_status_set_error(f_fork_failed);
+    }
+
+    // child
+    if (process_id == 0) {
+      clearenv();
+
+      for (f_array_length i = 0; i < names.used; i++) {
+        f_environment_set_dynamic(names.array[i], values.array[i], true);
+      }
+
+      execvp(program_name, fixed_arguments);
+
+      // according to manpages, calling _exit() is safer and should be called here instead of exit()
+      _exit(-1);
+    }
+
+    // have the parent wait for the child process to finish
+    waitpid(process_id, result, 0);
+
+    for (f_string_length i = 0; i < arguments.used; i++) {
+      f_macro_string_delete_simple(fixed_arguments[i + 1], arguments.array[i].used + 1);
+    } // for
+
+    if (*result != 0) return f_status_set_error(f_failure);
+
+    return f_none;
+  }
+#endif // _di_fll_execute_program_environment_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index d454b7248f557b889724f46d6131aa8b9de02f37..6d1e6e1f9cdc1d9e4b4e16e505579a0a2f82ffe4 100644 (file)
@@ -23,6 +23,7 @@
 #include <level_0/memory.h>
 #include <level_0/string.h>
 #include <level_0/type.h>
+#include <level_0/environment.h>
 
 // fll-1 includes
 #include <level_1/string.h>
@@ -298,10 +299,43 @@ extern "C" {
  * @see execv()
  */
 #ifndef _di_fll_execute_path_
-  extern f_return_status fll_execute_path(const f_string program_path, const f_string_dynamics arguments, int *result);
+  extern f_return_status fll_execute_path(const f_string program_path, const f_string_statics arguments, int *result);
 #endif // _di_fll_execute_path_
 
 /**
+ * Execute a program given some path + program name (such as "/bin/bash").
+ *
+ * The environment is defined by the names and values pair.
+ *
+ * @param program_path
+ *   The entire path to the program.
+ * @param arguments
+ *   An array of strings representing the arguments.
+ * @param names
+ *   An array of strings representing the environment variable names.
+ *   At most names.used variables are created.
+ *   Duplicate names are overwritten.
+ * @param values
+ *   An array of strings representing the environment variable names.
+ *   The values.used must be of at least names.used.
+ *   Set individual strings.used to 0 for empty/null values.
+ * @param result
+ *   The code returned after finishing execution of program_path.
+ *
+ * @return
+ *   f_none on success.
+ *   f_failure (with error bit) if result is non-zero.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on allocation error.
+ *   f_error_reallocation (with error bit) on reallocation error.
+ *
+ * @see execv()
+ */
+#ifndef _di_fll_execute_path_environment_
+  f_return_status fll_execute_path_environment(const f_string program_path, const f_string_statics arguments, const f_string_statics names, const f_string_statics values, int *result);
+#endif // _di_fll_execute_path_environment_
+
+/**
  * Execute a program given by name found in the PATH environment (such as "bash").
  *
  * @param program_name
@@ -322,9 +356,45 @@ extern "C" {
  * @see execvp()
  */
 #ifndef _di_fll_execute_program_
-  extern f_return_status fll_execute_program(const f_string program_name, const f_string_dynamics arguments, int *result);
+  extern f_return_status fll_execute_program(const f_string program_name, const f_string_statics arguments, int *result);
 #endif // _di_fll_execute_program_
 
+/**
+ * Execute a program given by name found in the PATH environment (such as "bash").
+ *
+ * Uses the provided environment array to designate the environment for the called program.
+ *
+ * @todo this probably needs special work to find the program from PATH when PATH environment variable gets cleared before execution.
+ *
+ * @param program_name
+ *   The name of the program.
+ * @param arguments
+ *   An array of strings representing the arguments.
+ * @param names
+ *   An array of strings representing the environment variable names.
+ *   At most names.used variables are created.
+ *   Duplicate names are overwritten.
+ * @param values
+ *   An array of strings representing the environment variable names.
+ *   The values.used must be of at least names.used.
+ *   Set individual strings.used to 0 for empty/null values.
+ * @param result
+ *   The code returned after finishing execution of program.
+ *
+ * @return
+ *   f_none on success.
+ *   f_failure (with error bit) if result is non-zero.
+ *   f_fork_failed (with error bit) on fork failure.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_error_allocation (with error bit) on allocation error.
+ *   f_error_reallocation (with error bit) on reallocation error.
+ *
+ * @see execvpe()
+ */
+#ifndef _di_fll_execute_program_environment_
+  extern f_return_status fll_execute_program_environment(const f_string program_name, const f_string_statics arguments, const f_string_statics names, const f_string_statics values, int *result);
+#endif // _di_fll_execute_program_environment_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/level_2/fll_execute/data/build/defines b/level_2/fll_execute/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
index 4804427cfaf4ad3129354334e7f2950cd6bfbfc4..c33a8e48e19217a28548f8ae24bbca3eab488144 100644 (file)
@@ -2,4 +2,5 @@ f_type
 f_status
 f_memory
 f_string
+f_environment
 fl_string
index c51b88da61e3e79f797b4fdb7f18304ba7a2c377..e9f161ef0c40433bc9e2ecc7b2d1509829bee62b 100644 (file)
@@ -10,7 +10,7 @@ version_micro 0
 build_compiler gcc
 build_linker ar
 build_libraries -lc
-build_libraries_fll -lfl_string -lf_memory
+build_libraries_fll -lfl_string -lf_environment -lf_memory
 build_sources_library execute.c private-execute.c
 build_sources_program
 build_sources_headers execute.h
diff --git a/level_2/fll_file/data/build/defines b/level_2/fll_file/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
index e71bb1ca0649603aff50cd4c4053ee73e94070fc..d1f506a443170f04e8b1002005f6d63532a859fc 100644 (file)
@@ -143,7 +143,7 @@ extern "C" {
 #endif // _di_fll_fss_basic_read_
 
 #ifndef _di_fll_fss_basic_write_
-  f_return_status fll_fss_basic_write(const f_string_static object, const f_string_dynamics contents, f_string_dynamic *buffer) {
+  f_return_status fll_fss_basic_write(const f_string_static object, const f_string_statics contents, f_string_dynamic *buffer) {
     #ifndef _di_level_2_parameter_checking_
       if (buffer == 0) return f_status_set_error(f_invalid_parameter);
       if (contents.used > contents.size) return f_status_set_error(f_invalid_parameter);
index 18032a5b2e70b5760bdab83ba238d7919d02a334..1eda122f08842b8cb48ac88533f455ae449c9fdf 100644 (file)
@@ -79,7 +79,7 @@ extern "C" {
  *   f_invalid_parameter (with error bit) if a parameter is invalid.
  */
 #ifndef _di_fll_fss_basic_write_
-  extern f_return_status fll_fss_basic_write(const f_string_static object, const f_string_dynamics contents, f_string_dynamic *buffer);
+  extern f_return_status fll_fss_basic_write(const f_string_static object, const f_string_statics contents, f_string_dynamic *buffer);
 #endif // _di_fll_fss_basic_write_
 
 #ifdef __cplusplus
index ff2c4bf20f53858aedc14f80f35cafd380983c9b..1d199ab0c9c19baecb467558262d368238c6ac4a 100644 (file)
@@ -143,7 +143,7 @@ extern "C" {
 #endif // _di_fll_fss_basic_list_read_
 
 #ifndef _di_fll_fss_basic_list_write_
-  f_return_status fll_fss_basic_list_write(const f_string_static object, const f_string_dynamics contents, f_string_dynamic *buffer) {
+  f_return_status fll_fss_basic_list_write(const f_string_static object, const f_string_statics contents, f_string_dynamic *buffer) {
     #ifndef _di_level_2_parameter_checking_
       if (buffer == 0) return f_status_set_error(f_invalid_parameter);
       if (contents.used > contents.size) return f_status_set_error(f_invalid_parameter);
index 8ac24a3cc91b1a0dffbef870b866a2cda5affc18..f201b2a009396be9d8ce7c23bc626a5df4dfd912 100644 (file)
@@ -78,7 +78,7 @@ extern "C" {
  *   f_invalid_parameter (with error bit) if a parameter is invalid.
  */
 #ifndef _di_fll_fss_basic_list_write_
-  extern f_return_status fll_fss_basic_list_write(const f_string_static object, const f_string_dynamics contents, f_string_dynamic *buffer);
+  extern f_return_status fll_fss_basic_list_write(const f_string_static object, const f_string_statics contents, f_string_dynamic *buffer);
 #endif // _di_fll_fss_basic_list_write_
 
 #ifdef __cplusplus
index a5662383ee9df173c53268df9abeafba07b83ace..20cdef0bf857227c29b1e14d39b26c452de7dff2 100644 (file)
@@ -143,7 +143,7 @@ extern "C" {
 #endif // _di_fll_fss_extended_read_
 
 #ifndef _di_fll_fss_extended_write_
-  f_return_status fll_fss_extended_write(const f_string_static object, const f_string_dynamics contents, f_string_dynamic *buffer) {
+  f_return_status fll_fss_extended_write(const f_string_static object, const f_string_statics contents, f_string_dynamic *buffer) {
     #ifndef _di_level_2_parameter_checking_
       if (buffer == 0) return f_status_set_error(f_invalid_parameter);
       if (contents.used > contents.size) return f_status_set_error(f_invalid_parameter);
index 0a6fdc376bd5f7becf31dd772f1070d7467c8d9a..8d1dde7fab3474de54b99bc4aef3afdab99e5805 100644 (file)
@@ -78,7 +78,7 @@ extern "C" {
  *   f_invalid_parameter (with error bit) if a parameter is invalid.
  */
 #ifndef _di_fll_fss_extended_write_
-  extern f_return_status fll_fss_extended_write(const f_string_static object, const f_string_dynamics contents, f_string_dynamic *buffer);
+  extern f_return_status fll_fss_extended_write(const f_string_static object, const f_string_statics contents, f_string_dynamic *buffer);
 #endif // _di_fll_fss_extended_write_
 
 #ifdef __cplusplus
index a9b60247d9be9052286d811023208b4b7d92d016..96971c60fa66265a321aa475509409db487ef377 100644 (file)
@@ -113,7 +113,7 @@ extern "C" {
 
 /*
 #ifndef _di_fll_fss_extended_list_write_
-  f_return_status fll_fss_extended_list_write(const f_string_static object, const f_string_dynamics contents, f_string_dynamic *buffer) {
+  f_return_status fll_fss_extended_list_write(const f_string_static object, const f_string_statics contents, f_string_dynamic *buffer) {
     #ifndef _di_level_3_parameter_checking_
       if (buffer == 0) return f_status_set_error(f_invalid_parameter);
       if (contents.used > contents.size) return f_status_set_error(f_invalid_parameter);
index 0ab413f518c24b21a8d42affb4e2d1b4117871e4..f3c635447fd5f3290bffe3e88a1831500613cf3c 100644 (file)
@@ -83,7 +83,7 @@ extern "C" {
  *   f_invalid_parameter (with error bit) if a parameter is invalid.
  */
 #ifndef _di_fll_fss_extended_list_write_
-  //extern f_return_status fll_fss_extended_list_write(const f_string_static object, const f_string_dynamics contents, f_string_dynamic *buffer);
+  //extern f_return_status fll_fss_extended_list_write(const f_string_static object, const f_string_statics contents, f_string_dynamic *buffer);
 #endif // _di_fll_fss_extended_list_write_
 
 #ifdef __cplusplus
diff --git a/level_2/fll_fss/data/build/defines b/level_2/fll_fss/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_2/fll_program/data/build/defines b/level_2/fll_program/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
index be2b8f383df20c8c8d0ee2c2713f4a517f0d0b04..fc8ec3cd25c673607e4748b977f43bbb795dba90 100644 (file)
@@ -1186,16 +1186,6 @@ extern "C" {
         return f_none;
       }
 
-      if (fl_string_compare(string, fl_status_string_directory_allocation_error, length, fl_status_string_directory_allocation_error_length) == f_equal_to) {
-        *code = f_directory_error_allocation;
-        return f_none;
-      }
-
-      if (fl_string_compare(string, fl_status_string_directory_reallocation_error, length, fl_status_string_directory_reallocation_error_length) == f_equal_to) {
-        *code = f_directory_error_reallocation;
-        return f_none;
-      }
-
       if (fl_string_compare(string, fl_status_string_directory_error, length, fl_status_string_directory_error_length) == f_equal_to) {
         *code = f_directory_error;
         return f_none;
diff --git a/level_2/fll_status/data/build/defines b/level_2/fll_status/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/byte_dump/data/build/defines b/level_3/byte_dump/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/fss_basic_list_read/data/build/defines b/level_3/fss_basic_list_read/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/fss_basic_list_write/data/build/defines b/level_3/fss_basic_list_write/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/fss_basic_read/data/build/defines b/level_3/fss_basic_read/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/fss_basic_write/data/build/defines b/level_3/fss_basic_write/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/fss_extended_list_read/data/build/defines b/level_3/fss_extended_list_read/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/fss_extended_read/data/build/defines b/level_3/fss_extended_read/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/fss_extended_write/data/build/defines b/level_3/fss_extended_write/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/fss_status_code/data/build/defines b/level_3/fss_status_code/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/init/data/build/defines b/level_3/init/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+
diff --git a/level_3/status_code/data/build/defines b/level_3/status_code/data/build/defines
new file mode 100644 (file)
index 0000000..c665317
--- /dev/null
@@ -0,0 +1,2 @@
+# fss-0000
+