From 2373d5db5b4cd5dfe139aa2a10017ef61b28b5ce Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Tue, 25 Dec 2018 16:57:21 +0100 Subject: [PATCH] ecore: here comes a env object the env object can be used to alter and edit the content of environment variables. Additionally, the class efl.core.env can be used to to setup a not applied set of environment variables, which then can be applied later (in the future) to set it directly to a spawned process for example, or as a general key/data storage. A efl.core.env object can also be forked off, which makes it easy to customize predefined objects. ref T7514 Differential Revision: https://phab.enlightenment.org/D7510 --- header_checks/meson.build | 3 +- meson.build | 1 + src/Makefile_Ecore.am | 7 +- src/lib/ecore/Ecore_Eo.h | 3 + src/lib/ecore/efl_core_env.c | 107 +++++++++++++++++++++ src/lib/ecore/efl_core_env.eo | 57 ++++++++++++ src/lib/ecore/efl_core_proc_env.c | 145 +++++++++++++++++++++++++++++ src/lib/ecore/efl_core_proc_env.eo | 21 +++++ src/lib/ecore/meson.build | 6 +- src/tests/ecore/efl_app_suite.c | 2 +- src/tests/ecore/efl_app_suite.h | 1 + src/tests/ecore/efl_app_test_env.c | 135 +++++++++++++++++++++++++++ src/tests/ecore/meson.build | 3 +- 13 files changed, 486 insertions(+), 5 deletions(-) create mode 100644 src/lib/ecore/efl_core_env.c create mode 100644 src/lib/ecore/efl_core_env.eo create mode 100644 src/lib/ecore/efl_core_proc_env.c create mode 100644 src/lib/ecore/efl_core_proc_env.eo create mode 100644 src/tests/ecore/efl_app_test_env.c diff --git a/header_checks/meson.build b/header_checks/meson.build index b23e774ec1..066d228a83 100644 --- a/header_checks/meson.build +++ b/header_checks/meson.build @@ -53,7 +53,8 @@ header_checks = [ 'langinfo.h', 'locale.h', 'uv.h', - 'ws2tcpip.h' + 'ws2tcpip.h', + 'crt_externs.h' ] function_checks = [ diff --git a/meson.build b/meson.build index 0e2a50c2c9..d6b9b6074d 100644 --- a/meson.build +++ b/meson.build @@ -210,6 +210,7 @@ elif sys_osx == true sys_lib_extension = 'dylib' sys_exe_extension = '' sys_mod_extension = 'dylib' + config_h.set('environ', '(*_NSGetEnviron())') else error('System '+host_machine.system()+' not known') endif diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am index 7bc8e43b74..5f10ea7f2e 100644 --- a/src/Makefile_Ecore.am +++ b/src/Makefile_Ecore.am @@ -49,7 +49,9 @@ ecore_eolian_files_public = \ lib/ecore/efl_boolean_model.eo \ lib/ecore/efl_select_model.eo \ lib/ecore/efl_composite_model.eo \ - lib/ecore/efl_view_model.eo + lib/ecore/efl_view_model.eo \ + lib/ecore/efl_core_env.eo \ + lib/ecore/efl_core_proc_env.eo \ ecore_eolian_files = \ $(ecore_eolian_files_legacy) \ @@ -98,6 +100,8 @@ lib/ecore/ecore_job.c \ lib/ecore/ecore_main.c \ lib/ecore/ecore_event_message.c \ lib/ecore/ecore_event_message_handler.c \ +lib/ecore/efl_core_env.c \ +lib/ecore/efl_core_proc_env.c \ lib/ecore/efl_app.c \ lib/ecore/efl_loop.c \ lib/ecore/efl_loop_consumer.c \ @@ -335,6 +339,7 @@ tests/ecore/efl_app_test_loop.c \ tests/ecore/efl_app_test_loop_fd.c \ tests/ecore/efl_app_test_loop_timer.c \ tests/ecore/efl_app_test_promise.c \ +tests/ecore/efl_app_test_env.c \ tests/ecore/efl_app_suite.c \ tests/ecore/efl_app_suite.h diff --git a/src/lib/ecore/Ecore_Eo.h b/src/lib/ecore/Ecore_Eo.h index 6a21ff5ea7..348b0f5b6d 100644 --- a/src/lib/ecore/Ecore_Eo.h +++ b/src/lib/ecore/Ecore_Eo.h @@ -26,6 +26,9 @@ * @{ */ +#include "efl_core_env.eo.h" +#include "efl_core_proc_env.eo.h" + #include "efl_loop_message.eo.h" #include "efl_loop_message_handler.eo.h" diff --git a/src/lib/ecore/efl_core_env.c b/src/lib/ecore/efl_core_env.c new file mode 100644 index 0000000000..38fc9ba1a9 --- /dev/null +++ b/src/lib/ecore/efl_core_env.c @@ -0,0 +1,107 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "ecore_private.h" + +#define MY_CLASS EFL_CORE_ENV_CLASS + +extern char **environ; + +typedef struct { + Eina_Hash *env; +} Efl_Core_Env_Data; + +static inline Eina_Bool +str_valid(const char *var) +{ + return var && var[0] != '\0'; +} + +static inline Eina_Bool +key_valid(const char *key) +{ + if (!key || key[0] == '\0') return EINA_FALSE; + + if isdigit(key[0]) return EINA_FALSE; + + for (int i = 0; key[i] != '\0'; ++i) { + if (!isalnum(key[i]) && key[i] != '_') return EINA_FALSE; + } + + return EINA_TRUE; +} + +EOLIAN static void +_efl_core_env_env_set(Eo *obj EINA_UNUSED, Efl_Core_Env_Data *pd, const char *var, const char *value) +{ + EINA_SAFETY_ON_FALSE_RETURN(key_valid(var)); + if (str_valid(value)) + { + Eina_Stringshare *share; + share = eina_hash_set(pd->env, var, eina_stringshare_add(value)); + if (share) eina_stringshare_del(share); + } + else + eina_hash_del(pd->env, var, NULL); +} + +EOLIAN static const char* +_efl_core_env_env_get(const Eo *obj EINA_UNUSED, Efl_Core_Env_Data *pd, const char *var) +{ + EINA_SAFETY_ON_FALSE_RETURN_VAL(key_valid(var), NULL); + + return eina_hash_find(pd->env, var); +} + +EOLIAN static void +_efl_core_env_unset(Eo *obj EINA_UNUSED, Efl_Core_Env_Data *pd, const char *var) +{ + EINA_SAFETY_ON_FALSE_RETURN(key_valid(var)); + eina_hash_del_by_key(pd->env, var); +} + +EOLIAN static void +_efl_core_env_clear(Eo *obj EINA_UNUSED, Efl_Core_Env_Data *pd) +{ + eina_hash_free_buckets(pd->env); +} + +EOLIAN static Efl_Core_Env* +_efl_core_env_efl_duplicate_duplicate(const Eo *obj EINA_UNUSED, Efl_Core_Env_Data *pd) +{ + Efl_Core_Env *fork = efl_add_ref(MY_CLASS, NULL); + Eina_Iterator *iter; + Eina_Hash_Tuple *tuple; + + iter = eina_hash_iterator_tuple_new(pd->env); + + EINA_ITERATOR_FOREACH(iter, tuple) + { + efl_core_env_set(fork, tuple->key, tuple->data); + } + + eina_iterator_free(iter); + return fork; +} + +EOLIAN static Efl_Object* +_efl_core_env_efl_object_constructor(Eo *obj, Efl_Core_Env_Data *pd) +{ + pd->env = eina_hash_string_superfast_new((Eina_Free_Cb)eina_stringshare_del); + + return efl_constructor(efl_super(obj, MY_CLASS)); +} + +EOLIAN static Eina_Iterator* +_efl_core_env_content_get(const Eo *obj EINA_UNUSED, Efl_Core_Env_Data *pd) +{ + Eina_Iterator *iter = eina_hash_iterator_key_new(pd->env); + return iter; +} + + +#include "efl_core_env.eo.c" diff --git a/src/lib/ecore/efl_core_env.eo b/src/lib/ecore/efl_core_env.eo new file mode 100644 index 0000000000..86da8c14ff --- /dev/null +++ b/src/lib/ecore/efl_core_env.eo @@ -0,0 +1,57 @@ +class Efl.Core.Env extends Efl.Object implements Efl.Duplicate { + [[This object can maintain a set of key value pairs + + A object of this type alone does not apply the object to the system. + For getting the value into the system, see @Efl.Core.Proc_Env. + + A object can be forked, which will only copy its values, changes to the returned object will not change the object where it is forked off. + ]] + methods { + @property env { + [[ Stored var value pairs of this object. + + Var must contain only: underscores ('_'), letters ('a-z', 'A-Z'), + numbers ('0-9'), but the first character may not be a number. + ]] + set { + [[ Add a new pair to this object ]] + } + get { + [[ Get the value of the $var, or $null if no such $var exists in the object]] + } + keys { + var: string; [[ The name of the variable ]] + } + values { + value: string; [[ Set var to this value if not $NULL, + otherwise clear this env value if value + is $NULL or if it is an empty string ]] + } + } + unset { + [[ Remove the pair with the matching $var from this object]] + params { + var : string; [[ The name of the variable ]] + } + } + clear { + [[ Remove all pairs from this object]] + } + @property content { + [[ Get the content of this object. + + This will return a iterator that contains all keys that are part of this object. + ]] + get { + + } + values { + iter : iterator; + } + } + } + implements { + Efl.Object.constructor; + Efl.Duplicate.duplicate; + } +} diff --git a/src/lib/ecore/efl_core_proc_env.c b/src/lib/ecore/efl_core_proc_env.c new file mode 100644 index 0000000000..846b69a350 --- /dev/null +++ b/src/lib/ecore/efl_core_proc_env.c @@ -0,0 +1,145 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#ifdef HAVE_CRT_EXTERNS_H +# include +#endif +#include "ecore_private.h" + +#define MY_CLASS EFL_CORE_PROC_ENV_CLASS + +static Efl_Core_Env *env = NULL; + +typedef struct { + Eina_Bool in_sync; +} Efl_Core_Proc_Env_Data; + +static void +_sync(Efl_Core_Env *obj, Efl_Core_Proc_Env_Data *pd) +{ + Eina_List *existing_keys = NULL, *n; + Eina_Iterator *content; + const char *key; + + pd->in_sync = EINA_TRUE; + content = efl_core_env_content_get(obj); + + EINA_ITERATOR_FOREACH(content, key) + { + existing_keys = eina_list_append(existing_keys, key); + } + + if (environ) + { + char **p; + + for (p = environ; *p; p++) + { + char **values; + + values = eina_str_split(*p, "=", 2); + efl_core_env_set(obj, values[0], values[1]); + + EINA_LIST_FOREACH(existing_keys, n, key) + { + if (!strcmp(key, values[0])) + { + existing_keys = eina_list_remove_list(existing_keys, n); + break; + } + } + } + } + EINA_LIST_FOREACH(existing_keys, n, key) + { + efl_core_env_unset(obj, key); + } + pd->in_sync = EINA_FALSE; +} + +EOLIAN static const char* +_efl_core_proc_env_efl_core_env_env_get(const Eo *obj, Efl_Core_Proc_Env_Data *pd, const char *var) +{ + if (!pd->in_sync) + _sync((Eo*)obj, pd); + return efl_core_env_get(efl_super(obj, MY_CLASS), var); +} + +EOLIAN static void +_efl_core_proc_env_efl_core_env_env_set(Eo *obj, Efl_Core_Proc_Env_Data *pd, const char *var, const char *value) +{ + efl_core_env_set(efl_super(obj, MY_CLASS), var, value); + if (!pd->in_sync) + { + if (value) + setenv(var, value, 1); + else + unsetenv(var); + } +} + +EOLIAN static void +_efl_core_proc_env_efl_core_env_unset(Eo *obj, Efl_Core_Proc_Env_Data *pd, const char *key) +{ + efl_core_env_unset(efl_super(obj, MY_CLASS), key); + if (!pd->in_sync) + { + unsetenv(key); + } +} + +EOLIAN static void +_efl_core_proc_env_efl_core_env_clear(Eo *obj, Efl_Core_Proc_Env_Data *pd) +{ + efl_core_env_clear(efl_super(obj, MY_CLASS)); + if (!pd->in_sync) + { +#ifdef HAVE_CLEARENV + clearenv(); +#else + environ = NULL; +#endif + } +} + + +EOLIAN static Efl_Duplicate* +_efl_core_proc_env_efl_duplicate_duplicate(const Eo *obj, Efl_Core_Proc_Env_Data *pd) +{ + if (!pd->in_sync) + _sync((Eo*) obj, pd); + return efl_duplicate(efl_super(obj, MY_CLASS)); +} + +EOLIAN static Eina_Iterator* +_efl_core_proc_env_efl_core_env_content_get(const Eo *obj, Efl_Core_Proc_Env_Data *pd) +{ + if (!pd->in_sync) + _sync((Eo*) obj, pd); + return efl_core_env_content_get(efl_super(obj, MY_CLASS)); +} + +EOLIAN static Efl_Object* +_efl_core_proc_env_efl_object_constructor(Eo *obj, Efl_Core_Proc_Env_Data *pd EINA_UNUSED) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL(!!env, NULL); + + obj = efl_constructor(efl_super(obj, MY_CLASS)); + return obj; +} + +EOLIAN static Efl_Core_Env* +_efl_core_proc_env_self(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED) +{ + if (!env) + { + env = efl_add_ref(EFL_CORE_PROC_ENV_CLASS, NULL); + efl_wref_add(env, &env); + } + + return env; +} + +#include "efl_core_proc_env.eo.c" diff --git a/src/lib/ecore/efl_core_proc_env.eo b/src/lib/ecore/efl_core_proc_env.eo new file mode 100644 index 0000000000..23c2c67d75 --- /dev/null +++ b/src/lib/ecore/efl_core_proc_env.eo @@ -0,0 +1,21 @@ +class Efl.Core.Proc_Env extends Efl.Core.Env +{ + eo_prefix : efl_env; + methods { + self @class { + [[Get a instance of this object + + The object will apply the environment operations onto this process. + ]] + return : Efl.Core.Env; + } + } + implements { + Efl.Core.Env.env { set; get; } + Efl.Core.Env.content { get; } + Efl.Core.Env.unset; + Efl.Core.Env.clear; + Efl.Duplicate.duplicate; + Efl.Object.constructor; + } +} diff --git a/src/lib/ecore/meson.build b/src/lib/ecore/meson.build index baa5263698..98909cb618 100644 --- a/src/lib/ecore/meson.build +++ b/src/lib/ecore/meson.build @@ -74,7 +74,9 @@ pub_eo_files = [ 'efl_boolean_model.eo', 'efl_select_model.eo', 'efl_composite_model.eo', - 'efl_view_model.eo' + 'efl_view_model.eo', + 'efl_core_env.eo', + 'efl_core_proc_env.eo' ] foreach eo_file : pub_eo_files @@ -180,6 +182,8 @@ ecore_src = [ 'efl_thread.c', 'efl_threadio.c', 'efl_appthread.c', + 'efl_core_env.c', + 'efl_core_proc_env.c', ] if sys_windows == true diff --git a/src/tests/ecore/efl_app_suite.c b/src/tests/ecore/efl_app_suite.c index b3be09915a..cd26e2d95e 100644 --- a/src/tests/ecore/efl_app_suite.c +++ b/src/tests/ecore/efl_app_suite.c @@ -9,7 +9,6 @@ #include "efl_app_suite.h" #include "../efl_check.h" - EFL_START_TEST(efl_app_test_efl_build_version) { const Efl_Version *ver; @@ -53,6 +52,7 @@ static const Efl_Test_Case etc[] = { { "Promise", efl_app_test_promise_2 }, { "Promise", efl_app_test_promise_3 }, { "Promise", efl_app_test_promise_safety }, + { "Env", efl_test_efl_env }, { NULL, NULL } }; diff --git a/src/tests/ecore/efl_app_suite.h b/src/tests/ecore/efl_app_suite.h index 29ed8f031f..3a66dcdfcf 100644 --- a/src/tests/ecore/efl_app_suite.h +++ b/src/tests/ecore/efl_app_suite.h @@ -11,5 +11,6 @@ void efl_app_test_promise(TCase *tc); void efl_app_test_promise_2(TCase *tc); void efl_app_test_promise_3(TCase *tc); void efl_app_test_promise_safety(TCase *tc); +void efl_test_efl_env(TCase *tc); #endif /* _EFL_APP_SUITE_H */ diff --git a/src/tests/ecore/efl_app_test_env.c b/src/tests/ecore/efl_app_test_env.c new file mode 100644 index 0000000000..63bad166a2 --- /dev/null +++ b/src/tests/ecore/efl_app_test_env.c @@ -0,0 +1,135 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#define EFL_NOLEGACY_API_SUPPORT +#include +#include "efl_app_suite.h" +#include "../efl_check.h" + +EFL_START_TEST(efl_core_env_test_set_get) +{ + Efl_Core_Env *env = efl_add_ref(EFL_CORE_ENV_CLASS, NULL); + + efl_core_env_set(env, "FOO", "bar"); + efl_core_env_set(env, "going", "home"); + efl_core_env_set(env, "Merry", "christmas"); + + ck_assert_str_eq(efl_core_env_get(env, "FOO"), "bar"); + ck_assert_str_eq(efl_core_env_get(env, "going"), "home"); + ck_assert_str_eq(efl_core_env_get(env, "Merry"), "christmas"); + + efl_core_env_unset(env, "Merry"); + + ck_assert_str_eq(efl_core_env_get(env, "FOO"), "bar"); + ck_assert_str_eq(efl_core_env_get(env, "going"), "home"); + ck_assert_ptr_eq(efl_core_env_get(env, "Merry"), NULL); + + efl_unref(env); +} +EFL_END_TEST + +EFL_START_TEST(efl_core_env_test_invalid_keys) +{ + Efl_Core_Env *env = efl_add_ref(EFL_CORE_ENV_CLASS, NULL); + +#define CHECK(val) \ + efl_core_env_set(env, val, "TEST"); \ + ck_assert_ptr_eq(efl_core_env_get(env, val), NULL); + + CHECK("0foo"); + CHECK("foo bar"); + CHECK("foo!bar"); + +#undef CHECK + + +#define CHECK(val) \ + efl_core_env_set(env, val, "TEST"); \ + ck_assert_str_eq(efl_core_env_get(env, val), "TEST"); + + CHECK("foo0"); + CHECK("foo_bar"); + +#undef CHECK + +} +EFL_END_TEST + +EFL_START_TEST(efl_core_env_test_clear) +{ + Efl_Core_Env *env = efl_add_ref(EFL_CORE_ENV_CLASS, NULL); + + efl_core_env_set(env, "FOO", "bar"); + efl_core_env_set(env, "going", "home"); + efl_core_env_set(env, "Merry", "christmas"); + + efl_core_env_clear(env); + + ck_assert_ptr_eq(efl_core_env_get(env, "FOO"), NULL); + ck_assert_ptr_eq(efl_core_env_get(env, "going"), NULL); + ck_assert_ptr_eq(efl_core_env_get(env, "Merry"), NULL); + + efl_unref(env); +} +EFL_END_TEST + +EFL_START_TEST(efl_core_env_test_fork) +{ + Efl_Core_Env *env_fork, *env = efl_add_ref(EFL_CORE_ENV_CLASS, NULL); + + efl_core_env_set(env, "FOO", "bar"); + efl_core_env_set(env, "going", "home"); + efl_core_env_set(env, "Merry", "christmas"); + + env_fork = efl_duplicate(env); + + ck_assert_str_eq(efl_core_env_get(env_fork, "FOO"), "bar"); + ck_assert_str_eq(efl_core_env_get(env_fork, "going"), "home"); + ck_assert_str_eq(efl_core_env_get(env_fork, "Merry"), "christmas"); + + efl_unref(env); +} +EFL_END_TEST + +EFL_START_TEST(efl_core_env_test_process) +{ + Efl_Core_Env *env_fork, *env = efl_env_self(EFL_CORE_PROC_ENV_CLASS); + + ck_assert(env); + + ck_assert_str_eq(efl_core_env_get(env, "PATH"), getenv("PATH")); + env_fork = efl_duplicate(env); + ck_assert_str_eq(efl_core_env_get(env_fork, "PATH"), getenv("PATH")); + + efl_unref(env); +} +EFL_END_TEST + +EFL_START_TEST(efl_core_env_test_undepend_fork) +{ + Efl_Core_Env *env_fork, *env = efl_env_self(EFL_CORE_PROC_ENV_CLASS); + + ck_assert(env); + + ck_assert_str_eq(efl_core_env_get(env, "PATH"), getenv("PATH")); + env_fork = efl_duplicate(env); + efl_core_env_set(env_fork, "PATH", "abc"); + ck_assert_str_eq(efl_core_env_get(env, "PATH"), getenv("PATH")); + + efl_unref(env); + efl_unref(env_fork); +} +EFL_END_TEST + +void efl_test_efl_env(TCase *tc) +{ + tcase_add_test(tc, efl_core_env_test_set_get); + tcase_add_test(tc, efl_core_env_test_invalid_keys); + tcase_add_test(tc, efl_core_env_test_clear); + tcase_add_test(tc, efl_core_env_test_fork); + tcase_add_test(tc, efl_core_env_test_process); + tcase_add_test(tc, efl_core_env_test_undepend_fork); +} diff --git a/src/tests/ecore/meson.build b/src/tests/ecore/meson.build index 4b46814bbe..e3b4f6c851 100644 --- a/src/tests/ecore/meson.build +++ b/src/tests/ecore/meson.build @@ -75,7 +75,8 @@ efl_app_suite_src = [ 'efl_app_test_loop.c', 'efl_app_test_loop_fd.c', 'efl_app_test_loop_timer.c', - 'efl_app_test_promise.c' + 'efl_app_test_promise.c', + 'efl_app_test_env.c' ] efl_app_suite_deps = [m]