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.
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
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
--- /dev/null
+# fss-0000
+
* - 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"
#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"
#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
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
/**
* 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_
--- /dev/null
+# fss-0000
+
--- /dev/null
+#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
--- /dev/null
+/**
+ * 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
--- /dev/null
+#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
--- /dev/null
+/**
+ * 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
--- /dev/null
+# fss-0000
+
--- /dev/null
+f_type
+f_status
+f_memory
+f_string
--- /dev/null
+# 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
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
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,
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,
--- /dev/null
+# fss-0000
+
#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.
* 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) \
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
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;
#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
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
#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);
}
#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);
}
#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
#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>
* @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
* @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
--- /dev/null
+# fss-0000
+
f_status
f_memory
f_string
+f_environment
fl_string
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
--- /dev/null
+# fss-0000
+
#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);
* 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
#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);
* 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
#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);
* 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
/*
#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);
* 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
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
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;
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+