summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ecore/Ecore_Eo.h1
-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/meson.build4
4 files changed, 351 insertions, 1 deletions
diff --git a/src/lib/ecore/Ecore_Eo.h b/src/lib/ecore/Ecore_Eo.h
index 348b0f5b6d..3615219c38 100644
--- a/src/lib/ecore/Ecore_Eo.h
+++ b/src/lib/ecore/Ecore_Eo.h
@@ -28,6 +28,7 @@
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"
31 32
32#include "efl_loop_message.eo.h" 33#include "efl_loop_message.eo.h"
33#include "efl_loop_message_handler.eo.h" 34#include "efl_loop_message_handler.eo.h"
diff --git a/src/lib/ecore/efl_core_command_line.c b/src/lib/ecore/efl_core_command_line.c
new file mode 100644
index 0000000000..74ae690c26
--- /dev/null
+++ b/src/lib/ecore/efl_core_command_line.c
@@ -0,0 +1,267 @@
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
new file mode 100644
index 0000000000..1cbb020856
--- /dev/null
+++ b/src/lib/ecore/efl_core_command_line.eo
@@ -0,0 +1,80 @@
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/meson.build b/src/lib/ecore/meson.build
index 98909cb618..375f745abd 100644
--- a/src/lib/ecore/meson.build
+++ b/src/lib/ecore/meson.build
@@ -76,7 +76,8 @@ 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',
80] 81]
81 82
82foreach eo_file : pub_eo_files 83foreach eo_file : pub_eo_files
@@ -184,6 +185,7 @@ ecore_src = [
184 'efl_appthread.c', 185 'efl_appthread.c',
185 'efl_core_env.c', 186 'efl_core_env.c',
186 'efl_core_proc_env.c', 187 'efl_core_proc_env.c',
188 'efl_core_command_line.c',
187] 189]
188 190
189if sys_windows == true 191if sys_windows == true