Revert "Revert command line array object because it's broken by design"

This reverts commit a57c7f7510.

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 :)
This commit is contained in:
Marcel Hollerbach 2019-02-12 21:34:30 +01:00
parent 06160466e8
commit 3b262340ba
20 changed files with 520 additions and 431 deletions

View 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 \
@ -339,6 +348,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

View 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);

View File

@ -28,6 +28,7 @@
#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"

View 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;

View 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 {

View File

@ -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"

View File

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

View 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);

View 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 {

View 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,

View File

@ -12,303 +12,6 @@
//////////////////////////////////////////////////////////////////////////
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));
}

View 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 { }

View 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);

View 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 {
}

View 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

View 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 }
};

View 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 */

View File

@ -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);
}

View File

@ -0,0 +1,4 @@
class Efl.App.Test.CML extends Efl.Object implements Efl.Core.Command_Line
{
}

View 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()+'"',