summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2019-02-12 19:54:22 +0000
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2019-02-12 19:54:35 +0000
commita57c7f751023fe1d1edeabbf8683574ac7497e5e (patch)
tree8803287a8502e666ee9f1762d850e9c9e978506c
parente908142da6e27a8e38f29895770d5d40f8587498 (diff)
Revert command line array object because it's broken by design
Revert "ecore: get rid of commands in efl_task." This reverts commit 616381e9cfed41b83fef039b0e38c09b41fd3d7f. Revert "ecore: here comes a command line object" This reverts commit 48e5684b3c37b337edd7004e68fc0690b58a84e6. 1. this is broken: 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); } it returns a const char * BUT it duplicates it on return. no. a big fat honking NO. return a char * or don't duplicate. pick. 2. _efl_core_command_line_command_array_set() is broken by design. it accepts an array of strings, but the strings are owned by the caller who creates the array (requiring they free them up themselves after this call) but the array becomes owned by the callee. the code here frees the incoming array but doesn't care about the string content of it. it's leak heaven waiting to happen (or bugs when someone wants to access the array they create to walk it to free the strings they put into it after it is set). i brought this up and it was dismissed. now exactly he issue i brought up is there with mixed ownership and the added complexity as well as transfer of some ownership but not others. go back and think about this so it isn't broken by design.
-rw-r--r--src/Makefile_Ecore.am12
-rw-r--r--src/bindings/mono/efl_mono/efl_csharp_application.cs5
-rw-r--r--src/lib/ecore/Ecore_Eo.h1
-rw-r--r--src/lib/ecore/efl_app.eo2
-rw-r--r--src/lib/ecore/efl_appthread.eo2
-rw-r--r--src/lib/ecore/efl_core_command_line.c267
-rw-r--r--src/lib/ecore/efl_core_command_line.eo80
-rw-r--r--src/lib/ecore/efl_exe.c4
-rw-r--r--src/lib/ecore/efl_exe.eo2
-rw-r--r--src/lib/ecore/efl_loop.c10
-rw-r--r--src/lib/ecore/efl_task.c298
-rw-r--r--src/lib/ecore/efl_task.eo77
-rw-r--r--src/lib/ecore/efl_thread.c71
-rw-r--r--src/lib/ecore/efl_thread.eo2
-rw-r--r--src/lib/ecore/meson.build5
-rw-r--r--src/tests/ecore/efl_app_suite.c1
-rw-r--r--src/tests/ecore/efl_app_suite.h1
-rw-r--r--src/tests/ecore/efl_app_test_cml.c85
-rw-r--r--src/tests/ecore/efl_app_test_cml.eo4
-rw-r--r--src/tests/ecore/meson.build22
20 files changed, 431 insertions, 520 deletions
diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am
index fd6074dec3..5f10ea7f2e 100644
--- a/src/Makefile_Ecore.am
+++ b/src/Makefile_Ecore.am
@@ -52,10 +52,6 @@ ecore_eolian_files_public = \
52 lib/ecore/efl_view_model.eo \ 52 lib/ecore/efl_view_model.eo \
53 lib/ecore/efl_core_env.eo \ 53 lib/ecore/efl_core_env.eo \
54 lib/ecore/efl_core_proc_env.eo \ 54 lib/ecore/efl_core_proc_env.eo \
55 lib/ecore/efl_core_command_line.eo
56
57ecore_test_eolian_files = \
58 tests/ecore/efl_app_test_cml.eo
59 55
60ecore_eolian_files = \ 56ecore_eolian_files = \
61 $(ecore_eolian_files_legacy) \ 57 $(ecore_eolian_files_legacy) \
@@ -64,14 +60,10 @@ ecore_eolian_files = \
64ecore_eolian_c = $(ecore_eolian_files:%.eo=%.eo.c) 60ecore_eolian_c = $(ecore_eolian_files:%.eo=%.eo.c)
65ecore_eolian_h = $(ecore_eolian_files:%.eo=%.eo.h) \ 61ecore_eolian_h = $(ecore_eolian_files:%.eo=%.eo.h) \
66 $(ecore_eolian_files_legacy:%.eo=%.eo.legacy.h) 62 $(ecore_eolian_files_legacy:%.eo=%.eo.legacy.h)
67ecore_test_c = $(ecore_test_eolian_files:%.eo=%.eo.c)
68ecore_test_h = $(ecore_test_eolian_files:%.eo=%.eo.h)
69 63
70BUILT_SOURCES += \ 64BUILT_SOURCES += \
71 $(ecore_eolian_c) \ 65 $(ecore_eolian_c) \
72 $(ecore_eolian_h) \ 66 $(ecore_eolian_h)
73 $(ecore_test_c) \
74 $(ecore_test_h)
75 67
76ecoreeolianfilesdir = $(datadir)/eolian/include/ecore-@VMAJ@ 68ecoreeolianfilesdir = $(datadir)/eolian/include/ecore-@VMAJ@
77ecoreeolianfiles_DATA = $(ecore_eolian_files_public) lib/ecore/efl_loop_timer.eo 69ecoreeolianfiles_DATA = $(ecore_eolian_files_public) lib/ecore/efl_loop_timer.eo
@@ -108,7 +100,6 @@ lib/ecore/ecore_job.c \
108lib/ecore/ecore_main.c \ 100lib/ecore/ecore_main.c \
109lib/ecore/ecore_event_message.c \ 101lib/ecore/ecore_event_message.c \
110lib/ecore/ecore_event_message_handler.c \ 102lib/ecore/ecore_event_message_handler.c \
111lib/ecore/efl_core_command_line.c \
112lib/ecore/efl_core_env.c \ 103lib/ecore/efl_core_env.c \
113lib/ecore/efl_core_proc_env.c \ 104lib/ecore/efl_core_proc_env.c \
114lib/ecore/efl_app.c \ 105lib/ecore/efl_app.c \
@@ -348,7 +339,6 @@ tests/ecore/efl_app_test_loop.c \
348tests/ecore/efl_app_test_loop_fd.c \ 339tests/ecore/efl_app_test_loop_fd.c \
349tests/ecore/efl_app_test_loop_timer.c \ 340tests/ecore/efl_app_test_loop_timer.c \
350tests/ecore/efl_app_test_promise.c \ 341tests/ecore/efl_app_test_promise.c \
351tests/ecore/efl_app_test_cml.c \
352tests/ecore/efl_app_test_env.c \ 342tests/ecore/efl_app_test_env.c \
353tests/ecore/efl_app_suite.c \ 343tests/ecore/efl_app_suite.c \
354tests/ecore/efl_app_suite.h 344tests/ecore/efl_app_suite.h
diff --git a/src/bindings/mono/efl_mono/efl_csharp_application.cs b/src/bindings/mono/efl_mono/efl_csharp_application.cs
index 84732d3993..2b2c55c75e 100644
--- a/src/bindings/mono/efl_mono/efl_csharp_application.cs
+++ b/src/bindings/mono/efl_mono/efl_csharp_application.cs
@@ -104,9 +104,8 @@ namespace Efl {
104 public void Launch(Efl.Csharp.Components components=Components.Ui) { 104 public void Launch(Efl.Csharp.Components components=Components.Ui) {
105 Init(components); 105 Init(components);
106 Efl.App app = Efl.App.AppMain; 106 Efl.App app = Efl.App.AppMain;
107 Eina.Array<String> command_line = new Eina.Array<String>(); 107 foreach (var arg in Environment.GetCommandLineArgs())
108 command_line.Append(Environment.GetCommandLineArgs()); 108 app.AppendArg(arg);
109 app.SetCommandArray(command_line);
110 app.ArgumentsEvt += (object sender, LoopArgumentsEvt_Args evt) => { 109 app.ArgumentsEvt += (object sender, LoopArgumentsEvt_Args evt) => {
111 if (evt.arg.Initialization) { 110 if (evt.arg.Initialization) {
112 OnInitialize(evt.arg.Argv); 111 OnInitialize(evt.arg.Argv);
diff --git a/src/lib/ecore/Ecore_Eo.h b/src/lib/ecore/Ecore_Eo.h
index 3615219c38..348b0f5b6d 100644
--- a/src/lib/ecore/Ecore_Eo.h
+++ b/src/lib/ecore/Ecore_Eo.h
@@ -28,7 +28,6 @@
28 28
29#include "efl_core_env.eo.h" 29#include "efl_core_env.eo.h"
30#include "efl_core_proc_env.eo.h" 30#include "efl_core_proc_env.eo.h"
31#include "efl_core_command_line.eo.h"
32 31
33#include "efl_loop_message.eo.h" 32#include "efl_loop_message.eo.h"
34#include "efl_loop_message_handler.eo.h" 33#include "efl_loop_message_handler.eo.h"
diff --git a/src/lib/ecore/efl_app.eo b/src/lib/ecore/efl_app.eo
index e046428626..f90324b39d 100644
--- a/src/lib/ecore/efl_app.eo
+++ b/src/lib/ecore/efl_app.eo
@@ -1,6 +1,6 @@
1import efl_types; 1import efl_types;
2 2
3class Efl.App extends Efl.Loop implements Efl.Core.Command_Line 3class Efl.App extends Efl.Loop
4{ 4{
5 [[ ]] 5 [[ ]]
6 data: null; 6 data: null;
diff --git a/src/lib/ecore/efl_appthread.eo b/src/lib/ecore/efl_appthread.eo
index 82a9d77ace..c60308f468 100644
--- a/src/lib/ecore/efl_appthread.eo
+++ b/src/lib/ecore/efl_appthread.eo
@@ -1,4 +1,4 @@
1class Efl.Appthread extends Efl.Loop implements Efl.ThreadIO, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer, Efl.Core.Command_Line 1class Efl.Appthread extends Efl.Loop implements Efl.ThreadIO, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer
2{ 2{
3 [[ ]] 3 [[ ]]
4 methods { 4 methods {
diff --git a/src/lib/ecore/efl_core_command_line.c b/src/lib/ecore/efl_core_command_line.c
deleted file mode 100644
index 74ae690c26..0000000000
--- a/src/lib/ecore/efl_core_command_line.c
+++ /dev/null
@@ -1,267 +0,0 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#define EFL_CORE_COMMAND_LINE_PROTECTED
6
7#include <Efl_Core.h>
8
9#define MY_CLASS EFL_CORE_COMMAND_LINE_MIXIN
10
11typedef struct {
12 Eina_Bool filled;
13 char *string_command;
14 Eina_Array *command;
15} Efl_Core_Command_Line_Data;
16
17static Eina_Array *
18_unescape(const char *s)
19{
20 Eina_Array *args;
21 const char *p;
22 char *tmp = NULL, *d = NULL;
23 if (!s) return NULL;
24
25 Eina_Bool in_quote_dbl = EINA_FALSE;
26 Eina_Bool in_quote = EINA_FALSE;
27
28 args = eina_array_new(16);
29 if (!args) return NULL;
30 for (p = s; *p; p++)
31 {
32 if (!tmp) tmp = d = strdup(p);
33 if (tmp)
34 {
35 if (in_quote_dbl)
36 {
37 switch (*p)
38 {
39 case '\"':
40 in_quote_dbl = EINA_FALSE;
41 *d = 0;
42 eina_array_push(args, eina_stringshare_add(tmp));
43 free(tmp);
44 tmp = d = NULL;
45 break;
46 case '\\':
47 p++;
48 EINA_FALLTHROUGH
49 default:
50 *d = *p;
51 d++;
52 break;
53 }
54 }
55 else if (in_quote)
56 {
57 switch (*p)
58 {
59 case '\'':
60 in_quote = EINA_FALSE;
61 *d = 0;
62 eina_array_push(args, eina_stringshare_add(tmp));
63 free(tmp);
64 tmp = d = NULL;
65 break;
66 case '\\':
67 p++;
68 EINA_FALLTHROUGH
69 default:
70 *d = *p;
71 d++;
72 break;
73 }
74 }
75 else
76 {
77 switch (*p)
78 {
79 case ' ':
80 case '\t':
81 case '\r':
82 case '\n':
83 *d = 0;
84 eina_array_push(args, eina_stringshare_add(tmp));
85 free(tmp);
86 tmp = d = NULL;
87 break;
88 case '\"':
89 in_quote_dbl = EINA_TRUE;
90 break;
91 case '\'':
92 in_quote = EINA_TRUE;
93 break;
94 case '\\':
95 p++;
96 EINA_FALLTHROUGH
97 default:
98 *d = *p;
99 d++;
100 break;
101 }
102 }
103 }
104 }
105 if (tmp)
106 {
107 *d = 0;
108 eina_array_push(args, eina_stringshare_add(tmp));
109 free(tmp);
110 }
111 return args;
112}
113
114static char *
115_escape(const char *s)
116{
117 Eina_Bool need_quote = EINA_FALSE;
118 const char *p;
119 char *s2 = malloc((strlen(s) * 2) + 1 + 2), *d;
120
121 if (!s2) return NULL;
122
123 for (p = s; *p; p++)
124 {
125 switch (*p)
126 {
127 case '\'':
128 case '\"':
129 case '$':
130 case '#':
131 case ';':
132 case '&':
133 case '`':
134 case '|':
135 case '(':
136 case ')':
137 case '[':
138 case ']':
139 case '{':
140 case '}':
141 case '>':
142 case '<':
143 case '\n':
144 case '\r':
145 case '\t':
146 case ' ':
147 need_quote = EINA_TRUE;
148 default:
149 break;
150 }
151 }
152
153 d = s2;
154 if (need_quote)
155 {
156 *d = '\"';
157 d++;
158 }
159 for (p = s; *p; p++, d++)
160 {
161 switch (*p)
162 {
163 case '\\':
164 case '\'':
165 case '\"':
166 *d = '\\';
167 d++;
168 EINA_FALLTHROUGH
169 default:
170 *d = *p;
171 break;
172 }
173 }
174 if (need_quote)
175 {
176 *d = '\"';
177 d++;
178 }
179 *d = 0;
180 return s2;
181}
182
183EOLIAN static const char*
184_efl_core_command_line_command_get(const Eo *obj EINA_UNUSED, Efl_Core_Command_Line_Data *pd)
185{
186 return eina_strdup(pd->string_command);
187}
188
189EOLIAN static Eina_Accessor*
190_efl_core_command_line_command_access(Eo *obj EINA_UNUSED, Efl_Core_Command_Line_Data *pd)
191{
192 return pd->command ? eina_array_accessor_new(pd->command) : NULL;
193}
194
195static void
196_remove_invalid_chars(char *command)
197{
198 for (unsigned int i = 0; i < strlen(command); ++i)
199 {
200 char c = command[i];
201 if (c < 0x20 || c == 0x7f)
202 command[i] = '\x12';
203 }
204}
205
206EOLIAN static Eina_Bool
207_efl_core_command_line_command_array_set(Eo *obj EINA_UNUSED, Efl_Core_Command_Line_Data *pd, Eina_Array *array)
208{
209 EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->filled, EINA_FALSE);
210 Eina_Strbuf *command = eina_strbuf_new();
211 unsigned int i = 0;
212
213 pd->command = eina_array_new(eina_array_count(array));
214 for (i = 0; i < (array ? eina_array_count(array) : 0); ++i)
215 {
216 char *content = eina_array_data_get(array, i);
217 char *param = calloc(1, strlen(content));
218
219 if (!param)
220 {
221 free(param);
222 while (eina_array_count(pd->command) > 0)
223 eina_stringshare_del(eina_array_pop(pd->command));
224 eina_array_free(pd->command);
225 pd->command = NULL;
226 eina_array_free(array);
227 return EINA_FALSE;
228 }
229
230 //build the command
231 if (i != 0)
232 eina_strbuf_append(command, " ");
233 eina_strbuf_append(command, _escape(content));
234 //convert string to stringshare
235 strcpy(param, content);
236 _remove_invalid_chars(param);
237 eina_array_push(pd->command, eina_stringshare_add(param));
238 free(param);
239 }
240 pd->string_command = eina_strbuf_release(command);
241 pd->filled = EINA_TRUE;
242 eina_array_free(array);
243
244 return EINA_TRUE;
245}
246
247EOLIAN static Eina_Bool
248_efl_core_command_line_command_string_set(Eo *obj EINA_UNUSED, Efl_Core_Command_Line_Data *pd, const char *str)
249{
250 EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->filled, EINA_FALSE);
251
252 pd->string_command = eina_strdup(str);
253 _remove_invalid_chars(pd->string_command);
254 pd->command = _unescape(str);
255 if (!pd->command)
256 {
257 if (pd->string_command)
258 free(pd->string_command);
259 pd->string_command = NULL;
260 return EINA_FALSE;
261 }
262 pd->filled = EINA_TRUE;
263
264 return EINA_TRUE;
265}
266
267#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
deleted file mode 100644
index 1cbb020856..0000000000
--- a/src/lib/ecore/efl_core_command_line.eo
+++ /dev/null
@@ -1,80 +0,0 @@
1mixin Efl.Core.Command_Line {
2 [[A mixin that implements standard functions for command lines.
3
4 This object parses the command line that gets passed, later the object can be accessed via accessor or the string directly.
5 ]]
6 methods {
7 @property command {
8 [[ A commandline that encodes arguments in a command string.
9 This command is unix shell-style, thus whitespace separates
10 arguments unless escaped. Also a semi-colon ';', ampersand
11 '&', pipe/bar '|', hash '#', bracket, square brace, brace
12 character ('(', ')', '[', ']', '{', '}'), exclamation
13 mark '!', backquote '`', greator or less than ('>' '<')
14 character unless escaped or in quotes would cause
15 args_count/value to not be generated properly, because
16 it would force complex shell interpretation which
17 will not be supported in evaluating the arg_count/value
18 information, but the final shell may interpret this if this
19 is executed via a command-line shell. To not be a complex
20 shell command, it should be simple with paths, options
21 and variable expansions, but nothing more complex involving
22 the above unescaped characters.
23
24 "cat -option /path/file"
25 "cat 'quoted argument'"
26 "cat ~/path/escaped\ argument"
27 "/bin/cat escaped\ argument $VARIABLE"
28 etc.
29
30 It should not try and use "complex shell features" if you
31 want the arg_count and arg_value set to be correct after
32 setting the command string. For example none of:
33
34 "VAR=x /bin/command && /bin/othercommand >& /dev/null"
35 "VAR=x /bin/command `/bin/othercommand` | /bin/cmd2 && cmd3 &"
36 etc.
37
38 If you set the command the arg_count/value property contents
39 can change and be completely re-evaluated by parsing the
40 command string into an argument array set along with
41 interpreting escapes back into individual argument strings.
42 ]]
43 get {
44
45 }
46 values {
47 commandline : string;
48 }
49 }
50 command_access {
51 [[ Get the accessor which enables access to each argument that got passed to this object. ]]
52 return : accessor<stringshare>;
53 }
54 @property command_array {
55 [[ Use an array to fill this object
56
57 Every element of a string is a argument.
58 ]]
59 set {
60 return : bool; [[On success $true, $false otherwise]]
61 }
62 values {
63 array : array<string> @owned; [[An array where every array field is an argument]]
64 }
65 }
66 @property command_string {
67 [[ Use a string to fill this object
68
69 The string will be split at every unescaped ' ', every resulting substring will be a new argument to the command line.
70 ]]
71 set {
72 return : bool; [[On success $true, $false otherwise]]
73 }
74 values {
75 str : string; [[A command in form of a string]]
76 }
77
78 }
79 }
80}
diff --git a/src/lib/ecore/efl_exe.c b/src/lib/ecore/efl_exe.c
index 61ff4ba798..4b3bc658d6 100644
--- a/src/lib/ecore/efl_exe.c
+++ b/src/lib/ecore/efl_exe.c
@@ -395,7 +395,7 @@ _efl_exe_efl_task_priority_get(const Eo *obj EINA_UNUSED, Efl_Exe_Data *pd)
395} 395}
396 396
397EOLIAN static Eina_Future * 397EOLIAN static Eina_Future *
398_efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd) 398_efl_exe_efl_task_run(Eo *obj EINA_UNUSED, Efl_Exe_Data *pd)
399{ 399{
400#ifdef _WIN32 400#ifdef _WIN32
401 return EINA_FALSE; 401 return EINA_FALSE;
@@ -414,7 +414,7 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
414 if (!td) return NULL; 414 if (!td) return NULL;
415 415
416 // get a cmdline to run 416 // get a cmdline to run
417 cmd = efl_core_command_line_command_get(obj); 417 cmd = efl_task_command_get(obj);
418 if (!cmd) return NULL; 418 if (!cmd) return NULL;
419 419
420 ret = pipe(pipe_exited); 420 ret = pipe(pipe_exited);
diff --git a/src/lib/ecore/efl_exe.eo b/src/lib/ecore/efl_exe.eo
index b7f97da7dc..111814af21 100644
--- a/src/lib/ecore/efl_exe.eo
+++ b/src/lib/ecore/efl_exe.eo
@@ -19,7 +19,7 @@ enum Efl.Exe_Flags {
19 hide_io = 4 19 hide_io = 4
20} 20}
21 21
22class Efl.Exe extends Efl.Task implements Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer,Efl.Core.Command_Line 22class Efl.Exe extends Efl.Task implements Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer
23{ 23{
24 [[ ]] 24 [[ ]]
25 methods { 25 methods {
diff --git a/src/lib/ecore/efl_loop.c b/src/lib/ecore/efl_loop.c
index cf8600c998..68f9573b76 100644
--- a/src/lib/ecore/efl_loop.c
+++ b/src/lib/ecore/efl_loop.c
@@ -383,19 +383,17 @@ _efl_loop_arguments_cleanup(Eo *o EINA_UNUSED, void *data, const Eina_Future *de
383EAPI void 383EAPI void
384ecore_loop_arguments_send(int argc, const char **argv) 384ecore_loop_arguments_send(int argc, const char **argv)
385{ 385{
386 Eina_Array *arga, *cml; 386 Eina_Array *arga;
387 int i = 0; 387 int i = 0;
388 388
389 efl_task_arg_reset(efl_main_loop_get());
389 arga = eina_array_new(argc); 390 arga = eina_array_new(argc);
390 cml = eina_array_new(argc);
391 for (i = 0; i < argc; i++) 391 for (i = 0; i < argc; i++)
392 { 392 {
393 Eina_Stringshare *arg = eina_stringshare_add(argv[i]); 393 eina_array_push(arga, eina_stringshare_add(argv[i]));
394 eina_array_push(arga, arg); 394 efl_task_arg_append(efl_main_loop_get(), argv[i]);
395 eina_array_push(cml, arg);
396 } 395 }
397 396
398 efl_core_command_line_command_array_set(efl_app_main_get(EFL_APP_CLASS), cml);
399 efl_future_then(efl_main_loop_get(), efl_loop_job(efl_main_loop_get()), 397 efl_future_then(efl_main_loop_get(), efl_loop_job(efl_main_loop_get()),
400 .success = _efl_loop_arguments_send, 398 .success = _efl_loop_arguments_send,
401 .free = _efl_loop_arguments_cleanup, 399 .free = _efl_loop_arguments_cleanup,
diff --git a/src/lib/ecore/efl_task.c b/src/lib/ecore/efl_task.c
index d610fcbf8b..311de0506a 100644
--- a/src/lib/ecore/efl_task.c
+++ b/src/lib/ecore/efl_task.c
@@ -12,6 +12,303 @@
12 12
13////////////////////////////////////////////////////////////////////////// 13//////////////////////////////////////////////////////////////////////////
14 14
15static void
16_clear_args(Efl_Task_Data *pd)
17{
18 unsigned int count, i;
19
20 if (!pd->args) return;
21 count = eina_array_count(pd->args);
22 for (i = 0; i < count; i++)
23 eina_stringshare_del(eina_array_data_get(pd->args, i));
24 eina_array_free(pd->args);
25 pd->args = NULL;
26}
27
28static Eina_Array *
29_unescape(const char *s)
30{
31 Eina_Array *args;
32 const char *p;
33 char *tmp = NULL, *d = NULL;
34 if (!s) return NULL;
35
36 Eina_Bool in_quote_dbl = EINA_FALSE;
37 Eina_Bool in_quote = EINA_FALSE;
38
39 args = eina_array_new(16);
40 if (!args) return NULL;
41 for (p = s; *p; p++)
42 {
43 if (!tmp) tmp = d = strdup(p);
44 if (tmp)
45 {
46 if (in_quote_dbl)
47 {
48 switch (*p)
49 {
50 case '\"':
51 in_quote_dbl = EINA_FALSE;
52 *d = 0;
53 eina_array_push(args, eina_stringshare_add(tmp));
54 free(tmp);
55 tmp = d = NULL;
56 break;
57 case '\\':
58 p++;
59 EINA_FALLTHROUGH
60 default:
61 *d = *p;
62 d++;
63 break;
64 }
65 }
66 else if (in_quote)
67 {
68 switch (*p)
69 {
70 case '\'':
71 in_quote = EINA_FALSE;
72 *d = 0;
73 eina_array_push(args, eina_stringshare_add(tmp));
74 free(tmp);
75 tmp = d = NULL;
76 break;
77 case '\\':
78 p++;
79 EINA_FALLTHROUGH
80 default:
81 *d = *p;
82 d++;
83 break;
84 }
85 }
86 else
87 {
88 switch (*p)
89 {
90 case ' ':
91 case '\t':
92 case '\r':
93 case '\n':
94 *d = 0;
95 eina_array_push(args, eina_stringshare_add(tmp));
96 free(tmp);
97 tmp = d = NULL;
98 break;
99 case '\"':
100 in_quote_dbl = EINA_TRUE;
101 break;
102 case '\'':
103 in_quote = EINA_TRUE;
104 break;
105 case '\\':
106 p++;
107 EINA_FALLTHROUGH
108 default:
109 *d = *p;
110 d++;
111 break;
112 }
113 }
114 }
115 }
116 if (tmp)
117 {
118 *d = 0;
119 eina_array_push(args, eina_stringshare_add(tmp));
120 free(tmp);
121 }
122 return args;
123}
124
125static char *
126_escape(const char *s)
127{
128 Eina_Bool need_quote = EINA_FALSE;
129 const char *p;
130 char *s2 = malloc((strlen(s) * 2) + 1 + 2), *d;
131
132 if (!s2) return NULL;
133
134 for (p = s; *p; p++)
135 {
136 switch (*p)
137 {
138 case '\'':
139 case '\"':
140 case '$':
141 case '#':
142 case ';':
143 case '&':
144 case '`':
145 case '|':
146 case '(':
147 case ')':
148 case '[':
149 case ']':
150 case '{':
151 case '}':
152 case '>':
153 case '<':
154 case '\n':
155 case '\r':
156 case '\t':
157 need_quote = EINA_TRUE;
158 default:
159 break;
160 }
161 }
162
163 d = s2;
164 if (need_quote)
165 {
166 *d = '\"';
167 d++;
168 }
169 for (p = s; *p; p++, d++)
170 {
171 switch (*p)
172 {
173 case ' ':
174 case '\\':
175 case '\'':
176 case '\"':
177 *d = '\\';
178 d++;
179 EINA_FALLTHROUGH
180 default:
181 *d = *p;
182 break;
183 }
184 }
185 if (need_quote)
186 {
187 *d = '\"';
188 d++;
189 }
190 *d = 0;
191 return s2;
192}
193
194static void
195_rebuild_command(Efl_Task_Data *pd)
196{
197 unsigned int count, i;
198 Eina_Strbuf *sb;
199 const char *arg, *cmd;
200 Eina_Bool have_args = EINA_FALSE;
201
202 if (!pd->command_dirty) return;
203 pd->command_dirty = EINA_FALSE;
204 eina_stringshare_del(pd->command);
205 pd->command = NULL;
206 if (!pd->args) return;
207 sb = eina_strbuf_new();
208 if (!sb) return;
209 count = eina_array_count(pd->args);
210 for (i = 0; i < count; i++)
211 {
212 arg = eina_array_data_get(pd->args, i);
213 if (arg)
214 {
215 char *str = _escape(arg);
216 if (str)
217 {
218 if (have_args) eina_strbuf_append(sb, " ");
219 eina_strbuf_append(sb, str);
220 free(str);
221 have_args = EINA_TRUE;
222 }
223 }
224 }
225 cmd = eina_strbuf_string_get(sb);
226 if (cmd) pd->command = eina_stringshare_add(cmd);
227 eina_strbuf_free(sb);
228}
229
230//////////////////////////////////////////////////////////////////////////
231
232EOLIAN static void
233_efl_task_command_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, const char *command)
234{
235 eina_stringshare_replace(&pd->command, command);
236 _clear_args(pd);
237 pd->args = _unescape(pd->command);
238}
239
240EOLIAN static const char *
241_efl_task_command_get(const Eo *obj EINA_UNUSED, Efl_Task_Data *pd)
242{
243 _rebuild_command(pd);
244 return pd->command;
245}
246
247EOLIAN static unsigned int
248_efl_task_arg_count_get(const Eo *obj EINA_UNUSED, Efl_Task_Data *pd)
249{
250 if (!pd->args) return 0;
251 return eina_array_count(pd->args);
252}
253
254EOLIAN static void
255_efl_task_arg_value_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, unsigned int num, const char *arg)
256{
257 const char *parg = NULL;
258 unsigned int count;
259
260 if (!pd->args) pd->args = eina_array_new(16);
261 count = eina_array_count(pd->args);
262 if ((count > 0) && (count > num))
263 parg = eina_array_data_get(pd->args, num);
264 else
265 {
266 unsigned int i;
267
268 for (i = count; i <= num; i++)
269 {
270 eina_array_push(pd->args, "");
271 eina_array_data_set(pd->args, i, NULL);
272 }
273 }
274
275 if (arg)
276 eina_array_data_set(pd->args, num, eina_stringshare_add(arg));
277 else
278 eina_array_data_set(pd->args, num, NULL);
279 if (parg) eina_stringshare_del(parg);
280 pd->command_dirty = EINA_TRUE;
281}
282
283EOLIAN static const char *
284_efl_task_arg_value_get(const Eo *obj EINA_UNUSED, Efl_Task_Data *pd, unsigned int num)
285{
286 unsigned int count;
287
288 if (!pd->args) return NULL;
289 count = eina_array_count(pd->args);
290 if (num >= count) return NULL;
291 return eina_array_data_get(pd->args, num);
292}
293
294EOLIAN static void
295_efl_task_arg_append(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, const char *arg)
296{
297 if (!pd->args) pd->args = eina_array_new(16);
298 if (arg)
299 eina_array_push(pd->args, eina_stringshare_add(arg));
300 else
301 eina_array_push(pd->args, NULL);
302 pd->command_dirty = EINA_TRUE;
303}
304
305EOLIAN static void
306_efl_task_arg_reset(Eo *obj EINA_UNUSED, Efl_Task_Data *pd)
307{
308 _clear_args(pd);
309 pd->command_dirty = EINA_TRUE;
310}
311
15EOLIAN static void 312EOLIAN static void
16_efl_task_priority_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, Efl_Task_Priority priority) 313_efl_task_priority_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, Efl_Task_Priority priority)
17{ 314{
@@ -47,6 +344,7 @@ _efl_task_efl_object_destructor(Eo *obj EINA_UNUSED, Efl_Task_Data *pd)
47{ 344{
48 eina_stringshare_del(pd->command); 345 eina_stringshare_del(pd->command);
49 pd->command = NULL; 346 pd->command = NULL;
347 _clear_args(pd);
50 efl_destructor(efl_super(obj, MY_CLASS)); 348 efl_destructor(efl_super(obj, MY_CLASS));
51} 349}
52 350
diff --git a/src/lib/ecore/efl_task.eo b/src/lib/ecore/efl_task.eo
index ddab5e6826..526746ff60 100644
--- a/src/lib/ecore/efl_task.eo
+++ b/src/lib/ecore/efl_task.eo
@@ -19,6 +19,83 @@ abstract Efl.Task extends Efl.Object
19{ 19{
20 [[ ]] 20 [[ ]]
21 methods { 21 methods {
22 @property command {
23 [[ A commandline that encodes arguments in a command string.
24 This command is unix shell-style, thus whitespace separates
25 arguments unless escaped. Also a semi-colon ';', ampersand
26 '&', pipe/bar '|', hash '#', bracket, square brace, brace
27 character ('(', ')', '[', ']', '{', '}'), exclamation
28 mark '!', backquote '`', greator or less than ('>' '<')
29 character unless escaped or in quotes would cause
30 args_count/value to not be generated properly, because
31 it would force complex shell interpretation which
32 will not be supported in evaluating the arg_count/value
33 information, but the final shell may interpret this if this
34 is executed via a command-line shell. To not be a complex
35 shell command, it should be simple with paths, options
36 and variable expansions, but nothing more complex involving
37 the above unescaped characters.
38
39 "cat -option /path/file"
40 "cat 'quoted argument'"
41 "cat ~/path/escaped\ argument"
42 "/bin/cat escaped\ argument $VARIABLE"
43 etc.
44
45 It should not try and use "complex shell features" if you
46 want the arg_count and arg_value set to be correct after
47 setting the command string. For example none of:
48
49 "VAR=x /bin/command && /bin/othercommand >& /dev/null"
50 "VAR=x /bin/command `/bin/othercommand` | /bin/cmd2 && cmd3 &"
51 etc.
52
53 If you set the command the arg_count/value property contents
54 can change and be completely re-evaluated by parsing the
55 command string into an argument array set along with
56 interpreting escapes back into individual argument strings. ]]
57 get { }
58 set { }
59 values {
60 command: string; [[ The command string as described ]]
61 }
62 }
63 @property arg_count {
64 [[ Number of arguments passed in or arguments that are to be
65 passed as sepcified by arg_value ]]
66 get { }
67 values {
68 args: uint; [[ ]]
69 }
70 }
71 @property arg_value {
72 [[ Argument number by index. If the index does not exist when
73 set, it is allocated and created. Getting an argument that
74 Has not been set yet will return $NULL. Empty arguments will
75 Be ignored. Setting an argument will result in the command
76 porperty being re-evaluated and escaped into a single
77 command string if needed. ]]
78 set { }
79 get { }
80 keys {
81 num: uint; [[ ]]
82 }
83 values {
84 arg: string; [[ ]]
85 }
86 }
87 arg_append {
88 [[ Append a new string argument at the end of the arg set.
89 This functions like setting an arg_value at the end of the
90 current set so the set increases by 1 in size. ]]
91 params {
92 arg: string; [[ ]]
93 }
94 }
95 arg_reset {
96 [[ Clear all arguments in arg_value/count set. Will result in the
97 command property also being cleared. ]]
98 }
22 @property priority { 99 @property priority {
23 [[ The priority of this task. ]] 100 [[ The priority of this task. ]]
24 get { } 101 get { }
diff --git a/src/lib/ecore/efl_thread.c b/src/lib/ecore/efl_thread.c
index a324af4f58..4d48296093 100644
--- a/src/lib/ecore/efl_thread.c
+++ b/src/lib/ecore/efl_thread.c
@@ -25,7 +25,10 @@ typedef struct
25 int in, out; 25 int in, out;
26 Eo *in_handler, *out_handler; 26 Eo *in_handler, *out_handler;
27 } fd, ctrl; 27 } fd, ctrl;
28 Eina_Array *argv; 28 struct {
29 unsigned int argc;
30 const char **argv;
31 } args;
29 Efl_Callback_Array_Item_Full *event_cb; 32 Efl_Callback_Array_Item_Full *event_cb;
30 void *indata, *outdata; 33 void *indata, *outdata;
31} Thread_Data; 34} Thread_Data;
@@ -148,16 +151,16 @@ _efl_loop_arguments_send(Eo *obj, void *data EINA_UNUSED, const Eina_Value v)
148 Efl_Loop_Arguments arge; 151 Efl_Loop_Arguments arge;
149 Eina_Array *arga; 152 Eina_Array *arga;
150 Eina_Stringshare *s; 153 Eina_Stringshare *s;
151 Eina_Accessor *accessor; 154 unsigned int argc = efl_task_arg_count_get(obj);
152 const char *argv; 155 unsigned int i;
153 int i = 0;
154 156
155 accessor = efl_core_command_line_command_access(obj); 157 arga = eina_array_new(argc);
156 arga = eina_array_new(10);
157 158
158 EINA_ACCESSOR_FOREACH(accessor, i, argv) 159 for (i = 0; i < argc; i++)
159 { 160 {
160 eina_array_push(arga, eina_stringshare_add(argv)); 161 const char *argv = efl_task_arg_value_get(obj, i);
162 if (argv)
163 eina_array_push(arga, eina_stringshare_add(argv));
161 } 164 }
162 arge.argv = arga; 165 arge.argv = arga;
163 arge.initialization = EINA_TRUE; 166 arge.initialization = EINA_TRUE;
@@ -226,6 +229,7 @@ _efl_thread_main(void *data, Eina_Thread t)
226 Eo *obj; 229 Eo *obj;
227 Eina_Value *ret; 230 Eina_Value *ret;
228 Control_Data cmd; 231 Control_Data cmd;
232 unsigned int i;
229 int real; 233 int real;
230 Efl_Callback_Array_Item_Full *it; 234 Efl_Callback_Array_Item_Full *it;
231 235
@@ -276,13 +280,16 @@ _efl_thread_main(void *data, Eina_Thread t)
276 efl_event_callback_priority_add(obj, it->desc, it->priority, 280 efl_event_callback_priority_add(obj, it->desc, it->priority,
277 it->func, it->user_data); 281 it->func, it->user_data);
278 } 282 }
279 efl_core_command_line_command_array_set(obj, thdat->argv); 283 for (i = 0; i < thdat->args.argc; i++)
284 efl_task_arg_append(obj, thdat->args.argv[i]);
280 efl_future_then(obj, efl_loop_job(obj), 285 efl_future_then(obj, efl_loop_job(obj),
281 .success = _efl_loop_arguments_send); 286 .success = _efl_loop_arguments_send);
282 287
283 while (thdat->argv && eina_array_count(thdat->argv)) free(eina_array_pop(thdat->argv)); 288 for (i = 0; i < thdat->args.argc; i++)
284 eina_array_free(thdat->argv); 289 eina_stringshare_del(thdat->args.argv[i]);
290 free(thdat->args.argv);
285 free(thdat->event_cb); 291 free(thdat->event_cb);
292 thdat->args.argv = NULL;
286 thdat->event_cb = NULL; 293 thdat->event_cb = NULL;
287 294
288 ret = efl_loop_begin(obj); 295 ret = efl_loop_begin(obj);
@@ -568,7 +575,7 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
568 const char *name; 575 const char *name;
569 int pipe_to_thread[2]; 576 int pipe_to_thread[2];
570 int pipe_from_thread[2]; 577 int pipe_from_thread[2];
571 unsigned int num; 578 unsigned int argc, i, num;
572 Efl_Callback_Array_Item_Full *it; 579 Efl_Callback_Array_Item_Full *it;
573 Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS); 580 Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS);
574 581
@@ -722,23 +729,24 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
722 name = efl_name_get(obj); 729 name = efl_name_get(obj);
723 if (name) thdat->name = eina_stringshare_add(name); 730 if (name) thdat->name = eina_stringshare_add(name);
724 731
725 { 732 argc = efl_task_arg_count_get(obj);
726 Eina_Accessor *acc; 733 if (argc > 0)
727 int i = 0; 734 {
728 const char *argv; 735 thdat->args.argc = argc;
729 736 thdat->args.argv = malloc(argc * sizeof(char *));
730 acc = efl_core_command_line_command_access(obj); 737 if (thdat->args.argv)
731 if (acc) 738 {
732 { 739 for (i = 0; i < argc; i++)
733 thdat->argv = eina_array_new(0); 740 {
734 EINA_ACCESSOR_FOREACH(acc, i, argv) 741 const char *argv = efl_task_arg_value_get(obj, i);
735 { 742 if (argv)
736 eina_array_push(thdat->argv, eina_stringshare_add(argv)); 743 thdat->args.argv[i] = eina_stringshare_add(argv);
737 } 744 else
738 } 745 thdat->args.argv[i] = NULL;
739 746 }
740 } 747 }
741 748 // XXX: if malloc fails?
749 }
742 if (pd->event_cb) 750 if (pd->event_cb)
743 { 751 {
744 num = 0; 752 num = 0;
@@ -754,8 +762,9 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
754 762
755 if (!eina_thread_create(&(pd->thread), pri, -1, _efl_thread_main, thdat)) 763 if (!eina_thread_create(&(pd->thread), pri, -1, _efl_thread_main, thdat))
756 { 764 {
757 while (eina_array_count(thdat->argv)) eina_stringshare_del(eina_array_pop(thdat->argv)); 765 for (i = 0; i < thdat->args.argc; i++)
758 eina_array_free(thdat->argv); 766 eina_stringshare_del(thdat->args.argv[i]);
767 free(thdat->args.argv);
759 efl_del(pd->fd.in_handler); 768 efl_del(pd->fd.in_handler);
760 efl_del(pd->fd.out_handler); 769 efl_del(pd->fd.out_handler);
761 efl_del(pd->ctrl.in_handler); 770 efl_del(pd->ctrl.in_handler);
diff --git a/src/lib/ecore/efl_thread.eo b/src/lib/ecore/efl_thread.eo
index 02bf2f15df..7837c7bfdb 100644
--- a/src/lib/ecore/efl_thread.eo
+++ b/src/lib/ecore/efl_thread.eo
@@ -1,4 +1,4 @@
1class Efl.Thread extends Efl.Task implements Efl.ThreadIO, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer, Efl.Core.Command_Line 1class Efl.Thread extends Efl.Task implements Efl.ThreadIO, Efl.Io.Reader, Efl.Io.Writer, Efl.Io.Closer
2{ 2{
3 methods { 3 methods {
4 } 4 }
diff --git a/src/lib/ecore/meson.build b/src/lib/ecore/meson.build
index 2e44804481..98909cb618 100644
--- a/src/lib/ecore/meson.build
+++ b/src/lib/ecore/meson.build
@@ -76,8 +76,7 @@ pub_eo_files = [
76 'efl_composite_model.eo', 76 'efl_composite_model.eo',
77 'efl_view_model.eo', 77 'efl_view_model.eo',
78 'efl_core_env.eo', 78 'efl_core_env.eo',
79 'efl_core_proc_env.eo', 79 'efl_core_proc_env.eo'
80 'efl_core_command_line.eo',
81] 80]
82 81
83foreach eo_file : pub_eo_files 82foreach eo_file : pub_eo_files
@@ -181,12 +180,10 @@ ecore_src = [
181 'ecore_main_common.h', 180 'ecore_main_common.h',
182 'efl_exe.c', 181 'efl_exe.c',
183 'efl_thread.c', 182 'efl_thread.c',
184 'efl_appthread.c',
185 'efl_threadio.c', 183 'efl_threadio.c',
186 'efl_appthread.c', 184 'efl_appthread.c',
187 'efl_core_env.c', 185 'efl_core_env.c',
188 'efl_core_proc_env.c', 186 'efl_core_proc_env.c',
189 'efl_core_command_line.c',
190] 187]
191 188
192if sys_windows == true 189if sys_windows == true
diff --git a/src/tests/ecore/efl_app_suite.c b/src/tests/ecore/efl_app_suite.c
index 2cab632622..cd26e2d95e 100644
--- a/src/tests/ecore/efl_app_suite.c
+++ b/src/tests/ecore/efl_app_suite.c
@@ -53,7 +53,6 @@ static const Efl_Test_Case etc[] = {
53 { "Promise", efl_app_test_promise_3 }, 53 { "Promise", efl_app_test_promise_3 },
54 { "Promise", efl_app_test_promise_safety }, 54 { "Promise", efl_app_test_promise_safety },
55 { "Env", efl_test_efl_env }, 55 { "Env", efl_test_efl_env },
56 { "CML", efl_test_efl_cml },
57 { NULL, NULL } 56 { NULL, NULL }
58}; 57};
59 58
diff --git a/src/tests/ecore/efl_app_suite.h b/src/tests/ecore/efl_app_suite.h
index 874d2bb503..3a66dcdfcf 100644
--- a/src/tests/ecore/efl_app_suite.h
+++ b/src/tests/ecore/efl_app_suite.h
@@ -12,6 +12,5 @@ void efl_app_test_promise_2(TCase *tc);
12void efl_app_test_promise_3(TCase *tc); 12void efl_app_test_promise_3(TCase *tc);
13void efl_app_test_promise_safety(TCase *tc); 13void efl_app_test_promise_safety(TCase *tc);
14void efl_test_efl_env(TCase *tc); 14void efl_test_efl_env(TCase *tc);
15void efl_test_efl_cml(TCase *tc);
16 15
17#endif /* _EFL_APP_SUITE_H */ 16#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
deleted file mode 100644
index 1b7cebf552..0000000000
--- a/src/tests/ecore/efl_app_test_cml.c
+++ /dev/null
@@ -1,85 +0,0 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#define EFL_CORE_COMMAND_LINE_PROTECTED
6
7#include <stdio.h>
8#include <unistd.h>
9#define EFL_NOLEGACY_API_SUPPORT
10#include <Efl_Core.h>
11#include "efl_app_suite.h"
12#include "../efl_check.h"
13
14typedef struct {
15
16} Efl_App_Test_CML_Data;
17
18#include "efl_app_test_cml.eo.h"
19#include "efl_app_test_cml.eo.c"
20
21static Eina_Array*
22_construct_array(void)
23{
24 Eina_Array *array = eina_array_new(16);
25
26 eina_array_push(array, "/bin/sh");
27 eina_array_push(array, "-C");
28 eina_array_push(array, "foo");
29 eina_array_push(array, "--test");
30 eina_array_push(array, "--option=done");
31 eina_array_push(array, "--");
32 eina_array_push(array, "asdf --test");
33 return array;
34}
35
36static const char*
37_construct_string(void)
38{
39 return "/bin/sh -C foo --test --option=done -- \"asdf --test\"";
40}
41
42EFL_START_TEST(efl_core_cml_string)
43{
44 Efl_App_Test_CML *cml = efl_add_ref(EFL_APP_TEST_CML_CLASS, NULL);
45 Eina_Array *content = _construct_array();
46 Eina_Stringshare *str;
47 Eina_Bool b;
48 int i = 0;
49
50 b = efl_core_command_line_command_string_set(cml, _construct_string());
51 ck_assert_int_ne(b, 0);
52
53 EINA_ACCESSOR_FOREACH(efl_core_command_line_command_access(cml), i, str)
54 {
55 ck_assert_str_eq(eina_array_data_get(content, i), str);
56 }
57 ck_assert_str_eq(efl_core_command_line_command_get(cml), _construct_string());
58}
59EFL_END_TEST
60
61EFL_START_TEST(efl_core_cml_array)
62{
63 Efl_App_Test_CML *cml = efl_add_ref(EFL_APP_TEST_CML_CLASS, NULL);
64 Eina_Array *content1 = _construct_array();
65 Eina_Array *content2 = _construct_array();
66 Eina_Stringshare *str;
67 Eina_Bool b;
68 int i = 0;
69
70 b = efl_core_command_line_command_array_set(cml, content1);
71 ck_assert_int_ne(b, 0);
72
73 EINA_ACCESSOR_FOREACH(efl_core_command_line_command_access(cml), i, str)
74 {
75 ck_assert_str_eq(eina_array_data_get(content2, i), str);
76 }
77 ck_assert_str_eq(efl_core_command_line_command_get(cml), _construct_string());
78}
79EFL_END_TEST
80
81void efl_test_efl_cml(TCase *tc)
82{
83 tcase_add_test(tc, efl_core_cml_string);
84 tcase_add_test(tc, efl_core_cml_array);
85}
diff --git a/src/tests/ecore/efl_app_test_cml.eo b/src/tests/ecore/efl_app_test_cml.eo
deleted file mode 100644
index b0877e0cf7..0000000000
--- a/src/tests/ecore/efl_app_test_cml.eo
+++ /dev/null
@@ -1,4 +0,0 @@
1class Efl.App.Test.CML extends Efl.Object implements Efl.Core.Command_Line
2{
3
4}
diff --git a/src/tests/ecore/meson.build b/src/tests/ecore/meson.build
index c49d941355..e3b4f6c851 100644
--- a/src/tests/ecore/meson.build
+++ b/src/tests/ecore/meson.build
@@ -76,32 +76,14 @@ efl_app_suite_src = [
76 'efl_app_test_loop_fd.c', 76 'efl_app_test_loop_fd.c',
77 'efl_app_test_loop_timer.c', 77 'efl_app_test_loop_timer.c',
78 'efl_app_test_promise.c', 78 'efl_app_test_promise.c',
79 'efl_app_test_env.c', 79 'efl_app_test_env.c'
80 'efl_app_test_cml.c',
81] 80]
82 81
83priv_eo_files = [
84 'efl_app_test_cml.eo',
85]
86
87priv_eo_file_target = []
88foreach eo_file : priv_eo_files
89 priv_eo_file_target += custom_target('eolian_gen_' + eo_file,
90 input : eo_file,
91 output : [eo_file + '.h'],
92 depfile : eo_file + '.d',
93 command : eolian_gen + [ '-I', meson.current_source_dir(), eolian_include_directories,
94 '-o', 'h:' + join_paths(meson.current_build_dir(), eo_file + '.h'),
95 '-o', 'c:' + join_paths(meson.current_build_dir(), eo_file + '.c'),
96 '-o', 'd:' + join_paths(meson.current_build_dir(), eo_file + '.d'),
97 '-gchd', '@INPUT@'])
98endforeach
99
100efl_app_suite_deps = [m] 82efl_app_suite_deps = [m]
101efl_app_suite_deps += ecore 83efl_app_suite_deps += ecore
102 84
103efl_app_suite = executable('efl_app_suite', 85efl_app_suite = executable('efl_app_suite',
104 efl_app_suite_src, priv_eo_file_target, 86 efl_app_suite_src,
105 dependencies: [efl_app_suite_deps, check], 87 dependencies: [efl_app_suite_deps, check],
106 c_args : [ 88 c_args : [
107 '-DTESTS_BUILD_DIR="'+meson.current_build_dir()+'"', 89 '-DTESTS_BUILD_DIR="'+meson.current_build_dir()+'"',