Files
bshell/bshell.runtime/runtime/cmdcall.c
T

265 lines
6.1 KiB
C
Raw Normal View History

#include <bshell/command/alias.h>
#include <bshell/command/command.h>
#include <bshell/runtime/cmdcall.h>
#include <bshell/runtime/pipeline.h>
#include <bshell/runtime/runtime.h>
#include <bshell/status.h>
#include <fx/collections/array.h>
#include <fx/reflection/assembly.h>
#include <fx/reflection/function.h>
#include <fx/reflection/type.h>
#include <fx/string.h>
#include <fx/vector.h>
#if BSHELL_INTERACTIVE == 1
#include <fx/term/print.h>
#endif
enum cmdcall_type {
CMDCALL_NONE = 0,
CMDCALL_CMDLET,
CMDCALL_NATIVE,
};
struct bshell_cmdcall_p {
enum cmdcall_type cmd_type;
bshell_command *cmd_target;
char *cmd_native_path;
bool cmd_initialised;
FX_VECTOR_DECLARE(fx_value, cmd_args);
fx_array *cmd_args_processed;
};
static void cmdcall_fini(fx_object *obj, void *priv)
{
struct bshell_cmdcall_p *cmdcall = priv;
2026-05-30 19:52:36 +01:00
if (cmdcall->cmd_target) {
bshell_command_end_processing(cmdcall->cmd_target);
bshell_command_unref(cmdcall->cmd_target);
}
if (cmdcall->cmd_native_path) {
free(cmdcall->cmd_native_path);
}
if (cmdcall->cmd_args_processed) {
fx_array_unref(cmdcall->cmd_args_processed);
}
for (size_t i = 0; i < cmdcall->cmd_args.count; i++) {
fx_value_unset(&cmdcall->cmd_args.items[i]);
}
fx_vector_destroy(cmdcall->cmd_args, NULL);
}
static enum bshell_status cmdcall_push_arg(
struct bshell_cmdcall_p *cmdcall,
fx_value arg)
{
fx_value *slot = fx_vector_emplace_back(cmdcall->cmd_args, NULL);
fx_value_copy(slot, &arg);
return BSHELL_SUCCESS;
}
static const fx_value *get_arg(struct bshell_cmdcall_p *cmdcall, size_t index)
{
if (index >= cmdcall->cmd_args.count) {
return NULL;
}
return &cmdcall->cmd_args.items[cmdcall->cmd_args.count - index - 1];
}
static bshell_command *__resolve_call_target(
const char *callable_name,
struct bshell_runtime *rt)
{
return bshell_runtime_find_command(rt, callable_name);
}
static enum bshell_status resolve_call_target(
struct bshell_cmdcall_p *cmdcall,
struct bshell_runtime *rt)
{
if (cmdcall->cmd_type != CMDCALL_NONE) {
return BSHELL_SUCCESS;
}
fx_value *cmd_name_v = fx_array_get_ref(cmdcall->cmd_args_processed, 0);
if (!cmd_name_v) {
return BSHELL_ERR_BAD_STATE;
}
fx_string *cmd_name_s = NULL;
fx_value_get_object(cmd_name_v, &cmd_name_s);
while (1) {
const char *cmd_name_cstr = fx_string_get_cstr(cmd_name_s);
bshell_command *cmd
= bshell_runtime_find_command(rt, cmd_name_cstr);
if (!cmd) {
break;
}
bshell_alias_class *alias
= fx_object_get_interface(cmd, BSHELL_TYPE_ALIAS);
if (alias) {
fx_string_clear(cmd_name_s);
fx_string_append_cstr(cmd_name_s, alias->a_target_name);
bshell_command_unref(cmd);
continue;
}
cmdcall->cmd_target = cmd;
cmdcall->cmd_type = CMDCALL_CMDLET;
return BSHELL_SUCCESS;
}
const char *cmd_name_cstr = fx_string_get_cstr(cmd_name_s);
#if BSHELL_INTERACTIVE == 1
fx_printf("[bold,bright_red]");
#endif
printf("%s: The term '%s' is not recognised as a name of a cmdlet, "
"function, script file, or executable program.\n",
cmd_name_cstr,
cmd_name_cstr);
#if BSHELL_INTERACTIVE == 1
fx_printf("[reset]");
#endif
printf("\n");
return BSHELL_ERR_NO_ENTRY;
}
static enum bshell_status process_args(struct bshell_cmdcall_p *cmdcall)
{
if (cmdcall->cmd_args_processed) {
return BSHELL_SUCCESS;
}
fx_stringstream *str = fx_stringstream_create();
if (!str) {
return BSHELL_ERR_NO_MEMORY;
}
cmdcall->cmd_args_processed = fx_array_create();
if (!cmdcall->cmd_args_processed) {
fx_stringstream_unref(str);
return BSHELL_ERR_NO_MEMORY;
}
for (i32 i = cmdcall->cmd_args.count - 1; i >= 0; i--) {
fx_stringstream_reset(str);
fx_value_to_string(&cmdcall->cmd_args.items[i], str, NULL);
fx_string *arg_str
= fx_string_create_from_cstr(fx_stringstream_ptr(str));
fx_array_push_back(
cmdcall->cmd_args_processed,
FX_VALUE_OBJECT(arg_str));
fx_string_unref(arg_str);
}
fx_stringstream_unref(str);
return BSHELL_SUCCESS;
}
static enum bshell_status cmdcall_resolve(
struct bshell_cmdcall_p *cmdcall,
struct bshell_runtime *rt)
{
enum bshell_status status = process_args(cmdcall);
if (status != BSHELL_SUCCESS) {
return status;
}
status = resolve_call_target(cmdcall, rt);
if (status != BSHELL_SUCCESS) {
return status;
}
bshell_command_set_args_reverse(
cmdcall->cmd_target,
cmdcall->cmd_args.items,
cmdcall->cmd_args.count);
return BSHELL_SUCCESS;
}
static enum bshell_status cmdcall_execute(struct bshell_cmdcall_p *cmdcall)
{
return BSHELL_SUCCESS;
}
static enum bshell_status cmdcall_process_record(
struct bshell_cmdcall_p *cmdcall,
bshell_pipeline *pipeline,
struct bshell_runtime *rt,
enum bshell_command_position position)
{
if (!cmdcall->cmd_target) {
return BSHELL_ERR_NOT_SUPPORTED;
}
if (!cmdcall->cmd_initialised) {
bshell_command_begin_processing(cmdcall->cmd_target, position);
cmdcall->cmd_initialised = true;
}
return bshell_command_process_record(cmdcall->cmd_target, pipeline, rt);
}
enum bshell_status bshell_cmdcall_push_arg(
bshell_cmdcall *cmdcall,
fx_value arg)
{
FX_CLASS_DISPATCH_STATIC(
BSHELL_TYPE_CMDCALL,
cmdcall_push_arg,
cmdcall,
arg);
}
enum bshell_status bshell_cmdcall_resolve(
bshell_cmdcall *cmdcall,
struct bshell_runtime *rt)
{
FX_CLASS_DISPATCH_STATIC(
BSHELL_TYPE_CMDCALL,
cmdcall_resolve,
cmdcall,
rt);
}
enum bshell_status bshell_cmdcall_process_record(
bshell_cmdcall *cmdcall,
bshell_pipeline *pipeline,
struct bshell_runtime *rt,
enum bshell_command_position position)
{
FX_CLASS_DISPATCH_STATIC(
BSHELL_TYPE_CMDCALL,
cmdcall_process_record,
cmdcall,
pipeline,
rt,
position);
}
FX_TYPE_CLASS_BEGIN(bshell_cmdcall)
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_CONSTRUCTOR("create", bshell_cmdcall_create, 0, FX_TYPE_VOID);
FX_TYPE_CLASS_END(bshell_cmdcall)
FX_TYPE_DEFINITION_BEGIN(bshell_cmdcall)
FX_TYPE_ID(0x08aeb275, 0xc09b, 0x4c3a, 0xa8df, 0xd9fba0bb4571);
FX_TYPE_NAME("bshell.cmdcall");
FX_TYPE_CLASS(bshell_cmdcall_class);
FX_TYPE_INSTANCE_PRIVATE(struct bshell_cmdcall_p);
FX_TYPE_INSTANCE_FINI(cmdcall_fini);
FX_TYPE_DEFINITION_END(bshell_cmdcall)