Files
bshell/bshell.runtime/command/native-command.c
T

230 lines
6.0 KiB
C
Raw Normal View History

#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(
2026-06-15 17:41:08 +01:00
fx_stringstream_get_cstr(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)