A get all environment variables function should exist.
The POSIX/libc standards do not seem to provide one.
Utilize the "environ" variable to load all of the environment variables into a string map array.
extern "C" {
#endif
+// for loading all current environment variables.
+extern char **environ;
+
#ifndef _di_f_environment_clear_
f_status_t f_environment_clear(void) {
}
#endif // _di_f_environment_get_
+#ifndef _di_f_environment_get_all_
+ f_status_t f_environment_get_all(f_string_maps_t * const environment) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!environment) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ f_status_t status = F_none;
+ char *at = 0;
+ f_string_map_t map = f_string_map_t_initialize;
+
+ // Copy all environment variables over when a custom define is used.
+ for (char **string = environ; *string; string++) {
+
+ map.name.string = 0;
+ map.value.string = 0;
+
+ map.name.used = 0;
+ map.value.used = 0;
+
+ at = index(*string, f_string_ascii_equal_s.string[0]);
+ if (!at || at == *string) continue;
+
+ map.name.string = *string;
+ map.name.used = at - *string;
+
+ map.value.string = at + 1;
+ map.value.used = strlen(at + 1);
+
+ status = f_string_maps_append(map, environment);
+ if (F_status_is_error(status)) return status;
+ } // for
+
+ return F_none;
+ }
+#endif // _di_f_environment_get_all_
+
#ifndef _di_f_environment_secure_is_
f_status_t f_environment_secure_is(void) {
#endif // _di_f_environment_get_
/**
+ * Get all environment variables.
+ *
+ * The variables are copied into a new dynamically allocated map and is safe to alter.
+ *
+ * @param environment
+ * An array of maps containing all available environment variable name and value pairs.
+ *
+ * @return
+ * F_none on success.
+ *
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * Errors (with error bit) from: f_string_maps_append().
+ *
+ * @see f_string_maps_append()
+ */
+#ifndef _di_f_environment_get_all_
+ extern f_status_t f_environment_get_all(f_string_maps_t * const environment);
+#endif // _di_f_environment_get_all_
+
+/**
* Check to see if the environment is secure for calling getenv() safely for "secure execution".
*
* This is intended to closely mimic the checks secure_getenv().
build_libraries -lc -lcmocka
build_libraries-individual -lf_memory -lf_string -lf_environment
-build_sources_program test-environment-clear.c test-environment-exists.c test-environment-get.c test-environment-secure_is.c test-environment-set.c test-environment-unset.c
+build_sources_program test-environment-clear.c test-environment-exists.c test-environment-get.c test-environment-get_all.c test-environment-secure_is.c test-environment-set.c test-environment-unset.c
build_sources_program test-environment.c
build_script no
--- /dev/null
+#include "test-environment.h"
+#include "test-environment-get.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_environment_get_all__parameter_checking(void **state) {
+
+ {
+ const f_status_t status = f_environment_get_all(0);
+
+ assert_int_equal(status, F_status_set_error(F_parameter));
+ }
+}
+
+void test__f_environment_get_all__works(void **state) {
+
+ const f_string_static_t name = macro_f_string_static_t_initialize("test", 0, 4);
+ const f_string_static_t value = macro_f_string_static_t_initialize("works", 0, 5);
+
+ f_string_maps_t environment = f_string_maps_t_initialize;
+
+ {
+ // Cannot easily mock because this is used: extern char **environ;
+ clearenv();
+ setenv(name.string, value.string, true);
+
+ const f_status_t status = f_environment_get_all(&environment);
+
+ assert_int_equal(status, F_none);
+ assert_int_equal(environment.used, 1);
+ assert_string_equal(environment.array[0].name.string, name.string);
+ assert_string_equal(environment.array[0].value.string, value.string);
+ }
+
+ f_string_maps_resize(0, &environment);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Environment
+ * API Version: 0.6
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the environment project.
+ */
+#ifndef _TEST__F_environment_get_all_h
+#define _TEST__F_environment_get_all_h
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_environment_get_all()
+ */
+extern void test__f_environment_get_all__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_environment_get_all()
+ */
+extern void test__f_environment_get_all__works(void **state);
+
+#endif // _TEST__F_environment_get_all_h
cmocka_unit_test(test__f_environment_get__returns_data_not),
cmocka_unit_test(test__f_environment_get__works),
+ cmocka_unit_test(test__f_environment_get_all__works),
+
cmocka_unit_test(test__f_environment_secure_is__fails),
cmocka_unit_test(test__f_environment_secure_is__works),
// f_environment_clear() doesn't use parameter checking.
// f_environment_exists() doesn't use parameter checking.
cmocka_unit_test(test__f_environment_get__parameter_checking),
+ cmocka_unit_test(test__f_environment_get_all__parameter_checking),
// f_environment_secure_is() doesn't use parameter checking.
// f_environment_set() doesn't use parameter checking.
// f_environment_unset() doesn't use parameter checking.
#include "test-environment-clear.h"
#include "test-environment-exists.h"
#include "test-environment-get.h"
+#include "test-environment-get_all.h"
#include "test-environment-secure_is.h"
#include "test-environment-set.h"
#include "test-environment-unset.h"