Here is the try to get a technical discussion:

Problems you have pointed out:
1. Portability
2. Ownership
3. Pseudocode example
4. strdup into a const char*

1.:
   Free/Openbsd meanwhile has setenv,
(https://www.freebsd.org/cgi/man.cgi?query=setenv&sektion=3&manpath=freebsd-release-ports)
   Windows has setenv etc. due to evil, and vincent pointed his "issues"
out in https://phab.enlightenment.org/T7693, where i still fail to see a
reason why this fails.

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 :)

3.:
   For the next time i would love to see a testcase, if you would have
gone the path of a testcase, then you would have seen that this actaully
works ... :)

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.

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]
> 

Attachment: pEpkey.asc
Description: application/pgp-keys

_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to