2026-05-25 10:33:29 +01:00
|
|
|
#include <bshell/command/command.h>
|
|
|
|
|
#include <bshell/runtime/pipeline.h>
|
|
|
|
|
#include <bshell/status.h>
|
2026-05-24 20:20:06 +01:00
|
|
|
#include <fx/reflection/assembly.h>
|
|
|
|
|
#include <fx/reflection/function.h>
|
|
|
|
|
#include <fx/reflection/type.h>
|
|
|
|
|
#include <fx/string.h>
|
|
|
|
|
#include <fx/vector.h>
|
|
|
|
|
|
|
|
|
|
struct bshell_command_p {
|
|
|
|
|
fx_value *cmd_args;
|
|
|
|
|
size_t cmd_nr_args;
|
|
|
|
|
bool cmd_args_reversed;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void init(fx_object *obj, void *priv)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void command_set_args(
|
|
|
|
|
struct bshell_command_p *cmd,
|
|
|
|
|
fx_value *args,
|
|
|
|
|
size_t nr_args)
|
|
|
|
|
{
|
|
|
|
|
cmd->cmd_args = args;
|
|
|
|
|
cmd->cmd_nr_args = nr_args;
|
|
|
|
|
cmd->cmd_args_reversed = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void command_set_args_reverse(
|
|
|
|
|
struct bshell_command_p *cmd,
|
|
|
|
|
fx_value *args,
|
|
|
|
|
size_t nr_args)
|
|
|
|
|
{
|
|
|
|
|
cmd->cmd_args = args;
|
|
|
|
|
cmd->cmd_nr_args = nr_args;
|
|
|
|
|
cmd->cmd_args_reversed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const fx_value *command_get_arg(
|
|
|
|
|
struct bshell_command_p *cmd,
|
|
|
|
|
size_t index)
|
|
|
|
|
{
|
|
|
|
|
if (index >= cmd->cmd_nr_args) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cmd->cmd_args_reversed) {
|
|
|
|
|
return &cmd->cmd_args[cmd->cmd_nr_args - index - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &cmd->cmd_args[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static fx_status get_command_type(
|
|
|
|
|
const fx_value *cmd_v,
|
|
|
|
|
const fx_property *prop,
|
|
|
|
|
fx_value *out)
|
|
|
|
|
{
|
|
|
|
|
bshell_command *cmd = NULL;
|
|
|
|
|
fx_value_get_object(cmd_v, &cmd);
|
2026-05-25 10:33:29 +01:00
|
|
|
bshell_command_class *cmd_class
|
|
|
|
|
= fx_object_get_interface(cmd, BSHELL_TYPE_COMMAND);
|
2026-05-24 20:20:06 +01:00
|
|
|
|
|
|
|
|
*out = FX_CSTR(cmd_class->c_command_type);
|
|
|
|
|
return FX_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static fx_status get_name(
|
|
|
|
|
const fx_value *cmd_v,
|
|
|
|
|
const fx_property *prop,
|
|
|
|
|
fx_value *out)
|
|
|
|
|
{
|
|
|
|
|
bshell_command *cmd = NULL;
|
|
|
|
|
fx_value_get_object(cmd_v, &cmd);
|
2026-05-25 10:33:29 +01:00
|
|
|
bshell_command_class *cmd_class
|
|
|
|
|
= fx_object_get_interface(cmd, BSHELL_TYPE_COMMAND);
|
2026-05-24 20:20:06 +01:00
|
|
|
|
|
|
|
|
fx_string *result = fx_string_create();
|
|
|
|
|
const fx_type *ty = fx_type_get_by_id(fx_object_query_type(cmd));
|
|
|
|
|
|
|
|
|
|
if (cmd_class->c_get_description) {
|
|
|
|
|
cmd_class->c_get_description(cmd, result);
|
|
|
|
|
} else if (cmd_class->c_get_description_static) {
|
|
|
|
|
cmd_class->c_get_description_static(ty, result);
|
|
|
|
|
} else if (cmd_class->c_get_callable_name) {
|
|
|
|
|
cmd_class->c_get_callable_name(cmd, result);
|
|
|
|
|
} else if (cmd_class->c_get_callable_name_static) {
|
|
|
|
|
cmd_class->c_get_callable_name_static(ty, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out = FX_VALUE_OBJECT(result);
|
|
|
|
|
return FX_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static fx_status get_version(
|
|
|
|
|
const fx_value *cmd_v,
|
|
|
|
|
const fx_property *prop,
|
|
|
|
|
fx_value *out)
|
|
|
|
|
{
|
|
|
|
|
bshell_command *cmd = NULL;
|
|
|
|
|
fx_value_get_object(cmd_v, &cmd);
|
|
|
|
|
const fx_type *ty = fx_type_get_by_id(fx_object_query_type(cmd));
|
|
|
|
|
const fx_assembly *assembly = fx_type_get_assembly(ty);
|
|
|
|
|
|
|
|
|
|
long major = 0, minor = 0, build = 0, revision = 0;
|
|
|
|
|
fx_assembly_get_version(assembly, &major, &minor, &build, &revision);
|
|
|
|
|
|
|
|
|
|
fx_string *result = fx_string_create();
|
|
|
|
|
if (revision != 0) {
|
|
|
|
|
fx_string_append_cstrf(
|
|
|
|
|
result,
|
|
|
|
|
"%ld.%ld.%ld.%ld",
|
|
|
|
|
major,
|
|
|
|
|
minor,
|
|
|
|
|
build,
|
|
|
|
|
revision);
|
|
|
|
|
} else {
|
|
|
|
|
fx_string_append_cstrf(
|
|
|
|
|
result,
|
|
|
|
|
"%ld.%ld.%ld",
|
|
|
|
|
major,
|
|
|
|
|
minor,
|
|
|
|
|
build);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out = FX_VALUE_OBJECT(result);
|
|
|
|
|
return FX_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static fx_status get_source(
|
|
|
|
|
const fx_value *cmd_v,
|
|
|
|
|
const fx_property *prop,
|
|
|
|
|
fx_value *out)
|
|
|
|
|
{
|
|
|
|
|
bshell_command *cmd = NULL;
|
|
|
|
|
fx_value_get_object(cmd_v, &cmd);
|
|
|
|
|
const fx_type *ty = fx_type_get_by_id(fx_object_query_type(cmd));
|
|
|
|
|
const fx_assembly *assembly = fx_type_get_assembly(ty);
|
|
|
|
|
|
|
|
|
|
*out = FX_CSTR(fx_assembly_get_name(assembly));
|
|
|
|
|
return FX_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
extern const fx_assembly *bshell_runtime_assembly_get(void);
|
2026-05-24 20:20:06 +01:00
|
|
|
|
|
|
|
|
bshell_command *bshell_command_find_static(const char *name)
|
|
|
|
|
{
|
|
|
|
|
fx_string *target_name = fx_string_create();
|
|
|
|
|
fx_string *call_name = fx_string_create_from_cstr(name);
|
|
|
|
|
fx_string_transform_lowercase(call_name);
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
bshell_command *result = NULL;
|
|
|
|
|
|
|
|
|
|
fx_iterator *assemblies = fx_assembly_get_all();
|
|
|
|
|
fx_foreach(asm_v, assemblies)
|
2026-05-24 20:20:06 +01:00
|
|
|
{
|
2026-05-25 10:33:29 +01:00
|
|
|
fx_assembly *assembly = NULL;
|
2026-05-25 19:14:52 +01:00
|
|
|
fx_value_get_object(asm_v, &assembly);
|
2026-05-25 10:33:29 +01:00
|
|
|
fx_iterator *types = fx_assembly_get_types(assembly);
|
|
|
|
|
fx_foreach(v, types)
|
|
|
|
|
{
|
|
|
|
|
fx_type *ty = NULL;
|
2026-05-25 19:14:52 +01:00
|
|
|
fx_value_get_object(v, &ty);
|
2026-05-25 10:33:29 +01:00
|
|
|
if (fx_type_id_compare(
|
|
|
|
|
fx_type_get_id(ty),
|
|
|
|
|
BSHELL_TYPE_COMMAND)
|
|
|
|
|
== 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
bshell_command_class *cmd = fx_type_get_interface(
|
|
|
|
|
ty,
|
|
|
|
|
BSHELL_TYPE_COMMAND);
|
|
|
|
|
if (!cmd || !cmd->c_get_callable_name_static) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fx_string_clear(target_name);
|
|
|
|
|
cmd->c_get_callable_name_static(ty, target_name);
|
|
|
|
|
|
|
|
|
|
if (!fx_strcmp_nocase(
|
|
|
|
|
fx_string_get_cstr(call_name),
|
|
|
|
|
fx_string_get_cstr(target_name))) {
|
|
|
|
|
result = fx_object_create(fx_type_get_id(ty));
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-05-24 20:20:06 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
fx_iterator_unref(types);
|
2026-05-24 20:20:06 +01:00
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
fx_iterator_unref(assemblies);
|
|
|
|
|
fx_string_unref(call_name);
|
|
|
|
|
fx_string_unref(target_name);
|
|
|
|
|
|
|
|
|
|
return result;
|
2026-05-24 20:20:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bshell_command_set_args(
|
|
|
|
|
bshell_command *cmd,
|
|
|
|
|
fx_value *args,
|
|
|
|
|
size_t nr_args)
|
|
|
|
|
{
|
|
|
|
|
FX_CLASS_DISPATCH_STATIC_V(
|
|
|
|
|
BSHELL_TYPE_COMMAND,
|
|
|
|
|
command_set_args,
|
|
|
|
|
cmd,
|
|
|
|
|
args,
|
|
|
|
|
nr_args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bshell_command_set_args_reverse(
|
|
|
|
|
bshell_command *cmd,
|
|
|
|
|
fx_value *args,
|
|
|
|
|
size_t nr_args)
|
|
|
|
|
{
|
|
|
|
|
FX_CLASS_DISPATCH_STATIC_V(
|
|
|
|
|
BSHELL_TYPE_COMMAND,
|
|
|
|
|
command_set_args_reverse,
|
|
|
|
|
cmd,
|
|
|
|
|
args,
|
|
|
|
|
nr_args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const fx_value *bshell_command_get_arg(bshell_command *cmd, size_t index)
|
|
|
|
|
{
|
|
|
|
|
FX_CLASS_DISPATCH_STATIC(
|
|
|
|
|
BSHELL_TYPE_COMMAND,
|
|
|
|
|
command_get_arg,
|
|
|
|
|
cmd,
|
|
|
|
|
index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum bshell_status bshell_command_begin_processing(bshell_command *command)
|
|
|
|
|
{
|
|
|
|
|
FX_CLASS_DISPATCH_VIRTUAL_0(
|
|
|
|
|
bshell_command,
|
|
|
|
|
BSHELL_TYPE_COMMAND,
|
|
|
|
|
BSHELL_ERR_NOT_SUPPORTED,
|
|
|
|
|
c_begin_processing,
|
|
|
|
|
command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum bshell_status bshell_command_process_record(
|
|
|
|
|
bshell_command *command,
|
|
|
|
|
bshell_pipeline *pipeline,
|
|
|
|
|
struct bshell_runtime *rt)
|
|
|
|
|
{
|
|
|
|
|
FX_CLASS_DISPATCH_VIRTUAL(
|
|
|
|
|
bshell_command,
|
|
|
|
|
BSHELL_TYPE_COMMAND,
|
|
|
|
|
BSHELL_ERR_NOT_SUPPORTED,
|
|
|
|
|
c_process_record,
|
|
|
|
|
command,
|
|
|
|
|
pipeline,
|
|
|
|
|
rt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum bshell_status bshell_command_end_processing(bshell_command *command)
|
|
|
|
|
{
|
|
|
|
|
FX_CLASS_DISPATCH_VIRTUAL_0(
|
|
|
|
|
bshell_command,
|
|
|
|
|
BSHELL_TYPE_COMMAND,
|
|
|
|
|
BSHELL_ERR_NOT_SUPPORTED,
|
|
|
|
|
c_end_processing,
|
|
|
|
|
command);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FX_TYPE_CLASS_BEGIN(bshell_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_PROPERTY("command_type", get_command_type, NULL);
|
|
|
|
|
FX_TYPE_PROPERTY("name", get_name, NULL);
|
|
|
|
|
FX_TYPE_PROPERTY("version", get_version, NULL);
|
|
|
|
|
FX_TYPE_PROPERTY("source", get_source, NULL);
|
|
|
|
|
FX_TYPE_CLASS_END(bshell_command)
|
|
|
|
|
|
|
|
|
|
FX_TYPE_DEFINITION_BEGIN(bshell_command)
|
|
|
|
|
FX_TYPE_ID(0x5c50630d, 0x7535, 0x40ed, 0xbae5, 0x88aabc274d79);
|
2026-05-25 10:33:29 +01:00
|
|
|
FX_TYPE_FLAGS(FX_TYPE_F_ABSTRACT);
|
|
|
|
|
FX_TYPE_NAME("bshell.runtime.command");
|
2026-05-24 20:20:06 +01:00
|
|
|
FX_TYPE_CLASS(bshell_command_class);
|
|
|
|
|
FX_TYPE_INSTANCE_INIT(init);
|
|
|
|
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_command_p);
|
|
|
|
|
FX_TYPE_DEFINITION_END(bshell_command)
|