230 lines
6.0 KiB
C
230 lines
6.0 KiB
C
#include <bshell/command/command.h>
|
|
#include <bshell/command/native-command.h>
|
|
#include <bshell/format.h>
|
|
#include <bshell/runtime/pipeline.h>
|
|
#include <bshell/status.h>
|
|
#include <fx/diagnostics/process.h>
|
|
#include <fx/reflection/function.h>
|
|
#include <fx/string.h>
|
|
#include <fx/vector.h>
|
|
|
|
enum {
|
|
F_REDIRECT_STDIN = 0x01u,
|
|
F_REDIRECT_STDOUT = 0x02u,
|
|
};
|
|
|
|
struct bshell_native_command_p {
|
|
int cmd_flags;
|
|
fx_string *cmd_path;
|
|
fx_stringstream *cmd_tmp;
|
|
fx_process *cmd_proc;
|
|
struct bshell_value_writer cmd_writer;
|
|
bool cmd_writer_init;
|
|
};
|
|
|
|
static void init(fx_object *obj, void *priv)
|
|
{
|
|
struct bshell_native_command_p *cmd_p = priv;
|
|
cmd_p->cmd_tmp = fx_stringstream_create();
|
|
}
|
|
|
|
static void fini(fx_object *obj, void *priv)
|
|
{
|
|
struct bshell_native_command_p *cmd_p = priv;
|
|
fx_stringstream_unref(cmd_p->cmd_tmp);
|
|
fx_string_unref(cmd_p->cmd_path);
|
|
}
|
|
|
|
static enum bshell_status start_process(bshell_native_command *cmd, int flags)
|
|
{
|
|
struct bshell_native_command_p *cmd_p
|
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
|
fx_stringstream *tmp = fx_stringstream_create();
|
|
size_t argc = bshell_command_get_arg_count(cmd);
|
|
char **argv = calloc(argc, sizeof *argv);
|
|
|
|
for (size_t i = 0; i < argc; i++) {
|
|
const fx_value *arg = bshell_command_get_arg(cmd, i);
|
|
|
|
fx_stringstream_reset(tmp);
|
|
fx_value_to_string(arg, tmp, NULL);
|
|
argv[i] = fx_stringstream_steal(tmp);
|
|
}
|
|
fx_stringstream_unref(tmp);
|
|
|
|
fx_process *self = fx_process_get_self();
|
|
|
|
fx_process_start_info info = {
|
|
.proc_args = (const char **)argv,
|
|
.proc_args_count = argc,
|
|
.proc_file_name = fx_string_get_cstr(cmd_p->cmd_path),
|
|
.proc_environment = fx_process_get_environment(self),
|
|
};
|
|
|
|
if (flags & F_REDIRECT_STDIN) {
|
|
info.proc_redirect_stdin = true;
|
|
}
|
|
|
|
if (flags & F_REDIRECT_STDOUT) {
|
|
info.proc_redirect_stdout = true;
|
|
}
|
|
|
|
cmd_p->cmd_flags = flags;
|
|
cmd_p->cmd_proc = fx_process_create(&info);
|
|
|
|
fx_status status = fx_process_start(cmd_p->cmd_proc);
|
|
for (size_t i = 0; i < argc; i++) {
|
|
free(argv[i]);
|
|
}
|
|
free(argv);
|
|
|
|
if (!FX_OK(status)) {
|
|
return BSHELL_ERR_NO_MEMORY;
|
|
}
|
|
|
|
return BSHELL_SUCCESS;
|
|
}
|
|
|
|
static enum bshell_status begin_processing(
|
|
bshell_command *cmd,
|
|
enum bshell_command_position position)
|
|
{
|
|
struct bshell_native_command_p *cmd_p
|
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
|
int flags = 0;
|
|
switch (position) {
|
|
case BSHELL_COMMAND_POSITION_BEGINNING:
|
|
flags = F_REDIRECT_STDOUT;
|
|
break;
|
|
case BSHELL_COMMAND_POSITION_MIDDLE:
|
|
flags = F_REDIRECT_STDIN | F_REDIRECT_STDOUT;
|
|
break;
|
|
case BSHELL_COMMAND_POSITION_END:
|
|
flags = F_REDIRECT_STDIN;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return start_process(cmd, flags);
|
|
}
|
|
|
|
static enum bshell_status process_record(
|
|
bshell_command *cmd,
|
|
bshell_pipeline *pipeline,
|
|
struct bshell_runtime *rt)
|
|
{
|
|
struct bshell_native_command_p *cmd_p
|
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
|
|
|
if (cmd_p->cmd_flags & F_REDIRECT_STDIN) {
|
|
fx_value in = bshell_pipeline_read_value(pipeline);
|
|
if (!fx_value_is_set(&in)) {
|
|
return BSHELL_SUCCESS;
|
|
}
|
|
|
|
fx_stream *in_stream = fx_process_get_stdin(cmd_p->cmd_proc);
|
|
if (!cmd_p->cmd_writer_init) {
|
|
bshell_value_writer_init(&cmd_p->cmd_writer, in_stream);
|
|
cmd_p->cmd_writer_init = true;
|
|
}
|
|
|
|
bshell_value_writer_write(&cmd_p->cmd_writer, &in);
|
|
fx_value_unset(&in);
|
|
}
|
|
|
|
if (cmd_p->cmd_flags & F_REDIRECT_STDOUT) {
|
|
fx_stream *out_stream = fx_process_get_stdout(cmd_p->cmd_proc);
|
|
fx_stringstream_reset(cmd_p->cmd_tmp);
|
|
fx_status status
|
|
= fx_stream_read_line_s(out_stream, cmd_p->cmd_tmp);
|
|
if (!FX_OK(status)) {
|
|
/* no more data available */
|
|
return BSHELL_SUCCESS;
|
|
}
|
|
|
|
fx_string *record = fx_string_create_from_cstr(
|
|
fx_stringstream_ptr(cmd_p->cmd_tmp));
|
|
bshell_pipeline_write_value(
|
|
pipeline,
|
|
FX_VALUE_OBJECT(record),
|
|
false);
|
|
fx_string_unref(record);
|
|
}
|
|
|
|
return BSHELL_SUCCESS;
|
|
}
|
|
|
|
static enum bshell_status end_processing(bshell_command *cmd)
|
|
{
|
|
struct bshell_native_command_p *cmd_p
|
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
|
if (cmd_p->cmd_writer_init) {
|
|
bshell_value_writer_cleanup(&cmd_p->cmd_writer);
|
|
cmd_p->cmd_writer_init = false;
|
|
}
|
|
|
|
if (cmd_p->cmd_proc) {
|
|
fx_process_close_stdin(cmd_p->cmd_proc);
|
|
fx_process_close_stdout(cmd_p->cmd_proc);
|
|
fx_process_close_stderr(cmd_p->cmd_proc);
|
|
|
|
int result = 0;
|
|
fx_process_wait(cmd_p->cmd_proc, &result);
|
|
fx_process_unref(cmd_p->cmd_proc);
|
|
cmd_p->cmd_proc = NULL;
|
|
}
|
|
|
|
return BSHELL_SUCCESS;
|
|
}
|
|
|
|
static enum bshell_status get_callable_name(
|
|
const bshell_native_command *cmd,
|
|
fx_string *out)
|
|
{
|
|
struct bshell_native_command_p *cmd_p
|
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
|
fx_string_append_s(out, cmd_p->cmd_path);
|
|
return BSHELL_SUCCESS;
|
|
}
|
|
|
|
bshell_native_command *bshell_native_command_create(const char *path)
|
|
{
|
|
bshell_native_command *out
|
|
= fx_object_create(BSHELL_TYPE_NATIVE_COMMAND);
|
|
if (!out) {
|
|
return NULL;
|
|
}
|
|
|
|
struct bshell_native_command_p *cmd
|
|
= fx_object_get_private(out, BSHELL_TYPE_NATIVE_COMMAND);
|
|
cmd->cmd_path = fx_string_create_from_cstr(path);
|
|
|
|
return out;
|
|
}
|
|
|
|
FX_TYPE_CLASS_BEGIN(bshell_native_command)
|
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
|
|
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
|
FX_INTERFACE_ENTRY(c_command_type) = "Native-Command";
|
|
FX_INTERFACE_ENTRY(c_get_callable_name) = get_callable_name;
|
|
FX_INTERFACE_ENTRY(c_begin_processing) = begin_processing;
|
|
FX_INTERFACE_ENTRY(c_process_record) = process_record;
|
|
FX_INTERFACE_ENTRY(c_end_processing) = end_processing;
|
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_command, BSHELL_TYPE_COMMAND)
|
|
FX_TYPE_CLASS_END(bshell_native_command)
|
|
|
|
FX_TYPE_DEFINITION_BEGIN(bshell_native_command)
|
|
FX_TYPE_ID(0x720ede87, 0xe586, 0x495a, 0xa229, 0x1505c01b5714);
|
|
FX_TYPE_FLAGS(FX_TYPE_F_ABSTRACT);
|
|
FX_TYPE_NAME("bshell.runtime.native_command");
|
|
FX_TYPE_EXTENDS(BSHELL_TYPE_COMMAND);
|
|
FX_TYPE_CLASS(bshell_native_command_class);
|
|
FX_TYPE_INSTANCE_INIT(init);
|
|
FX_TYPE_INSTANCE_FINI(fini);
|
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_native_command_p);
|
|
FX_TYPE_DEFINITION_END(bshell_native_command)
|