Hi, On 2/13/19 11:00 AM, Carsten Haitzler (The Rasterman) wrote: > On Tue, 12 Feb 2019 22:05:06 +0100 Marcel Hollerbach <m...@bu5hm4n.de> said: > >> Here is the try to get a technical discussion: > > let's solve these before landing, shll we? if they were just bugs i would have > fixed them, but as there are "bugs by design" it needs to go back to the > drawing > board.
Yes, that is why i am sticking things into review, and tbh. a ownership discussion is nothing that sends back things onto the drawing board :) >> 2.: >> Yes, this is a design decision for now, the string that is forming a >> command is not taken care of, reason for this is, that in most usecases >> that i have seen the strings are eitherway allocated on the stack of the >> function, or are global (argv) and are also not heap allocated (in our >> meaning). If this does not work out in other usecases, then i can >> happily agree with a patch to change that :) > > rethink ownership. but what you have is wrong. i have examples where they are > generated on the stack with multiple args .. so parent does have to allocate > space and cant use a single fixed size buffer. if ownership goes to the array > consistently then it's at least consistent (and the api consumes the array > entirely including strings), but it's not like this. i brought this up and it > was not addressed before landing the patch. Can you write some pseudocode? Because your example suites perfectly well what this is written for. You have: - Allocated strings on the stack, You do: - Allocate an eina_array - Add all your stack strings into it - Pass it to the function - Be happy with it. >> 4.: this will be fixed :) >> >> For anyone new to this discussion: This is about getting the abstraction >> of environment variables / command lines away from our generic task >> interface and get them into something which stands more alone, so it is >> more usable. > > let's get ownership sane and consistent. the env one is ok in that regard, > though i need to see the impl for the same env object when its NOT the global > (u e.g. create or duplicate then modify it). > > i still don't like it s its extra code/work for the caller for sure, but it > seems you guys all want to make efl worse to use from c. i'm beginning to > re-evaluate if i wish to use efl in future as it marches on in this direction. > i'm distinctly unhappy about it. Yeah, i even pinned a giant poster over my bed "Make C hard to use" so i really believe in it. No, but honestly, i am not trying to make life in C harder. Moving the POV from the amount of chars per API call, into something like usage range of our abstraction shows you that efl_task is now usable in a wider range, and even efl_env is more powerfull than before. Further more, compare the bindings code before and after the patches, you will see that the code integrates much nicer now, while its a little more (expressive) code in C. Greetings, bu5hm4n > >> Greetings, >> bu5hm4n >> >> On 2/12/19 9:26 PM, Carsten Haitzler wrote: >>> raster pushed a commit to branch master. >>> >>> http://git.enlightenment.org/core/efl.git/commit/?id=d6294fa22b88187e44391c1c8ca64b1ebdf14533 >>> >>> commit d6294fa22b88187e44391c1c8ca64b1ebdf14533 >>> Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com> >>> Date: Tue Feb 12 20:11:44 2019 +0000 >>> >>> Revert the env object because it's broken portability - please redo >>> >>> setenv and unsetenv are not portable. i explained to you at fosdem >>> there are issues and it's why i used putenv in the original >>> implementation and even though it's a pain (the string tou pass to >>> putenv is a pointer used literallt from there on in and you get it >>> from getenv, thus making ownership a pain -this is a libc issue we >>> can't readily solve). use putenv like the original code. then put it >>> back in. vtorri now has windows porting issues with the setenv use. i >>> knew there was a reason that still existed... >>> >>> in addition your in_sync stuff is broken. psuedocode: >>> >>> // assuming BLAGH env is not set to anything here >>> c = efl_core_env_get(global_env, "BLAH"); >>> ... >>> putenv("BLAH=10"); >>> ... >>> c = efl_core_env_Get(global_env, "BLAH"); >>> >>> i will get NULL in both cases for c ... but i should get "10" for the >>> 2nd in reality. reality is lots of code across application code and >>> libraries will at times mess with the environment. it has to work with >>> this. the prior implementation did work with this. >>> >>> Revert "ecore: here comes a env object" >>> This reverts commit 2373d5db5b4cd5dfe139aa2a10017ef61b28b5ce. >>> >>> Revert "efl_task: remove env from this object" >>> This reverts commit c3d69f66a69c0def357a5c373a13343e1c01ff5d. >>> --- >>> header_checks/meson.build | 3 +- >>> meson.build | 1 - >>> src/Makefile_Ecore.am | 7 +- >>> src/lib/ecore/Ecore_Eo.h | 3 - >>> src/lib/ecore/ecore_private.h | 1 + >>> src/lib/ecore/efl_core_env.c | 2 +- >>> 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/efl_exe.c | 67 +++++-------- >>> src/lib/ecore/efl_exe.eo | 17 ---- >>> src/lib/ecore/efl_loop.c | 189 ++++++++++++++++++++++++++++++++++ >>> +++ src/lib/ecore/efl_loop.eo | 2 + >>> src/lib/ecore/efl_task.c | 62 +++++++++++- >>> src/lib/ecore/efl_task.eo | 20 ++++ >>> 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 +- >>> 20 files changed, 305 insertions(+), 439 deletions(-) >>> >>> diff --git a/header_checks/meson.build b/header_checks/meson.build >>> index 066d228a83..b23e774ec1 100644 >>> --- a/header_checks/meson.build >>> +++ b/header_checks/meson.build >>> @@ -53,8 +53,7 @@ header_checks = [ >>> 'langinfo.h', >>> 'locale.h', >>> 'uv.h', >>> - 'ws2tcpip.h', >>> - 'crt_externs.h' >>> + 'ws2tcpip.h' >>> ] >>> >>> function_checks = [ >>> diff --git a/meson.build b/meson.build >>> index d6b9b6074d..0e2a50c2c9 100644 >>> --- a/meson.build >>> +++ b/meson.build >>> @@ -210,7 +210,6 @@ 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 5f10ea7f2e..7bc8e43b74 100644 >>> --- a/src/Makefile_Ecore.am >>> +++ b/src/Makefile_Ecore.am >>> @@ -49,9 +49,7 @@ 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_core_env.eo \ >>> - lib/ecore/efl_core_proc_env.eo \ >>> + lib/ecore/efl_view_model.eo >>> >>> ecore_eolian_files = \ >>> $(ecore_eolian_files_legacy) \ >>> @@ -100,8 +98,6 @@ 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 \ >>> @@ -339,7 +335,6 @@ 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 348b0f5b6d..6a21ff5ea7 100644 >>> --- a/src/lib/ecore/Ecore_Eo.h >>> +++ b/src/lib/ecore/Ecore_Eo.h >>> @@ -26,9 +26,6 @@ >>> * @{ >>> */ >>> >>> -#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/ecore_private.h b/src/lib/ecore/ecore_private.h >>> index 4e980d9123..c29f73d189 100644 >>> --- a/src/lib/ecore/ecore_private.h >>> +++ b/src/lib/ecore/ecore_private.h >>> @@ -188,6 +188,7 @@ struct _Efl_Task_Data >>> { >>> Eina_Stringshare *command; >>> Eina_Array *args; >>> + Eina_Hash *env; >>> Efl_Task_Priority priority; >>> int exit_code; >>> Efl_Task_Flags flags; >>> diff --git a/src/lib/ecore/efl_core_env.c b/src/lib/ecore/efl_core_env.c >>> index e0ee5a25e3..38fc9ba1a9 100644 >>> --- a/src/lib/ecore/efl_core_env.c >>> +++ b/src/lib/ecore/efl_core_env.c >>> @@ -26,7 +26,7 @@ key_valid(const char *key) >>> { >>> if (!key || key[0] == '\0') return EINA_FALSE; >>> >>> - if (isdigit(key[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; >>> diff --git a/src/lib/ecore/efl_core_env.eo b/src/lib/ecore/efl_core_env.eo >>> deleted file mode 100644 >>> index 86da8c14ff..0000000000 >>> --- a/src/lib/ecore/efl_core_env.eo >>> +++ /dev/null >>> @@ -1,57 +0,0 @@ >>> -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<string>; >>> - } >>> - } >>> - } >>> - 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 deleted file mode 100644 >>> index 846b69a350..0000000000 >>> --- a/src/lib/ecore/efl_core_proc_env.c >>> +++ /dev/null >>> @@ -1,145 +0,0 @@ >>> -#ifdef HAVE_CONFIG_H >>> -# include <config.h> >>> -#endif >>> - >>> -#include <Ecore.h> >>> -#ifdef HAVE_CRT_EXTERNS_H >>> -# include <crt_externs.h> >>> -#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 deleted file mode 100644 >>> index 23c2c67d75..0000000000 >>> --- a/src/lib/ecore/efl_core_proc_env.eo >>> +++ /dev/null >>> @@ -1,21 +0,0 @@ >>> -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/efl_exe.c b/src/lib/ecore/efl_exe.c >>> index 4b3bc658d6..a6f9f5f506 100644 >>> --- a/src/lib/ecore/efl_exe.c >>> +++ b/src/lib/ecore/efl_exe.c >>> @@ -40,7 +40,6 @@ typedef struct _Efl_Exe_Data Efl_Exe_Data; >>> >>> struct _Efl_Exe_Data >>> { >>> - Efl_Core_Env *env; >>> int exit_signal; >>> Efl_Exe_Flags flags; >>> #ifdef _WIN32 >>> @@ -166,6 +165,22 @@ _exec(const char *cmd, Efl_Exe_Flags flags) >>> } >>> } >>> >>> +static Eina_Bool >>> +_foreach_env(const Eina_Hash *hash EINA_UNUSED, const void *key, void >>> *data, void *fdata EINA_UNUSED) +{ >>> + int keylen; >>> + char *buf, *s; >>> + >>> + if (!data) return EINA_TRUE; >>> + keylen = strlen(key); >>> + buf = alloca(keylen + 1 + strlen(data) + 1); >>> + strcpy(buf, key); >>> + buf[keylen] = '='; >>> + strcpy(buf + keylen + 1, data); >>> + if ((s = strdup(buf))) putenv(s); >>> + return EINA_TRUE; >>> +} >>> + >>> static void >>> _exe_exit_eval(Eo *obj, Efl_Exe_Data *pd) >>> { >>> @@ -191,7 +206,7 @@ _exe_exit_eval(Eo *obj, Efl_Exe_Data *pd) >>> // 128+n Fatal error signal "n" kill -9 >>> $PPID $? returns 137 (128 + 9) // 130 Script terminated by >>> Control-C Ctl-C Control-C is fatal error signal 2, (130 = 128 >>> + 2, see above) // 255* Exit status out of range exit -1 >>> exit takes only integer args in the range 0 - 255 >>> - // >>> + // >>> // According to the above table, exit codes 1 - 2, >>> // 126 - 165, and 255 [1] have special meanings, and >>> // should therefore be avoided for user-specified exit >>> @@ -285,25 +300,6 @@ _run_clean_cb(Efl_Loop_Consumer *consumer EINA_UNUSED, >>> >>> ////////////////////////////////////////////////////////////////////////// >>> >>> - >>> -EOLIAN static void >>> -_efl_exe_env_set(Eo *obj EINA_UNUSED, Efl_Exe_Data *pd, Efl_Core_Env *env) >>> -{ >>> - if (pd->env == env) return; >>> - >>> - if (!pd->env) >>> - efl_unref(pd->env); >>> - pd->env = env; >>> - if (pd->env) >>> - efl_ref(pd->env); >>> -} >>> - >>> -EOLIAN static Efl_Core_Env* >>> -_efl_exe_env_get(const Eo *obj EINA_UNUSED, Efl_Exe_Data *pd) >>> -{ >>> - return pd->env; >>> -} >>> - >>> EOLIAN static void >>> _efl_exe_signal(Eo *obj EINA_UNUSED, Efl_Exe_Data *pd, Efl_Exe_Signal sig) >>> { >>> @@ -568,28 +564,17 @@ _efl_exe_efl_task_run(Eo *obj EINA_UNUSED, >>> Efl_Exe_Data *pd) // clear systemd notify socket... only relevant for >>> systemd world, // otherwise shouldn't be trouble >>> putenv("NOTIFY_SOCKET="); >>> + // force the env hash to update from env vars >>> + efl_task_env_get(loop, "HOME"); >>> >>> - // actually setenv the env object (clear what was there before so it is >>> + // actually setenv the env hash (clear what was there before so it is >>> // the only env there) >>> - if (pd->env) >>> - { >>> - Eina_Iterator *itr; >>> - const char *key; >>> - >>> - #ifdef HAVE_CLEARENV >>> - clearenv(); >>> - #else >>> - environ = NULL; >>> - #endif >>> - itr = efl_core_env_content_get(pd->env); >>> - >>> - EINA_ITERATOR_FOREACH(itr, key) >>> - { >>> - setenv(key, efl_core_env_get(pd->env, key) , 1); >>> - } >>> - efl_unref(pd->env); >>> - pd->env = NULL; >>> - } >>> +#ifdef HAVE_CLEARENV >>> + clearenv(); >>> +#else >>> + environ = NULL; >>> +#endif >>> + eina_hash_foreach(td->env, _foreach_env, NULL); >>> >>> // actually execute! >>> _exec(cmd, pd->flags); >>> diff --git a/src/lib/ecore/efl_exe.eo b/src/lib/ecore/efl_exe.eo >>> index 111814af21..d0d0cb585e 100644 >>> --- a/src/lib/ecore/efl_exe.eo >>> +++ b/src/lib/ecore/efl_exe.eo >>> @@ -42,23 +42,6 @@ class Efl.Exe extends Efl.Task implements Efl.Io.Reader, >>> Efl.Io.Writer, Efl.Io.C sig: int; [[ The exit signal, or -1 if no exit >>> signal happened ]] } >>> } >>> - @property env { >>> - [[ If $env is $null then the process created by this object is >>> - going to inherit the enviroment of this process. >>> - >>> - In case $env is not $null then the environment variables >>> declared >>> - in this object will represent the environment passed to the >>> new process. >>> - ]] >>> - get { >>> - [[ Get the object assosiated with this object ]] >>> - } >>> - set { >>> - [[ Set the object assosiated with this object ]] >>> - } >>> - values { >>> - env : Efl.Core.Env; [[$env will be referenced until this >>> object does not need it anymore.]] >>> - } >>> - } >>> } >>> implements { >>> Efl.Object.constructor; >>> diff --git a/src/lib/ecore/efl_loop.c b/src/lib/ecore/efl_loop.c >>> index 68f9573b76..44e9c872c9 100644 >>> --- a/src/lib/ecore/efl_loop.c >>> +++ b/src/lib/ecore/efl_loop.c >>> @@ -15,6 +15,8 @@ >>> >>> #include "ecore_main_common.h" >>> >>> +extern char **environ; >>> + >>> typedef struct _Efl_Loop_Promise_Simple_Data Efl_Loop_Promise_Simple_Data; >>> typedef struct _Efl_Internal_Promise Efl_Internal_Promise; >>> >>> @@ -51,6 +53,11 @@ _efl_loop_message_handler_get(Eo *obj EINA_UNUSED, void >>> *pd EINA_UNUSED, Efl_Loo Eo *_mainloop_singleton = NULL; >>> Efl_Loop_Data *_mainloop_singleton_data = NULL; >>> >>> +extern Eina_Lock _environ_lock; >>> +static Eina_List *_environ_strings_set = NULL; >>> + >>> +static void _clean_old_environ(void); >>> + >>> EAPI Eo * >>> efl_main_loop_get(void) >>> { >>> @@ -347,6 +354,16 @@ _efl_loop_efl_object_destructor(Eo *obj, Efl_Loop_Data >>> *pd) { >>> pd->future_message_handler = NULL; >>> >>> + eina_lock_take(&_environ_lock); >>> + _clean_old_environ(); >>> + _environ_strings_set = eina_list_free(_environ_strings_set); >>> + pd->env.environ_ptr = NULL; >>> + free(pd->env.environ_copy); >>> + pd->env.environ_copy = NULL; >>> + eina_lock_release(&_environ_lock); >>> + >>> + eina_value_flush(&pd->exit_code); >>> + >>> efl_destructor(efl_super(obj, EFL_LOOP_CLASS)); >>> } >>> >>> @@ -657,6 +674,178 @@ efl_build_version_set(int vmaj, int vmin, int vmic, >>> int revision, _app_efl_version.build_id = build_id ? strdup(build_id) : >>> NULL; } >>> >>> +static void >>> +_env_sync(Efl_Loop_Data *pd, Efl_Task_Data *td) >>> +{ >>> + Eina_Bool update = EINA_FALSE; >>> + unsigned int count = 0, i; >>> + char **p; >>> + >>> + // count environs >>> + if (environ) >>> + { >>> + for (p = environ; *p; p++) count++; >>> + } >>> + // cached env ptr is the same... so look deeper if things changes >>> + if (pd->env.environ_ptr == environ) >>> + { >>> + // if we have no cached copy then update >>> + if (!pd->env.environ_copy) update = EINA_TRUE; >>> + else >>> + { >>> + // if any ptr in the cached copy doesnt match environ ptr >>> + // then update >>> + for (i = 0; i <= count; i++) >>> + { >>> + if (pd->env.environ_copy[i] != environ[i]) >>> + { >>> + update = EINA_TRUE; >>> + break; >>> + } >>> + } >>> + } >>> + } >>> + // cached env ptr changed so we need to update anyway >>> + else update = EINA_TRUE; >>> + if (!update) return; >>> + // things changed - do the update >>> + pd->env.environ_ptr = environ; >>> + free(pd->env.environ_copy); >>> + pd->env.environ_copy = NULL; >>> + if (count > 0) >>> + { >>> + pd->env.environ_copy = malloc((count + 1) * sizeof(char *)); >>> + if (pd->env.environ_copy) >>> + { >>> + for (i = 0; i <= count; i++) >>> + pd->env.environ_copy[i] = environ[i]; >>> + } >>> + } >>> + // clear previous env hash and rebuild it from environ so it matches >>> + if (td->env) eina_hash_free(td->env); >>> + td->env = eina_hash_string_superfast_new >>> + ((Eina_Free_Cb)eina_stringshare_del); >>> + for (i = 0; i < count; i++) >>> + { >>> + char *var; >>> + const char *value; >>> + >>> + if (!environ[i]) continue; >>> + if ((value = strchr(environ[i], '='))) >>> + { >>> + if (*value) >>> + { >>> + if ((var = malloc(value - environ[i] + 1))) >>> + { >>> + strncpy(var, environ[i], value - environ[i]); >>> + var[value - environ[i]] = 0; >>> + value++; >>> + eina_hash_add(td->env, var, >>> + eina_stringshare_add(value)); >>> + free(var); >>> + } >>> + } >>> + } >>> + } >>> +} >>> + >>> +static void >>> +_clean_old_environ(void) >>> +{ >>> + char **p; >>> + const char *str; >>> + Eina_List *l, *ll; >>> + Eina_Bool ok; >>> + >>> + // clean up old strings no longer in environ >>> + EINA_LIST_FOREACH_SAFE(_environ_strings_set, l, ll, str) >>> + { >>> + ok = EINA_FALSE; >>> + for (p = environ; *p; p++) >>> + { >>> + if (*p == str) >>> + { >>> + ok = EINA_TRUE; >>> + break; >>> + } >>> + } >>> + if (!ok) >>> + { >>> + _environ_strings_set = >>> + eina_list_remove_list(_environ_strings_set, l); >>> + eina_stringshare_del(str); >>> + } >>> + } >>> +} >>> + >>> +EOLIAN static void >>> +_efl_loop_efl_task_env_set(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED, const >>> char *var, const char *value) +{ >>> + char *str, *str2; >>> + size_t varlen, vallen = 0; >>> + >>> + if (!var) return; >>> + >>> + Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS); >>> + if (!td) return; >>> + >>> + varlen = strlen(var); >>> + if (value) vallen = strlen(value); >>> + >>> + str = malloc(varlen + 1 + vallen + 1); >>> + if (!str) return; >>> + strcpy(str, var); >>> + str[varlen] = '='; >>> + if (value) strcpy(str + varlen + 1, value); >>> + else str[varlen + 1] = 0; >>> + >>> + str2 = (char *)eina_stringshare_add(str); >>> + free(str); >>> + if (!str2) return; >>> + >>> + eina_lock_take(&_environ_lock); >>> + if (putenv(str2) != 0) >>> + { >>> + eina_stringshare_del(str2); >>> + eina_lock_release(&_environ_lock); >>> + return; >>> + } >>> + _environ_strings_set = eina_list_append(_environ_strings_set, str2); >>> + eina_lock_release(&_environ_lock); >>> + >>> + efl_task_env_set(efl_super(obj, EFL_LOOP_CLASS), var, value); >>> + >>> + eina_lock_take(&_environ_lock); >>> + _clean_old_environ(); >>> + eina_lock_release(&_environ_lock); >>> +} >>> + >>> +EOLIAN static const char * >>> +_efl_loop_efl_task_env_get(const Eo *obj, Efl_Loop_Data *pd, const char >>> *var) +{ >>> + Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS); >>> + if (!td) return NULL; >>> + eina_lock_take(&_environ_lock); >>> + _env_sync(pd, td); >>> + eina_lock_release(&_environ_lock); >>> + return efl_task_env_get(efl_super(obj, EFL_LOOP_CLASS), var); >>> +} >>> + >>> +EOLIAN static void >>> +_efl_loop_efl_task_env_reset(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd) >>> +{ >>> + Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS); >>> + if (!td) return; >>> + eina_lock_take(&_environ_lock); >>> +#ifdef HAVE_CLEARENV >>> + clearenv(); >>> +#else >>> + environ = NULL; >>> +#endif >>> + _env_sync(pd, td); >>> + eina_lock_release(&_environ_lock); >>> +} >>> + >>> EOLIAN static Eina_Future * >>> _efl_loop_efl_task_run(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED) >>> { >>> diff --git a/src/lib/ecore/efl_loop.eo b/src/lib/ecore/efl_loop.eo >>> index 7480eee867..fe9cbd9a5d 100644 >>> --- a/src/lib/ecore/efl_loop.eo >>> +++ b/src/lib/ecore/efl_loop.eo >>> @@ -125,6 +125,8 @@ class Efl.Loop extends Efl.Task >>> Efl.Object.invalidate; >>> Efl.Object.destructor; >>> Efl.Object.provider_find; >>> + Efl.Task.env { set; get; } >>> + Efl.Task.env_reset; >>> Efl.Task.run; >>> Efl.Task.end; >>> } >>> diff --git a/src/lib/ecore/efl_task.c b/src/lib/ecore/efl_task.c >>> index 311de0506a..6442669efd 100644 >>> --- a/src/lib/ecore/efl_task.c >>> +++ b/src/lib/ecore/efl_task.c >>> @@ -227,6 +227,19 @@ _rebuild_command(Efl_Task_Data *pd) >>> eina_strbuf_free(sb); >>> } >>> >>> + >>> +static Eina_Bool >>> +_foreach_env_copy(const Eina_Hash *hash EINA_UNUSED, const void *key, void >>> *data, void *fdata) +{ >>> + if (data) >>> + { >>> + // only copy env vars not already set >>> + if (!eina_hash_find(fdata, key)) >>> + eina_hash_add(fdata, key, eina_stringshare_add(data)); >>> + } >>> + return EINA_TRUE; >>> +} >>> + >>> ////////////////////////////////////////////////////////////////////////// >>> >>> EOLIAN static void >>> @@ -309,6 +322,34 @@ _efl_task_arg_reset(Eo *obj EINA_UNUSED, Efl_Task_Data >>> *pd) pd->command_dirty = EINA_TRUE; >>> } >>> >>> +EOLIAN static void >>> +_efl_task_env_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, const char *var, >>> const char *value) +{ >>> + if (!var) return; >>> + if (!pd->env) >>> + pd->env = eina_hash_string_superfast_new >>> + ((Eina_Free_Cb)eina_stringshare_del); >>> + if (!pd->env) return; >>> + if ((value) && (*value)) >>> + eina_hash_add(pd->env, var, eina_stringshare_add(value)); >>> + else eina_hash_del(pd->env, var, NULL); >>> +} >>> + >>> + >>> +EOLIAN static const char * >>> +_efl_task_env_get(const Eo *obj EINA_UNUSED, Efl_Task_Data *pd, const char >>> *var) +{ >>> + if ((!var) || (!pd->env)) return NULL; >>> + return eina_hash_find(pd->env, var); >>> +} >>> + >>> +EOLIAN static void >>> +_efl_task_env_reset(Eo *obj EINA_UNUSED, Efl_Task_Data *pd) >>> +{ >>> + if (pd->env) eina_hash_free(pd->env); >>> + pd->env = NULL; >>> +} >>> + >>> EOLIAN static void >>> _efl_task_priority_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, >>> Efl_Task_Priority priority) { >>> @@ -345,13 +386,32 @@ _efl_task_efl_object_destructor(Eo *obj EINA_UNUSED, >>> Efl_Task_Data *pd) eina_stringshare_del(pd->command); >>> pd->command = NULL; >>> _clear_args(pd); >>> + if (pd->env) eina_hash_free(pd->env); >>> + pd->env = NULL; >>> efl_destructor(efl_super(obj, MY_CLASS)); >>> } >>> >>> EOLIAN static void >>> -_efl_task_efl_object_parent_set(Eo *obj, Efl_Task_Data *pd EINA_UNUSED, >>> Efl_Object *parent) +_efl_task_efl_object_parent_set(Eo *obj, Efl_Task_Data >>> *pd, Efl_Object *parent) { >>> + Eo *loop; >>> + >>> efl_parent_set(efl_super(obj, MY_CLASS), parent); >>> + // copy loop env into exe task env, if not already set in env >>> (overridden) >>> + loop = efl_provider_find(parent, EFL_LOOP_CLASS); >>> + if (loop) >>> + { >>> + Efl_Task_Data *tdl = efl_data_scope_get(loop, EFL_TASK_CLASS); >>> + >>> + if (tdl) >>> + { >>> + if (!pd->env) >>> + pd->env = eina_hash_string_superfast_new >>> + ((Eina_Free_Cb)eina_stringshare_del); >>> + if (tdl->env) >>> + eina_hash_foreach(tdl->env, _foreach_env_copy, pd->env); >>> + } >>> + } >>> } >>> >>> ////////////////////////////////////////////////////////////////////////// >>> diff --git a/src/lib/ecore/efl_task.eo b/src/lib/ecore/efl_task.eo >>> index 526746ff60..92f0094fef 100644 >>> --- a/src/lib/ecore/efl_task.eo >>> +++ b/src/lib/ecore/efl_task.eo >>> @@ -96,6 +96,26 @@ abstract Efl.Task extends Efl.Object >>> [[ Clear all arguments in arg_value/count set. Will result in the >>> command property also being cleared. ]] >>> } >>> + @property env { >>> + [[ The environment to be passed in or that was passed to the >>> + task. This is a string key, value list which map to environment >>> + variables where appropriate. The var string must contain >>> + only an underscore ('_'), letters ('a-z', 'A-Z'), >>> + numbers ('0-9'), but the first character may not be a number.]] >>> + set { } >>> + get { } >>> + keys { >>> + var: string; [[ The variable name as a string ]] >>> + } >>> + 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 ]] >>> + } >>> + } >>> + env_reset { >>> + [[ Clear all environment variables. ]] >>> + } >>> @property priority { >>> [[ The priority of this task. ]] >>> get { } >>> diff --git a/src/lib/ecore/meson.build b/src/lib/ecore/meson.build >>> index 98909cb618..baa5263698 100644 >>> --- a/src/lib/ecore/meson.build >>> +++ b/src/lib/ecore/meson.build >>> @@ -74,9 +74,7 @@ pub_eo_files = [ >>> 'efl_boolean_model.eo', >>> 'efl_select_model.eo', >>> 'efl_composite_model.eo', >>> - 'efl_view_model.eo', >>> - 'efl_core_env.eo', >>> - 'efl_core_proc_env.eo' >>> + 'efl_view_model.eo' >>> ] >>> >>> foreach eo_file : pub_eo_files >>> @@ -182,8 +180,6 @@ 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 cd26e2d95e..b3be09915a 100644 >>> --- a/src/tests/ecore/efl_app_suite.c >>> +++ b/src/tests/ecore/efl_app_suite.c >>> @@ -9,6 +9,7 @@ >>> #include "efl_app_suite.h" >>> #include "../efl_check.h" >>> >>> + >>> EFL_START_TEST(efl_app_test_efl_build_version) >>> { >>> const Efl_Version *ver; >>> @@ -52,7 +53,6 @@ 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 3a66dcdfcf..29ed8f031f 100644 >>> --- a/src/tests/ecore/efl_app_suite.h >>> +++ b/src/tests/ecore/efl_app_suite.h >>> @@ -11,6 +11,5 @@ 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 deleted file mode 100644 >>> index 63bad166a2..0000000000 >>> --- a/src/tests/ecore/efl_app_test_env.c >>> +++ /dev/null >>> @@ -1,135 +0,0 @@ >>> -#ifdef HAVE_CONFIG_H >>> -# include <config.h> >>> -#endif >>> - >>> -#include <stdio.h> >>> -#include <unistd.h> >>> -#define EFL_NOLEGACY_API_SUPPORT >>> -#include <Efl_Core.h> >>> -#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 e3b4f6c851..4b46814bbe 100644 >>> --- a/src/tests/ecore/meson.build >>> +++ b/src/tests/ecore/meson.build >>> @@ -75,8 +75,7 @@ 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_env.c' >>> + 'efl_app_test_promise.c' >>> ] >>> >>> efl_app_suite_deps = [m] >>> > >
pEpkey.asc
Description: application/pgp-keys
_______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel