Revert "Revert command line array object because it's broken by design"
authorMarcel Hollerbach <mail@marcel-hollerbach.de>
Tue, 12 Feb 2019 20:34:30 +0000 (21:34 +0100)
committerWonki Kim <wonki_.kim@samsung.com>
Fri, 8 Mar 2019 11:49:33 +0000 (20:49 +0900)
This reverts commit a57c7f751023fe1d1edeabbf8683574ac7497e5e.

I pretty much hate to just revert your revert, but you failed to read my
replies, and failed to understand what i was talking about.

And YES we talked at fosdem about the platform issue, and do you
remember my answer, that back in time this might be the case, today is
different freebsd suppoerts setenv, and for windows we have a setenv
implementation in evil. And yes, vtorri also created a issue how bad and
evil this commit is, however, i still fail to see the issue since setenv
unsetenv and clearenv usages are taken as needed. (T7693)

The ownership question is answered in
https://phab.enlightenment.org/D7516#137367.

Can we please get into a state of technical discussions, and not *oh
shit, i am going to revert this* this has been in review for a long
time, a lots of people have tested it, we discussed things on it, and
there was 3 weeks of no reply from you.

The issues that exist will be dealed with. Feel free to create tasks if
you want :)

20 files changed:
src/Makefile_Ecore.am
src/bindings/mono/efl_mono/efl_csharp_application.cs
src/lib/ecore/Ecore_Eo.h
src/lib/ecore/efl_app.eo
src/lib/ecore/efl_appthread.eo
src/lib/ecore/efl_core_command_line.c [new file with mode: 0644]
src/lib/ecore/efl_core_command_line.eo [new file with mode: 0644]
src/lib/ecore/efl_exe.c
src/lib/ecore/efl_exe.eo
src/lib/ecore/efl_loop.c
src/lib/ecore/efl_task.c
src/lib/ecore/efl_task.eo
src/lib/ecore/efl_thread.c
src/lib/ecore/efl_thread.eo
src/lib/ecore/meson.build
src/tests/ecore/efl_app_suite.c
src/tests/ecore/efl_app_suite.h
src/tests/ecore/efl_app_test_cml.c [new file with mode: 0644]
src/tests/ecore/efl_app_test_cml.eo [new file with mode: 0644]
src/tests/ecore/meson.build

index a16e1cf55bd829780ec134c7000213d143031faf..b8b185e5005904e08bd9cb9a851470692bfb91ed 100644 (file)
@@ -52,6 +52,10 @@ ecore_eolian_files_public = \
        lib/ecore/efl_view_model.eo \
        lib/ecore/efl_core_env.eo \
        lib/ecore/efl_core_proc_env.eo \
+       lib/ecore/efl_core_command_line.eo
+
+ecore_test_eolian_files = \
+       tests/ecore/efl_app_test_cml.eo
 
 ecore_eolian_files = \
        $(ecore_eolian_files_legacy) \
@@ -60,10 +64,14 @@ ecore_eolian_files = \
 ecore_eolian_c = $(ecore_eolian_files:%.eo=%.eo.c)
 ecore_eolian_h = $(ecore_eolian_files:%.eo=%.eo.h) \
                  $(ecore_eolian_files_legacy:%.eo=%.eo.legacy.h)
+ecore_test_c = $(ecore_test_eolian_files:%.eo=%.eo.c)
+ecore_test_h = $(ecore_test_eolian_files:%.eo=%.eo.h)
 
 BUILT_SOURCES += \
                  $(ecore_eolian_c) \
-                 $(ecore_eolian_h)
+                 $(ecore_eolian_h) \
+                 $(ecore_test_c) \
+                 $(ecore_test_h)
 
 ecoreeolianfilesdir = $(datadir)/eolian/include/ecore-@VMAJ@
 ecoreeolianfiles_DATA = $(ecore_eolian_files_public) lib/ecore/efl_loop_timer.eo
@@ -100,6 +108,7 @@ 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_command_line.c \
 lib/ecore/efl_core_env.c \
 lib/ecore/efl_core_proc_env.c \
 lib/ecore/efl_app.c \
@@ -340,6 +349,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_cml.c \
 tests/ecore/efl_app_test_env.c \
 tests/ecore/efl_app_suite.c \
 tests/ecore/efl_app_suite.h
index 2b2c55c75eb0b721e9d3a1752838b6b20be7228e..84732d399399a8dc58c113604aff0563ab39e294 100644 (file)
@@ -104,8 +104,9 @@ namespace Efl {
       public void Launch(Efl.Csharp.Components components=Components.Ui) {
         Init(components);
         Efl.App app = Efl.App.AppMain;
-        foreach (var arg in Environment.GetCommandLineArgs())
-          app.AppendArg(arg);
+        Eina.Array<String> command_line = new Eina.Array<String>();
+        command_line.Append(Environment.GetCommandLineArgs());
+        app.SetCommandArray(command_line);
         app.ArgumentsEvt += (object sender, LoopArgumentsEvt_Args evt) => {
           if (evt.arg.Initialization) {
             OnInitialize(evt.arg.Argv);
index 3898b518c7ee14619f1ccde9f5312a9cb0a200d3..89c826a266c92a9c058b103e7bf8e7b658a3035d 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 
 #include "efl_core_env.eo.h"
 #include "efl_core_proc_env.eo.h"
+#include "efl_core_command_line.eo.h"
 
 #include "efl_loop_message.eo.h"
 #include "efl_loop_message_handler.eo.h"
index f90324b39deb5c4d92dc3e5fdd93a4da7c517f79..e046428626f2f348fba733d097861a7b91dbe5e6 100644 (file)
@@ -1,6 +1,6 @@
 import efl_types;
 
-class Efl.App extends Efl.Loop
+class Efl.App extends Efl.Loop implements Efl.Core.Command_Line
 {
    [[ ]]
    data: null;
index c60308f468f3887e6687d68824b9719e11c32b24..82a9d77ace83f3e9030fad87e8438227bdc2c4cc 100644 (file)
@@ -1,4 +1,4 @@
-class Efl.Appthread extends Efl.Loop implements Efl.ThreadIO, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer
+class Efl.Appthread extends Efl.Loop implements Efl.ThreadIO, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer, Efl.Core.Command_Line
 {
    [[ ]]
    methods {
diff --git a/src/lib/ecore/efl_core_command_line.c b/src/lib/ecore/efl_core_command_line.c
new file mode 100644 (file)
index 0000000..74ae690
--- /dev/null
@@ -0,0 +1,267 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define EFL_CORE_COMMAND_LINE_PROTECTED
+
+#include <Efl_Core.h>
+
+#define MY_CLASS EFL_CORE_COMMAND_LINE_MIXIN
+
+typedef struct {
+   Eina_Bool filled;
+   char *string_command;
+   Eina_Array *command;
+} Efl_Core_Command_Line_Data;
+
+static Eina_Array *
+_unescape(const char *s)
+{
+   Eina_Array *args;
+   const char *p;
+   char *tmp = NULL, *d = NULL;
+   if (!s) return NULL;
+
+   Eina_Bool in_quote_dbl = EINA_FALSE;
+   Eina_Bool in_quote = EINA_FALSE;
+
+   args = eina_array_new(16);
+   if (!args) return NULL;
+   for (p = s; *p; p++)
+     {
+        if (!tmp) tmp = d = strdup(p);
+        if (tmp)
+          {
+             if (in_quote_dbl)
+               {
+                  switch (*p)
+                    {
+                     case '\"':
+                       in_quote_dbl = EINA_FALSE;
+                       *d = 0;
+                       eina_array_push(args, eina_stringshare_add(tmp));
+                       free(tmp);
+                       tmp = d = NULL;
+                       break;
+                     case '\\':
+                       p++;
+                       EINA_FALLTHROUGH
+                     default:
+                       *d = *p;
+                       d++;
+                       break;
+                    }
+               }
+             else if (in_quote)
+               {
+                  switch (*p)
+                    {
+                     case '\'':
+                       in_quote = EINA_FALSE;
+                       *d = 0;
+                       eina_array_push(args, eina_stringshare_add(tmp));
+                       free(tmp);
+                       tmp = d = NULL;
+                       break;
+                     case '\\':
+                       p++;
+                       EINA_FALLTHROUGH
+                     default:
+                       *d = *p;
+                       d++;
+                       break;
+                    }
+               }
+             else
+               {
+                  switch (*p)
+                    {
+                     case ' ':
+                     case '\t':
+                     case '\r':
+                     case '\n':
+                       *d = 0;
+                       eina_array_push(args, eina_stringshare_add(tmp));
+                       free(tmp);
+                       tmp = d = NULL;
+                       break;
+                     case '\"':
+                       in_quote_dbl = EINA_TRUE;
+                       break;
+                     case '\'':
+                       in_quote = EINA_TRUE;
+                       break;
+                     case '\\':
+                       p++;
+                       EINA_FALLTHROUGH
+                     default:
+                       *d = *p;
+                       d++;
+                       break;
+                    }
+               }
+          }
+     }
+   if (tmp)
+     {
+        *d = 0;
+        eina_array_push(args, eina_stringshare_add(tmp));
+        free(tmp);
+     }
+   return args;
+}
+
+static char *
+_escape(const char *s)
+{
+   Eina_Bool need_quote = EINA_FALSE;
+   const char *p;
+   char *s2 = malloc((strlen(s) * 2) + 1 + 2), *d;
+
+   if (!s2) return NULL;
+
+   for (p = s; *p; p++)
+     {
+        switch (*p)
+          {
+           case '\'':
+           case '\"':
+           case '$':
+           case '#':
+           case ';':
+           case '&':
+           case '`':
+           case '|':
+           case '(':
+           case ')':
+           case '[':
+           case ']':
+           case '{':
+           case '}':
+           case '>':
+           case '<':
+           case '\n':
+           case '\r':
+           case '\t':
+           case ' ':
+             need_quote = EINA_TRUE;
+           default:
+             break;
+          }
+     }
+
+   d = s2;
+   if (need_quote)
+     {
+        *d = '\"';
+        d++;
+     }
+   for (p = s; *p; p++, d++)
+     {
+        switch (*p)
+          {
+           case '\\':
+           case '\'':
+           case '\"':
+             *d = '\\';
+             d++;
+             EINA_FALLTHROUGH
+           default:
+             *d = *p;
+             break;
+          }
+     }
+   if (need_quote)
+     {
+        *d = '\"';
+        d++;
+     }
+   *d = 0;
+   return s2;
+}
+
+EOLIAN static const char*
+_efl_core_command_line_command_get(const Eo *obj EINA_UNUSED, Efl_Core_Command_Line_Data *pd)
+{
+   return eina_strdup(pd->string_command);
+}
+
+EOLIAN static Eina_Accessor*
+_efl_core_command_line_command_access(Eo *obj EINA_UNUSED, Efl_Core_Command_Line_Data *pd)
+{
+   return pd->command ? eina_array_accessor_new(pd->command) : NULL;
+}
+
+static void
+_remove_invalid_chars(char *command)
+{
+   for (unsigned int i = 0; i < strlen(command); ++i)
+     {
+        char c = command[i];
+        if (c < 0x20 || c == 0x7f)
+          command[i] = '\x12';
+     }
+}
+
+EOLIAN static Eina_Bool
+_efl_core_command_line_command_array_set(Eo *obj EINA_UNUSED, Efl_Core_Command_Line_Data *pd, Eina_Array *array)
+{
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->filled, EINA_FALSE);
+   Eina_Strbuf *command = eina_strbuf_new();
+   unsigned int i = 0;
+
+   pd->command = eina_array_new(eina_array_count(array));
+   for (i = 0; i < (array ? eina_array_count(array) : 0); ++i)
+     {
+        char *content = eina_array_data_get(array, i);
+        char *param = calloc(1, strlen(content));
+
+        if (!param)
+          {
+             free(param);
+             while (eina_array_count(pd->command) > 0)
+              eina_stringshare_del(eina_array_pop(pd->command));
+             eina_array_free(pd->command);
+             pd->command = NULL;
+             eina_array_free(array);
+             return EINA_FALSE;
+          }
+
+        //build the command
+        if (i != 0)
+          eina_strbuf_append(command, " ");
+        eina_strbuf_append(command, _escape(content));
+        //convert string to stringshare
+        strcpy(param, content);
+        _remove_invalid_chars(param);
+        eina_array_push(pd->command, eina_stringshare_add(param));
+        free(param);
+     }
+   pd->string_command = eina_strbuf_release(command);
+   pd->filled = EINA_TRUE;
+   eina_array_free(array);
+
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_efl_core_command_line_command_string_set(Eo *obj EINA_UNUSED, Efl_Core_Command_Line_Data *pd, const char *str)
+{
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->filled, EINA_FALSE);
+
+   pd->string_command = eina_strdup(str);
+   _remove_invalid_chars(pd->string_command);
+   pd->command = _unescape(str);
+   if (!pd->command)
+     {
+        if (pd->string_command)
+          free(pd->string_command);
+        pd->string_command = NULL;
+        return EINA_FALSE;
+     }
+   pd->filled = EINA_TRUE;
+
+   return EINA_TRUE;
+}
+
+#include "efl_core_command_line.eo.c"
diff --git a/src/lib/ecore/efl_core_command_line.eo b/src/lib/ecore/efl_core_command_line.eo
new file mode 100644 (file)
index 0000000..1cbb020
--- /dev/null
@@ -0,0 +1,80 @@
+mixin Efl.Core.Command_Line {
+  [[A mixin that implements standard functions for command lines.
+
+    This object parses the command line that gets passed, later the object can be accessed via accessor or the string directly.
+  ]]
+  methods {
+    @property command {
+        [[ A commandline that encodes arguments in a command string.
+          This command is unix shell-style, thus whitespace separates
+          arguments unless escaped. Also a semi-colon ';', ampersand
+          '&', pipe/bar '|', hash '#', bracket, square brace, brace
+          character ('(', ')', '[', ']', '{', '}'), exclamation
+          mark '!',  backquote '`', greator or less than ('>' '<')
+          character unless escaped or in quotes would cause
+          args_count/value to not be generated properly, because
+          it would force complex shell interpretation which
+          will not be supported in evaluating the arg_count/value
+          information, but the final shell may interpret this if this
+          is executed via a command-line shell. To not be a complex
+          shell command, it should be simple with paths, options
+          and variable expansions, but nothing more complex involving
+          the above unescaped characters.
+
+          "cat -option /path/file"
+          "cat 'quoted argument'"
+          "cat ~/path/escaped\ argument"
+          "/bin/cat escaped\ argument $VARIABLE"
+          etc.
+
+          It should not try and use "complex shell features" if you
+          want the arg_count and arg_value set to be correct after
+          setting the command string. For example none of:
+
+          "VAR=x /bin/command && /bin/othercommand >& /dev/null"
+          "VAR=x /bin/command `/bin/othercommand` | /bin/cmd2 && cmd3 &"
+          etc.
+
+          If you set the command the arg_count/value property contents
+          can change and be completely re-evaluated by parsing the
+          command string into an argument array set along with
+          interpreting escapes back into individual argument strings.
+        ]]
+      get {
+
+      }
+      values {
+        commandline : string;
+      }
+    }
+    command_access {
+      [[ Get the accessor which enables access to each argument that got passed to this object. ]]
+      return : accessor<stringshare>;
+    }
+    @property command_array {
+      [[ Use an array to fill this object
+
+         Every element of a string is a argument.
+      ]]
+      set {
+        return : bool; [[On success $true, $false otherwise]]
+      }
+      values {
+        array : array<string> @owned; [[An array where every array field is an argument]]
+      }
+    }
+    @property command_string {
+      [[ Use a string to fill this object
+
+         The string will be split at every unescaped ' ', every resulting substring will be a new argument to the command line.
+      ]]
+      set {
+        return : bool; [[On success $true, $false otherwise]]
+      }
+      values {
+        str : string; [[A command in form of a string]]
+      }
+
+    }
+  }
+}
index 4b3bc658d6bd8ca47b9979703d5cbe30d1f08789..61ff4ba7987e165bb59340cbc49ed2f8eece5298 100644 (file)
@@ -395,7 +395,7 @@ _efl_exe_efl_task_priority_get(const Eo *obj EINA_UNUSED, Efl_Exe_Data *pd)
 }
 
 EOLIAN static Eina_Future *
-_efl_exe_efl_task_run(Eo *obj EINA_UNUSED, Efl_Exe_Data *pd)
+_efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
 {
 #ifdef _WIN32
    return EINA_FALSE;
@@ -414,7 +414,7 @@ _efl_exe_efl_task_run(Eo *obj EINA_UNUSED, Efl_Exe_Data *pd)
    if (!td) return NULL;
 
    // get a cmdline to run
-   cmd = efl_task_command_get(obj);
+   cmd = efl_core_command_line_command_get(obj);
    if (!cmd) return NULL;
 
    ret = pipe(pipe_exited);
index 111814af21c7e228830c06a1f46a9122b63cb913..b7f97da7dca16cbad942362a8768a31c718b9fed 100644 (file)
@@ -19,7 +19,7 @@ enum Efl.Exe_Flags {
    hide_io          = 4
 }
 
-class Efl.Exe extends Efl.Task implements Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer
+class Efl.Exe extends Efl.Task implements Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer,Efl.Core.Command_Line
 {
    [[ ]]
    methods {
index 68f9573b76465c699164f012aa1e8fcf534f52a5..cf8600c9985c370258497f942824d6f2405df517 100644 (file)
@@ -383,17 +383,19 @@ _efl_loop_arguments_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_Future *de
 EAPI void
 ecore_loop_arguments_send(int argc, const char **argv)
 {
-   Eina_Array *arga;
+   Eina_Array *arga, *cml;
    int i = 0;
 
-   efl_task_arg_reset(efl_main_loop_get());
    arga = eina_array_new(argc);
+   cml = eina_array_new(argc);
    for (i = 0; i < argc; i++)
      {
-        eina_array_push(arga, eina_stringshare_add(argv[i]));
-        efl_task_arg_append(efl_main_loop_get(), argv[i]);
+        Eina_Stringshare *arg = eina_stringshare_add(argv[i]);
+        eina_array_push(arga, arg);
+        eina_array_push(cml, arg);
      }
 
+   efl_core_command_line_command_array_set(efl_app_main_get(EFL_APP_CLASS), cml);
    efl_future_then(efl_main_loop_get(), efl_loop_job(efl_main_loop_get()),
                    .success = _efl_loop_arguments_send,
                    .free = _efl_loop_arguments_cleanup,
index 311de0506a76900fb6895754db49ceb228c9bdd7..d610fcbf8bd9932afd8aafab9775e1a4334210bc 100644 (file)
 
 //////////////////////////////////////////////////////////////////////////
 
-static void
-_clear_args(Efl_Task_Data *pd)
-{
-   unsigned int count, i;
-
-   if (!pd->args) return;
-   count = eina_array_count(pd->args);
-   for (i = 0; i < count; i++)
-     eina_stringshare_del(eina_array_data_get(pd->args, i));
-   eina_array_free(pd->args);
-   pd->args = NULL;
-}
-
-static Eina_Array *
-_unescape(const char *s)
-{
-   Eina_Array *args;
-   const char *p;
-   char *tmp = NULL, *d = NULL;
-   if (!s) return NULL;
-
-   Eina_Bool in_quote_dbl = EINA_FALSE;
-   Eina_Bool in_quote = EINA_FALSE;
-
-   args = eina_array_new(16);
-   if (!args) return NULL;
-   for (p = s; *p; p++)
-     {
-        if (!tmp) tmp = d = strdup(p);
-        if (tmp)
-          {
-             if (in_quote_dbl)
-               {
-                  switch (*p)
-                    {
-                     case '\"':
-                       in_quote_dbl = EINA_FALSE;
-                       *d = 0;
-                       eina_array_push(args, eina_stringshare_add(tmp));
-                       free(tmp);
-                       tmp = d = NULL;
-                       break;
-                     case '\\':
-                       p++;
-                       EINA_FALLTHROUGH
-                     default:
-                       *d = *p;
-                       d++;
-                       break;
-                    }
-               }
-             else if (in_quote)
-               {
-                  switch (*p)
-                    {
-                     case '\'':
-                       in_quote = EINA_FALSE;
-                       *d = 0;
-                       eina_array_push(args, eina_stringshare_add(tmp));
-                       free(tmp);
-                       tmp = d = NULL;
-                       break;
-                     case '\\':
-                       p++;
-                       EINA_FALLTHROUGH
-                     default:
-                       *d = *p;
-                       d++;
-                       break;
-                    }
-               }
-             else
-               {
-                  switch (*p)
-                    {
-                     case ' ':
-                     case '\t':
-                     case '\r':
-                     case '\n':
-                       *d = 0;
-                       eina_array_push(args, eina_stringshare_add(tmp));
-                       free(tmp);
-                       tmp = d = NULL;
-                       break;
-                     case '\"':
-                       in_quote_dbl = EINA_TRUE;
-                       break;
-                     case '\'':
-                       in_quote = EINA_TRUE;
-                       break;
-                     case '\\':
-                       p++;
-                       EINA_FALLTHROUGH
-                     default:
-                       *d = *p;
-                       d++;
-                       break;
-                    }
-               }
-          }
-     }
-   if (tmp)
-     {
-        *d = 0;
-        eina_array_push(args, eina_stringshare_add(tmp));
-        free(tmp);
-     }
-   return args;
-}
-
-static char *
-_escape(const char *s)
-{
-   Eina_Bool need_quote = EINA_FALSE;
-   const char *p;
-   char *s2 = malloc((strlen(s) * 2) + 1 + 2), *d;
-
-   if (!s2) return NULL;
-
-   for (p = s; *p; p++)
-     {
-        switch (*p)
-          {
-           case '\'':
-           case '\"':
-           case '$':
-           case '#':
-           case ';':
-           case '&':
-           case '`':
-           case '|':
-           case '(':
-           case ')':
-           case '[':
-           case ']':
-           case '{':
-           case '}':
-           case '>':
-           case '<':
-           case '\n':
-           case '\r':
-           case '\t':
-             need_quote = EINA_TRUE;
-           default:
-             break;
-          }
-     }
-
-   d = s2;
-   if (need_quote)
-     {
-        *d = '\"';
-        d++;
-     }
-   for (p = s; *p; p++, d++)
-     {
-        switch (*p)
-          {
-           case ' ':
-           case '\\':
-           case '\'':
-           case '\"':
-             *d = '\\';
-             d++;
-             EINA_FALLTHROUGH
-           default:
-             *d = *p;
-             break;
-          }
-     }
-   if (need_quote)
-     {
-        *d = '\"';
-        d++;
-     }
-   *d = 0;
-   return s2;
-}
-
-static void
-_rebuild_command(Efl_Task_Data *pd)
-{
-   unsigned int count, i;
-   Eina_Strbuf *sb;
-   const char *arg, *cmd;
-   Eina_Bool have_args = EINA_FALSE;
-
-   if (!pd->command_dirty) return;
-   pd->command_dirty = EINA_FALSE;
-   eina_stringshare_del(pd->command);
-   pd->command = NULL;
-   if (!pd->args) return;
-   sb = eina_strbuf_new();
-   if (!sb) return;
-   count = eina_array_count(pd->args);
-   for (i = 0; i < count; i++)
-     {
-        arg = eina_array_data_get(pd->args, i);
-        if (arg)
-          {
-             char *str = _escape(arg);
-             if (str)
-               {
-                  if (have_args) eina_strbuf_append(sb, " ");
-                  eina_strbuf_append(sb, str);
-                  free(str);
-                  have_args = EINA_TRUE;
-               }
-          }
-     }
-   cmd = eina_strbuf_string_get(sb);
-   if (cmd) pd->command = eina_stringshare_add(cmd);
-   eina_strbuf_free(sb);
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-EOLIAN static void
-_efl_task_command_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, const char *command)
-{
-   eina_stringshare_replace(&pd->command, command);
-   _clear_args(pd);
-   pd->args = _unescape(pd->command);
-}
-
-EOLIAN static const char *
-_efl_task_command_get(const Eo *obj EINA_UNUSED, Efl_Task_Data *pd)
-{
-   _rebuild_command(pd);
-   return pd->command;
-}
-
-EOLIAN static unsigned int
-_efl_task_arg_count_get(const Eo *obj EINA_UNUSED, Efl_Task_Data *pd)
-{
-   if (!pd->args) return 0;
-   return eina_array_count(pd->args);
-}
-
-EOLIAN static void
-_efl_task_arg_value_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, unsigned int num, const char *arg)
-{
-   const char *parg = NULL;
-   unsigned int count;
-
-   if (!pd->args) pd->args = eina_array_new(16);
-   count = eina_array_count(pd->args);
-   if ((count > 0) && (count > num))
-     parg = eina_array_data_get(pd->args, num);
-   else
-     {
-        unsigned int i;
-
-        for (i = count; i <= num; i++)
-          {
-             eina_array_push(pd->args, "");
-             eina_array_data_set(pd->args, i, NULL);
-          }
-     }
-
-   if (arg)
-     eina_array_data_set(pd->args, num, eina_stringshare_add(arg));
-   else
-     eina_array_data_set(pd->args, num, NULL);
-   if (parg) eina_stringshare_del(parg);
-   pd->command_dirty = EINA_TRUE;
-}
-
-EOLIAN static const char *
-_efl_task_arg_value_get(const Eo *obj EINA_UNUSED, Efl_Task_Data *pd, unsigned int num)
-{
-   unsigned int count;
-
-   if (!pd->args) return NULL;
-   count = eina_array_count(pd->args);
-   if (num >= count) return NULL;
-   return eina_array_data_get(pd->args, num);
-}
-
-EOLIAN static void
-_efl_task_arg_append(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, const char *arg)
-{
-   if (!pd->args) pd->args = eina_array_new(16);
-   if (arg)
-     eina_array_push(pd->args, eina_stringshare_add(arg));
-   else
-     eina_array_push(pd->args, NULL);
-   pd->command_dirty = EINA_TRUE;
-}
-
-EOLIAN static void
-_efl_task_arg_reset(Eo *obj EINA_UNUSED, Efl_Task_Data *pd)
-{
-   _clear_args(pd);
-   pd->command_dirty = EINA_TRUE;
-}
-
 EOLIAN static void
 _efl_task_priority_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, Efl_Task_Priority priority)
 {
@@ -344,7 +47,6 @@ _efl_task_efl_object_destructor(Eo *obj EINA_UNUSED, Efl_Task_Data *pd)
 {
    eina_stringshare_del(pd->command);
    pd->command = NULL;
-   _clear_args(pd);
    efl_destructor(efl_super(obj, MY_CLASS));
 }
 
index 526746ff604810092bb563f781ff0fbafb8f92a1..ddab5e6826afbe156b7de731f5ba8fb534297da6 100644 (file)
@@ -19,83 +19,6 @@ abstract Efl.Task extends Efl.Object
 {
    [[ ]]
    methods {
-      @property command {
-         [[ A commandline that encodes arguments in a command string.
-            This command is unix shell-style, thus whitespace separates
-            arguments unless escaped. Also a semi-colon ';', ampersand
-            '&', pipe/bar '|', hash '#', bracket, square brace, brace
-            character ('(', ')', '[', ']', '{', '}'), exclamation
-            mark '!',  backquote '`', greator or less than ('>' '<')
-            character unless escaped or in quotes would cause
-            args_count/value to not be generated properly, because
-            it would force complex shell interpretation which
-            will not be supported in evaluating the arg_count/value
-            information, but the final shell may interpret this if this
-            is executed via a command-line shell. To not be a complex
-            shell command, it should be simple with paths, options
-            and variable expansions, but nothing more complex involving
-            the above unescaped characters.
-
-            "cat -option /path/file"
-            "cat 'quoted argument'"
-            "cat ~/path/escaped\ argument"
-            "/bin/cat escaped\ argument $VARIABLE"
-            etc.
-
-            It should not try and use "complex shell features" if you
-            want the arg_count and arg_value set to be correct after
-            setting the command string. For example none of:
-
-            "VAR=x /bin/command && /bin/othercommand >& /dev/null"
-            "VAR=x /bin/command `/bin/othercommand` | /bin/cmd2 && cmd3 &"
-            etc.
-
-            If you set the command the arg_count/value property contents
-            can change and be completely re-evaluated by parsing the
-            command string into an argument array set along with
-            interpreting escapes back into individual argument strings. ]]
-         get { }
-         set { }
-         values {
-            command: string; [[ The command string as described ]]
-         }
-      }
-      @property arg_count {
-         [[ Number of arguments passed in or arguments that are to be
-            passed as sepcified by arg_value ]]
-         get { }
-         values {
-            args: uint; [[ ]]
-         }
-      }
-      @property arg_value {
-         [[ Argument number by index. If the index does not exist when
-            set, it is allocated and created. Getting an argument that
-            Has not been set yet will return $NULL. Empty arguments will
-            Be ignored. Setting an argument will result in the command
-            porperty being re-evaluated and escaped into a single
-            command string if needed. ]]
-         set { }
-         get { }
-         keys {
-            num: uint; [[ ]]
-         }
-         values {
-            arg: string; [[ ]]
-         }
-      }
-      arg_append {
-         [[ Append a new string argument at the end of the arg set.
-            This functions like setting an arg_value at the end of the
-            current set so the set increases by 1 in size. ]]
-         params {
-            arg: string; [[ ]]
-         }
-      }
-      arg_reset {
-         [[ Clear all arguments in arg_value/count set. Will result in the
-            command property also being cleared. ]]
-      }
       @property priority {
          [[ The priority of this task. ]]
          get { }
index 4d482960938c8b4d9e7c43ddceeebfaebd05bb0e..a324af4f58ce1f999006b9813901a257c5d8d656 100644 (file)
@@ -25,10 +25,7 @@ typedef struct
       int in, out;
       Eo *in_handler, *out_handler;
    } fd, ctrl;
-   struct {
-      unsigned int argc;
-      const char **argv;
-   } args;
+   Eina_Array *argv;
    Efl_Callback_Array_Item_Full *event_cb;
    void *indata, *outdata;
 } Thread_Data;
@@ -151,16 +148,16 @@ _efl_loop_arguments_send(Eo *obj, void *data EINA_UNUSED, const Eina_Value v)
    Efl_Loop_Arguments arge;
    Eina_Array *arga;
    Eina_Stringshare *s;
-   unsigned int argc = efl_task_arg_count_get(obj);
-   unsigned int i;
+   Eina_Accessor *accessor;
+   const char *argv;
+   int i = 0;
 
-   arga = eina_array_new(argc);
+   accessor = efl_core_command_line_command_access(obj);
+   arga = eina_array_new(10);
 
-   for (i = 0; i < argc; i++)
+   EINA_ACCESSOR_FOREACH(accessor, i, argv)
      {
-        const char *argv = efl_task_arg_value_get(obj, i);
-        if (argv)
-          eina_array_push(arga, eina_stringshare_add(argv));
+        eina_array_push(arga, eina_stringshare_add(argv));
      }
    arge.argv = arga;
    arge.initialization = EINA_TRUE;
@@ -229,7 +226,6 @@ _efl_thread_main(void *data, Eina_Thread t)
    Eo *obj;
    Eina_Value *ret;
    Control_Data cmd;
-   unsigned int i;
    int real;
    Efl_Callback_Array_Item_Full *it;
 
@@ -280,16 +276,13 @@ _efl_thread_main(void *data, Eina_Thread t)
           efl_event_callback_priority_add(obj, it->desc, it->priority,
                                           it->func, it->user_data);
      }
-   for (i = 0; i < thdat->args.argc; i++)
-     efl_task_arg_append(obj, thdat->args.argv[i]);
+   efl_core_command_line_command_array_set(obj, thdat->argv);
    efl_future_then(obj, efl_loop_job(obj),
                    .success = _efl_loop_arguments_send);
 
-   for (i = 0; i < thdat->args.argc; i++)
-     eina_stringshare_del(thdat->args.argv[i]);
-   free(thdat->args.argv);
+   while (thdat->argv && eina_array_count(thdat->argv)) free(eina_array_pop(thdat->argv));
+   eina_array_free(thdat->argv);
    free(thdat->event_cb);
-   thdat->args.argv = NULL;
    thdat->event_cb = NULL;
 
    ret = efl_loop_begin(obj);
@@ -575,7 +568,7 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
    const char *name;
    int pipe_to_thread[2];
    int pipe_from_thread[2];
-   unsigned int argc, i, num;
+   unsigned int num;
    Efl_Callback_Array_Item_Full *it;
    Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS);
 
@@ -729,24 +722,23 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
    name = efl_name_get(obj);
    if (name) thdat->name = eina_stringshare_add(name);
 
-   argc = efl_task_arg_count_get(obj);
-   if (argc > 0)
-     {
-        thdat->args.argc = argc;
-        thdat->args.argv = malloc(argc * sizeof(char *));
-        if (thdat->args.argv)
-          {
-             for (i = 0; i < argc; i++)
-               {
-                  const char *argv = efl_task_arg_value_get(obj, i);
-                  if (argv)
-                    thdat->args.argv[i] = eina_stringshare_add(argv);
-                  else
-                    thdat->args.argv[i] = NULL;
-               }
-          }
-        // XXX: if malloc fails?
-     }
+   {
+      Eina_Accessor *acc;
+      int i = 0;
+      const char *argv;
+
+      acc = efl_core_command_line_command_access(obj);
+      if (acc)
+        {
+           thdat->argv = eina_array_new(0);
+           EINA_ACCESSOR_FOREACH(acc, i, argv)
+             {
+                eina_array_push(thdat->argv, eina_stringshare_add(argv));
+             }
+        }
+
+   }
+
    if (pd->event_cb)
      {
         num = 0;
@@ -762,9 +754,8 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
 
    if (!eina_thread_create(&(pd->thread), pri, -1, _efl_thread_main, thdat))
      {
-        for (i = 0; i < thdat->args.argc; i++)
-          eina_stringshare_del(thdat->args.argv[i]);
-        free(thdat->args.argv);
+        while (eina_array_count(thdat->argv)) eina_stringshare_del(eina_array_pop(thdat->argv));
+        eina_array_free(thdat->argv);
         efl_del(pd->fd.in_handler);
         efl_del(pd->fd.out_handler);
         efl_del(pd->ctrl.in_handler);
index 7837c7bfdbe8ee5fa38cbf62d791ca31ebe1a3f3..02bf2f15df20eec54ba9f430d4cac6bfa5fb17db 100644 (file)
@@ -1,4 +1,4 @@
-class Efl.Thread extends Efl.Task implements Efl.ThreadIO, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer
+class Efl.Thread extends Efl.Task implements Efl.ThreadIO, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer, Efl.Core.Command_Line
 {
    methods {
    }
index 98909cb6181b1d52932ec840ef3126db12a054b0..2e44804481996186959349e217c0690ba2bdca8b 100644 (file)
@@ -76,7 +76,8 @@ pub_eo_files = [
   'efl_composite_model.eo',
   'efl_view_model.eo',
   'efl_core_env.eo',
-  'efl_core_proc_env.eo'
+  'efl_core_proc_env.eo',
+  'efl_core_command_line.eo',
 ]
 
 foreach eo_file : pub_eo_files
@@ -180,10 +181,12 @@ ecore_src = [
   'ecore_main_common.h',
   'efl_exe.c',
   'efl_thread.c',
+  'efl_appthread.c',
   'efl_threadio.c',
   'efl_appthread.c',
   'efl_core_env.c',
   'efl_core_proc_env.c',
+  'efl_core_command_line.c',
 ]
 
 if sys_windows == true
index cd26e2d95ee9c6edb287bdb497977d87374f7641..2cab632622f31af9b71245dd44c757f8cff50496 100644 (file)
@@ -53,6 +53,7 @@ static const Efl_Test_Case etc[] = {
   { "Promise", efl_app_test_promise_3 },
   { "Promise", efl_app_test_promise_safety },
   { "Env", efl_test_efl_env },
+  { "CML", efl_test_efl_cml },
   { NULL, NULL }
 };
 
index 3a66dcdfcf44342e051a94b6374b45a058f4eae1..874d2bb50339e4bda5c7f0ddd5d95f7bbebe6919 100644 (file)
@@ -12,5 +12,6 @@ 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);
+void efl_test_efl_cml(TCase *tc);
 
 #endif /* _EFL_APP_SUITE_H */
diff --git a/src/tests/ecore/efl_app_test_cml.c b/src/tests/ecore/efl_app_test_cml.c
new file mode 100644 (file)
index 0000000..1b7cebf
--- /dev/null
@@ -0,0 +1,85 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define EFL_CORE_COMMAND_LINE_PROTECTED
+
+#include <stdio.h>
+#include <unistd.h>
+#define EFL_NOLEGACY_API_SUPPORT
+#include <Efl_Core.h>
+#include "efl_app_suite.h"
+#include "../efl_check.h"
+
+typedef struct {
+
+} Efl_App_Test_CML_Data;
+
+#include "efl_app_test_cml.eo.h"
+#include "efl_app_test_cml.eo.c"
+
+static Eina_Array*
+_construct_array(void)
+{
+   Eina_Array *array = eina_array_new(16);
+
+   eina_array_push(array, "/bin/sh");
+   eina_array_push(array, "-C");
+   eina_array_push(array, "foo");
+   eina_array_push(array, "--test");
+   eina_array_push(array, "--option=done");
+   eina_array_push(array, "--");
+   eina_array_push(array, "asdf --test");
+   return array;
+}
+
+static const char*
+_construct_string(void)
+{
+   return "/bin/sh -C foo --test --option=done -- \"asdf --test\"";
+}
+
+EFL_START_TEST(efl_core_cml_string)
+{
+   Efl_App_Test_CML *cml = efl_add_ref(EFL_APP_TEST_CML_CLASS, NULL);
+   Eina_Array *content = _construct_array();
+   Eina_Stringshare *str;
+   Eina_Bool b;
+   int i = 0;
+
+   b = efl_core_command_line_command_string_set(cml, _construct_string());
+   ck_assert_int_ne(b, 0);
+
+   EINA_ACCESSOR_FOREACH(efl_core_command_line_command_access(cml), i, str)
+     {
+        ck_assert_str_eq(eina_array_data_get(content, i), str);
+     }
+   ck_assert_str_eq(efl_core_command_line_command_get(cml), _construct_string());
+}
+EFL_END_TEST
+
+EFL_START_TEST(efl_core_cml_array)
+{
+   Efl_App_Test_CML *cml = efl_add_ref(EFL_APP_TEST_CML_CLASS, NULL);
+   Eina_Array *content1 = _construct_array();
+   Eina_Array *content2 = _construct_array();
+   Eina_Stringshare *str;
+   Eina_Bool b;
+   int i = 0;
+
+   b = efl_core_command_line_command_array_set(cml, content1);
+   ck_assert_int_ne(b, 0);
+
+   EINA_ACCESSOR_FOREACH(efl_core_command_line_command_access(cml), i, str)
+     {
+        ck_assert_str_eq(eina_array_data_get(content2, i), str);
+     }
+   ck_assert_str_eq(efl_core_command_line_command_get(cml), _construct_string());
+}
+EFL_END_TEST
+
+void efl_test_efl_cml(TCase *tc)
+{
+   tcase_add_test(tc, efl_core_cml_string);
+   tcase_add_test(tc, efl_core_cml_array);
+}
diff --git a/src/tests/ecore/efl_app_test_cml.eo b/src/tests/ecore/efl_app_test_cml.eo
new file mode 100644 (file)
index 0000000..b0877e0
--- /dev/null
@@ -0,0 +1,4 @@
+class Efl.App.Test.CML extends Efl.Object implements Efl.Core.Command_Line
+{
+
+}
index e3b4f6c85173cff2960e6a1f2ef40949e29c5d9b..c49d9413556a1a7767aab67df245146a22395ce3 100644 (file)
@@ -76,14 +76,32 @@ efl_app_suite_src = [
   '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_env.c',
+  'efl_app_test_cml.c',
 ]
 
+priv_eo_files = [
+   'efl_app_test_cml.eo',
+]
+
+priv_eo_file_target = []
+foreach eo_file : priv_eo_files
+  priv_eo_file_target += custom_target('eolian_gen_' + eo_file,
+    input : eo_file,
+    output : [eo_file + '.h'],
+    depfile : eo_file + '.d',
+    command : eolian_gen + [ '-I', meson.current_source_dir(), eolian_include_directories,
+                           '-o', 'h:' + join_paths(meson.current_build_dir(), eo_file + '.h'),
+                           '-o', 'c:' + join_paths(meson.current_build_dir(), eo_file + '.c'),
+                           '-o', 'd:' + join_paths(meson.current_build_dir(), eo_file + '.d'),
+                           '-gchd', '@INPUT@'])
+endforeach
+
 efl_app_suite_deps = [m]
 efl_app_suite_deps += ecore
 
 efl_app_suite = executable('efl_app_suite',
-  efl_app_suite_src,
+  efl_app_suite_src, priv_eo_file_target,
   dependencies: [efl_app_suite_deps, check],
   c_args : [
   '-DTESTS_BUILD_DIR="'+meson.current_build_dir()+'"',