cmdlet: implement a set of builtin cmdlets

This commit is contained in:
2026-05-24 20:22:19 +01:00
parent 92e58ec7c6
commit 0ee1a3575d
5 changed files with 512 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
#include "../command/cmdlet.h"
#include "../command/command.h"
#include "../runtime/pipeline.h"
#include "../runtime/runtime.h"
#include "../script-block.h"
#include "../status.h"
#include <fx/reflection/function.h>
#include <fx/string.h>
#include <fx/vector.h>
#define BSHELL_TYPE_FOREACH_OBJECT (bshell_foreach_object_get_type())
fx_type_id bshell_foreach_object_get_type(void);
FX_DECLARE_TYPE(bshell_foreach_object);
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_foreach_object)
FX_TYPE_CLASS_DECLARATION_END(bshell_foreach_object)
struct bshell_foreach_object_p {
bshell_scriptblock *f_block;
};
static enum bshell_status begin_processing(bshell_cmdlet *cmdlet)
{
struct bshell_foreach_object_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_FOREACH_OBJECT);
const fx_value *block_v = bshell_command_get_arg(cmdlet, 1);
if (!block_v) {
return BSHELL_ERR_INVALID_ARGUMENT;
}
fx_value_get_object(block_v, &p->f_block);
return BSHELL_SUCCESS;
}
static enum bshell_status process_record(
bshell_cmdlet *cmdlet,
bshell_pipeline *pipeline,
struct bshell_runtime *rt)
{
struct bshell_foreach_object_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_FOREACH_OBJECT);
fx_value in = bshell_pipeline_read_value(pipeline);
if (!fx_value_is_set(&in)) {
return BSHELL_SUCCESS;
}
bshell_runtime_push_scope(rt, p->f_block);
bshell_variable *item = bshell_runtime_define_var(rt, "_");
bshell_variable_set_value(item, &in);
fx_value out = bshell_runtime_eval(rt);
bshell_runtime_pop_scope(rt);
fx_value_unset(&in);
bshell_pipeline_write_value(pipeline, out, false);
fx_value_unset(&out);
return BSHELL_SUCCESS;
}
static enum bshell_status end_processing(bshell_cmdlet *cmdlet)
{
struct bshell_foreach_object_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_FOREACH_OBJECT);
return BSHELL_SUCCESS;
}
static void init(fx_object *obj, void *priv)
{
}
FX_TYPE_CLASS_BEGIN(bshell_foreach_object)
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_cmdlet, BSHELL_TYPE_CMDLET)
FX_INTERFACE_ENTRY(c_verb) = BSHELL_VERB_FOREACH;
FX_INTERFACE_ENTRY(c_noun) = "Object";
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
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_foreach_object)
FX_TYPE_DEFINITION_BEGIN(bshell_foreach_object)
FX_TYPE_ID(0x44ae3223, 0x14b3, 0x4c89, 0x9753, 0x6c7901ae00e9);
FX_TYPE_NAME("bshell.core.foreach_object");
FX_TYPE_EXTENDS(BSHELL_TYPE_CMDLET);
FX_TYPE_CLASS(bshell_foreach_object_class);
FX_TYPE_INSTANCE_INIT(init);
FX_TYPE_INSTANCE_PRIVATE(struct bshell_foreach_object_p);
FX_TYPE_DEFINITION_END(bshell_foreach_object)
+9
View File
@@ -0,0 +1,9 @@
#include "../status.h"
#include <fx/object.h>
#include <fx/stream.h>
enum bshell_status do_format_table(fx_object *object, fx_stream *dest)
{
return BSHELL_SUCCESS;
}
+143
View File
@@ -0,0 +1,143 @@
#include "../command/cmdlet.h"
#include "../command/command.h"
#include "../runtime/pipeline.h"
#include "../runtime/runtime.h"
#include "../runtime/scope.h"
#include "../status.h"
#include <fx/reflection/assembly.h>
#include <fx/reflection/function.h>
#include <fx/string.h>
#include <fx/vector.h>
#define BSHELL_TYPE_GET_COMMAND (bshell_get_command_get_type())
fx_type_id bshell_get_command_get_type(void);
FX_DECLARE_TYPE(bshell_get_command);
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_get_command)
FX_TYPE_CLASS_DECLARATION_END(bshell_get_command)
struct bshell_get_command_p {
bool c_eof;
};
extern const fx_assembly *bshell_assembly_get(void);
static enum bshell_status begin_processing(bshell_cmdlet *cmdlet)
{
struct bshell_get_command_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_GET_COMMAND);
return BSHELL_SUCCESS;
}
static enum bshell_status process_record(
bshell_cmdlet *cmdlet,
bshell_pipeline *pipeline,
struct bshell_runtime *rt)
{
struct bshell_get_command_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_GET_COMMAND);
if (p->c_eof) {
return BSHELL_SUCCESS;
}
fx_iterator *it = fx_iterator_begin(rt->rt_aliases);
fx_foreach(item_v, it)
{
fx_hashtable_item *item;
fx_value_get_object(&item_v, &item);
fx_value alias_v = fx_hashtable_item_get_value(item);
bshell_pipeline_write_value(pipeline, alias_v, false);
}
fx_iterator_unref(it);
fx_queue_entry *cur = fx_queue_last(&rt->rt_scope);
while (cur) {
struct runtime_scope *scope = fx_unbox(
struct runtime_scope,
cur,
s_entry);
it = fx_iterator_begin(scope->s_functions);
fx_foreach(item_v, it)
{
fx_hashtable_item *item;
fx_value_get_object(&item_v, &item);
fx_value func_v = fx_hashtable_item_get_value(item);
bshell_pipeline_write_value(pipeline, func_v, false);
}
fx_iterator_unref(it);
cur = fx_queue_prev(cur);
}
const fx_assembly *self = bshell_assembly_get();
it = fx_assembly_get_types(self);
fx_foreach(v, it)
{
fx_type *ty = NULL;
fx_value_get_object(&v, &ty);
if (fx_type_id_compare(fx_type_get_id(ty), BSHELL_TYPE_CMDLET)
== 0) {
continue;
}
bshell_command_class *cmd = fx_type_get_interface(
ty,
BSHELL_TYPE_COMMAND);
if (!cmd) {
continue;
}
fx_value callable = FX_VALUE_OBJECT(
fx_object_create(fx_type_get_id(ty)));
bshell_pipeline_write_value(pipeline, callable, false);
fx_value_unset(&callable);
}
fx_iterator_unref(it);
p->c_eof = true;
return BSHELL_SUCCESS;
}
static enum bshell_status end_processing(bshell_cmdlet *cmdlet)
{
struct bshell_get_command_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_GET_COMMAND);
return BSHELL_SUCCESS;
}
static void init(fx_object *obj, void *priv)
{
}
FX_TYPE_CLASS_BEGIN(bshell_get_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_cmdlet, BSHELL_TYPE_CMDLET)
FX_INTERFACE_ENTRY(c_verb) = BSHELL_VERB_GET;
FX_INTERFACE_ENTRY(c_noun) = "Command";
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
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_cmdlet, BSHELL_TYPE_CMDLET)
FX_TYPE_CLASS_END(bshell_get_command)
FX_TYPE_DEFINITION_BEGIN(bshell_get_command)
FX_TYPE_ID(0x4f862cc3, 0xf3d3, 0x4f04, 0xb68e, 0x8764079f03c4);
FX_TYPE_NAME("bshell.core.get_command");
FX_TYPE_EXTENDS(BSHELL_TYPE_CMDLET);
FX_TYPE_CLASS(bshell_get_command_class);
FX_TYPE_INSTANCE_INIT(init);
FX_TYPE_INSTANCE_PRIVATE(struct bshell_get_command_p);
FX_TYPE_DEFINITION_END(bshell_get_command)
+114
View File
@@ -0,0 +1,114 @@
#include "../command/cmdlet.h"
#include "../command/command.h"
#include "../runtime/pipeline.h"
#include "../status.h"
#include <fx/reflection/function.h>
#include <fx/string.h>
#include <fx/vector.h>
#define BSHELL_TYPE_GET_VERB (bshell_get_verb_get_type())
fx_type_id bshell_get_verb_get_type(void);
FX_DECLARE_TYPE(bshell_get_verb);
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_get_verb)
FX_TYPE_CLASS_DECLARATION_END(bshell_get_verb)
struct bshell_get_verb_p {
fx_hashtable *c_verbs;
fx_iterator *c_it;
};
static enum bshell_status begin_processing(bshell_cmdlet *cmdlet)
{
struct bshell_get_verb_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_GET_VERB);
p->c_verbs = bshell_get_all_verbs();
p->c_it = fx_iterator_begin(p->c_verbs);
return BSHELL_SUCCESS;
}
static enum bshell_status process_record(
bshell_cmdlet *cmdlet,
bshell_pipeline *pipeline,
struct bshell_runtime *rt)
{
struct bshell_get_verb_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_GET_VERB);
do {
fx_value v = fx_iterator_get_value(p->c_it);
if (!v.v_type) {
return BSHELL_SUCCESS;
}
fx_hashtable_item *item = NULL;
fx_value_get_object(&v, &item);
v = fx_hashtable_item_get_value(item);
bshell_verb *verb = NULL;
fx_value_get_object(&v, &verb);
fx_iterator_move_next(p->c_it);
if (bshell_verb_is_reserved(verb)) {
continue;
}
bshell_verb_ref(verb);
bshell_pipeline_write_value(
pipeline,
fx_value_copy_return(fx_hashtable_item_get_value(item)),
false);
break;
} while (1);
return BSHELL_SUCCESS;
}
static enum bshell_status end_processing(bshell_cmdlet *cmdlet)
{
struct bshell_get_verb_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_GET_VERB);
if (p->c_it) {
fx_iterator_unref(p->c_it);
p->c_it = NULL;
}
return BSHELL_SUCCESS;
}
static void init(fx_object *obj, void *priv)
{
}
FX_TYPE_CLASS_BEGIN(bshell_get_verb)
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_cmdlet, BSHELL_TYPE_CMDLET)
FX_INTERFACE_ENTRY(c_verb) = BSHELL_VERB_GET;
FX_INTERFACE_ENTRY(c_noun) = "Verb";
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
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_cmdlet, BSHELL_TYPE_CMDLET)
FX_TYPE_CLASS_END(bshell_get_verb)
FX_TYPE_DEFINITION_BEGIN(bshell_get_verb)
FX_TYPE_ID(0xa47976a6, 0xf7d8, 0x447f, 0x887b, 0x6c5d78b7bd2e);
FX_TYPE_NAME("bshell.core.get_verb");
FX_TYPE_EXTENDS(BSHELL_TYPE_CMDLET);
FX_TYPE_CLASS(bshell_get_verb_class);
FX_TYPE_INSTANCE_INIT(init);
FX_TYPE_INSTANCE_PRIVATE(struct bshell_get_verb_p);
FX_TYPE_DEFINITION_END(bshell_get_verb)
+144
View File
@@ -0,0 +1,144 @@
#include "../command/cmdlet.h"
#include "../command/command.h"
#include "../format/format.h"
#include "../runtime/pipeline.h"
#include "../status.h"
#include <fx/collections/array.h>
#include <fx/reflection/function.h>
#include <fx/string.h>
#include <fx/value-type.h>
#include <fx/vector.h>
#define BSHELL_TYPE_WRITE_OUTPUT (bshell_write_output_get_type())
fx_type_id bshell_write_output_get_type(void);
FX_DECLARE_TYPE(bshell_write_output);
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_write_output)
FX_TYPE_CLASS_DECLARATION_END(bshell_write_output)
struct bshell_write_output_p {
struct table_format_ctx w_table_ctx;
bool w_table_initialised;
};
static void initialise_table(
struct bshell_write_output_p *cmd,
const fx_value *first_record)
{
table_format_ctx_init(&cmd->w_table_ctx, fx_stdout);
const fx_type *ty = fx_type_get_by_id(first_record->v_type);
table_format_ctx_prepare_columns_from_format(
&cmd->w_table_ctx,
ty,
NULL);
table_format_ctx_print_headers(&cmd->w_table_ctx);
cmd->w_table_initialised = true;
}
static bool value_requires_table(const fx_value *value)
{
if (fx_type_is_value_type(value->v_type)) {
return false;
}
if (fx_value_is_type(value, FX_TYPE_STRING)
|| fx_value_is_type(value, FX_TYPE_ARRAY)) {
return false;
}
return true;
}
static void write_value(
struct bshell_write_output_p *cmd,
const fx_value *value)
{
if (!value_requires_table(value)) {
fx_value_to_string(value, fx_stdout, NULL);
fx_stream_write_char(fx_stdout, '\n');
return;
}
if (!cmd->w_table_initialised) {
initialise_table(cmd, value);
}
table_format_ctx_print_record(&cmd->w_table_ctx, value);
}
static enum bshell_status begin_processing(bshell_cmdlet *cmdlet)
{
struct bshell_write_output_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_WRITE_OUTPUT);
for (size_t i = 1;; i++) {
const fx_value *v = bshell_command_get_arg(cmdlet, i);
if (!v) {
break;
}
write_value(p, v);
}
return BSHELL_SUCCESS;
}
static enum bshell_status process_record(
bshell_cmdlet *cmdlet,
bshell_pipeline *pipeline,
struct bshell_runtime *rt)
{
struct bshell_write_output_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_WRITE_OUTPUT);
fx_value in = bshell_pipeline_read_value(pipeline);
if (fx_value_is_set(&in)) {
write_value(p, &in);
fx_value_unset(&in);
}
return BSHELL_SUCCESS;
}
static enum bshell_status end_processing(bshell_cmdlet *cmdlet)
{
struct bshell_write_output_p *p = fx_object_get_private(
cmdlet,
BSHELL_TYPE_WRITE_OUTPUT);
return BSHELL_SUCCESS;
}
static void init(fx_object *obj, void *priv)
{
}
FX_TYPE_CLASS_BEGIN(bshell_write_output)
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_cmdlet, BSHELL_TYPE_CMDLET)
FX_INTERFACE_ENTRY(c_verb) = BSHELL_VERB_WRITE;
FX_INTERFACE_ENTRY(c_noun) = "Output";
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
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_cmdlet, BSHELL_TYPE_CMDLET)
FX_TYPE_CLASS_END(bshell_write_output)
FX_TYPE_DEFINITION_BEGIN(bshell_write_output)
FX_TYPE_ID(0xf7f9c42d, 0xc053, 0x4ffc, 0xa8ec, 0x78fef4844ac0);
FX_TYPE_NAME("bshell.core.write_output");
FX_TYPE_EXTENDS(BSHELL_TYPE_CMDLET);
FX_TYPE_CLASS(bshell_write_output_class);
FX_TYPE_INSTANCE_INIT(init);
FX_TYPE_INSTANCE_PRIVATE(struct bshell_write_output_p);
FX_TYPE_DEFINITION_END(bshell_write_output)