管道等一系列shell语法

This commit is contained in:
2026-04-15 20:35:51 +08:00
parent 0a50c6a146
commit 3725203496
6 changed files with 693 additions and 33 deletions

View File

@@ -349,8 +349,8 @@ set(RAMDISK_ROOT_APPS)
set(USER_SHELL_COMMAND_APPS
help ls cat pwd cd exec pid spawn wait sleep yield
shutdown restart exit clear ansi memstat fsstat taskstat userstat
shstat stats tty dmesg kbdstat mkdir touch write append cp mv rm
shutdown restart exit clear ansi ansitest memstat fsstat taskstat userstat
shstat stats tty dmesg kbdstat mkdir touch write append cp mv grep rm
)
foreach(SRC IN LISTS USER_APP_MAIN_SOURCES)

View File

@@ -0,0 +1,5 @@
#include "shell/shell_internal.h"
int cleonos_app_main(void) {
return ush_command_program_main("ansitest");
}

View File

@@ -0,0 +1,5 @@
#include "shell/shell_internal.h"
int cleonos_app_main(void) {
return ush_command_program_main("grep");
}

View File

@@ -3,6 +3,22 @@
#define USH_DMESG_DEFAULT 64ULL
#define USH_DMESG_LINE_MAX 256ULL
#define USH_COPY_MAX 65536U
#define USH_PIPELINE_MAX_STAGES 8ULL
#define USH_PIPE_CAPTURE_MAX USH_COPY_MAX
typedef struct ush_pipeline_stage {
char text[USH_LINE_MAX];
char cmd[USH_CMD_MAX];
char arg[USH_ARG_MAX];
char redirect_path[USH_PATH_MAX];
int redirect_mode; /* 0: none, 1: >, 2: >> */
} ush_pipeline_stage;
static const char *ush_pipeline_stdin_text = (const char *)0;
static u64 ush_pipeline_stdin_len = 0ULL;
static char ush_pipeline_capture_a[USH_PIPE_CAPTURE_MAX + 1U];
static char ush_pipeline_capture_b[USH_PIPE_CAPTURE_MAX + 1U];
static int ush_path_is_under_temp(const char *path) {
if (path == (const char *)0) {
@@ -111,7 +127,8 @@ static int ush_cmd_help(void) {
ush_writeln("commands:");
ush_writeln(" help");
ush_writeln(" ls [-l] [-R] [path]");
ush_writeln(" cat <file>");
ush_writeln(" cat [file] (reads pipeline input when file omitted)");
ush_writeln(" grep [-n] <pattern> [file]");
ush_writeln(" pwd");
ush_writeln(" cd [dir]");
ush_writeln(" exec|run <path|name>");
@@ -123,8 +140,8 @@ static int ush_cmd_help(void) {
ush_writeln(" kbdstat");
ush_writeln(" mkdir <dir> (/temp only)");
ush_writeln(" touch <file> (/temp only)");
ush_writeln(" write <file> <text> (/temp only)");
ush_writeln(" append <file> <text> (/temp only)");
ush_writeln(" write <file> <text> (/temp only, or from pipeline)");
ush_writeln(" append <file> <text> (/temp only, or from pipeline)");
ush_writeln(" cp <src> <dst> (dst /temp only)");
ush_writeln(" mv <src> <dst> (/temp only)");
ush_writeln(" rm <path> (/temp only)");
@@ -136,6 +153,8 @@ static int ush_cmd_help(void) {
ush_writeln(" shutdown / restart");
ush_writeln(" exit [code]");
ush_writeln(" rusttest / panic / elfloader (kernel shell only)");
ush_writeln("pipeline/redirection: cmd1 | cmd2 | cmd3 > /temp/out.txt");
ush_writeln("redirection append: cmd >> /temp/out.txt");
ush_writeln("edit keys: Left/Right, Home/End, Up/Down history");
return 1;
}
@@ -439,6 +458,11 @@ static int ush_cmd_cat(const ush_state *sh, const char *arg) {
u64 got;
if (arg == (const char *)0 || arg[0] == '\0') {
if (ush_pipeline_stdin_text != (const char *)0 && ush_pipeline_stdin_len > 0ULL) {
ush_write(ush_pipeline_stdin_text);
return 1;
}
ush_writeln("cat: file path required");
return 0;
}
@@ -486,6 +510,207 @@ static int ush_cmd_cat(const ush_state *sh, const char *arg) {
return 1;
}
static void ush_grep_write_u64_dec(u64 value) {
char tmp[32];
u64 len = 0ULL;
if (value == 0ULL) {
ush_write_char('0');
return;
}
while (value > 0ULL && len < (u64)sizeof(tmp)) {
tmp[len++] = (char)('0' + (value % 10ULL));
value /= 10ULL;
}
while (len > 0ULL) {
len--;
ush_write_char(tmp[len]);
}
}
static int ush_grep_line_has_pattern(const char *line, u64 line_len, const char *pattern, u64 pattern_len) {
u64 i;
if (line == (const char *)0 || pattern == (const char *)0) {
return 0;
}
if (pattern_len == 0ULL) {
return 1;
}
if (pattern_len > line_len) {
return 0;
}
for (i = 0ULL; i + pattern_len <= line_len; i++) {
u64 j = 0ULL;
while (j < pattern_len && line[i + j] == pattern[j]) {
j++;
}
if (j == pattern_len) {
return 1;
}
}
return 0;
}
static u64 ush_grep_emit_matches(const char *input, u64 input_len, const char *pattern, int with_line_number) {
u64 matches = 0ULL;
u64 line_no = 1ULL;
u64 start = 0ULL;
u64 i;
u64 pattern_len;
if (input == (const char *)0 || pattern == (const char *)0) {
return 0ULL;
}
pattern_len = ush_strlen(pattern);
for (i = 0ULL; i <= input_len; i++) {
if (i == input_len || input[i] == '\n') {
u64 line_len = i - start;
if (ush_grep_line_has_pattern(&input[start], line_len, pattern, pattern_len) != 0) {
u64 j;
matches++;
if (with_line_number != 0) {
ush_grep_write_u64_dec(line_no);
ush_write(":");
}
for (j = 0ULL; j < line_len; j++) {
ush_write_char(input[start + j]);
}
ush_write_char('\n');
}
start = i + 1ULL;
line_no++;
}
}
return matches;
}
static int ush_cmd_grep(const ush_state *sh, const char *arg) {
char first[USH_PATH_MAX];
char second[USH_PATH_MAX];
char third[USH_PATH_MAX];
char path[USH_PATH_MAX];
const char *rest = "";
const char *rest2 = "";
const char *pattern = (const char *)0;
const char *file_arg = (const char *)0;
const char *input = (const char *)0;
u64 input_len = 0ULL;
u64 size;
u64 got;
int with_line_number = 0;
static char file_buf[USH_COPY_MAX + 1U];
if (sh == (const ush_state *)0 || arg == (const char *)0 || arg[0] == '\0') {
ush_writeln("grep: usage grep [-n] <pattern> [file]");
return 0;
}
if (ush_split_first_and_rest(arg, first, (u64)sizeof(first), &rest) == 0) {
ush_writeln("grep: usage grep [-n] <pattern> [file]");
return 0;
}
if (ush_streq(first, "-n") != 0) {
with_line_number = 1;
if (ush_split_first_and_rest(rest, second, (u64)sizeof(second), &rest2) == 0) {
ush_writeln("grep: usage grep [-n] <pattern> [file]");
return 0;
}
pattern = second;
rest = rest2;
} else {
pattern = first;
}
if (rest != (const char *)0 && rest[0] != '\0') {
if (ush_split_first_and_rest(rest, third, (u64)sizeof(third), &rest2) == 0) {
ush_writeln("grep: usage grep [-n] <pattern> [file]");
return 0;
}
file_arg = third;
if (rest2 != (const char *)0 && rest2[0] != '\0') {
ush_writeln("grep: usage grep [-n] <pattern> [file]");
return 0;
}
}
if (pattern == (const char *)0 || pattern[0] == '\0') {
ush_writeln("grep: pattern required");
return 0;
}
if (file_arg != (const char *)0) {
if (ush_resolve_path(sh, file_arg, path, (u64)sizeof(path)) == 0) {
ush_writeln("grep: invalid path");
return 0;
}
if (cleonos_sys_fs_stat_type(path) != 1ULL) {
ush_writeln("grep: file not found");
return 0;
}
size = cleonos_sys_fs_stat_size(path);
if (size == (u64)-1) {
ush_writeln("grep: failed to stat file");
return 0;
}
if (size > (u64)USH_COPY_MAX) {
ush_writeln("grep: file too large for user buffer");
return 0;
}
if (size == 0ULL) {
return 1;
}
got = cleonos_sys_fs_read(path, file_buf, size);
if (got == 0ULL || got != size) {
ush_writeln("grep: read failed");
return 0;
}
file_buf[got] = '\0';
input = file_buf;
input_len = got;
} else {
if (ush_pipeline_stdin_text == (const char *)0) {
ush_writeln("grep: file path required (or pipeline input)");
return 0;
}
input = ush_pipeline_stdin_text;
input_len = ush_pipeline_stdin_len;
}
(void)ush_grep_emit_matches(input, input_len, pattern, with_line_number);
return 1;
}
static int ush_cmd_pwd(const ush_state *sh) {
ush_writeln(sh->cwd);
return 1;
@@ -989,7 +1214,7 @@ static int ush_cmd_touch(const ush_state *sh, const char *arg) {
static int ush_cmd_write(const ush_state *sh, const char *arg) {
char path_arg[USH_PATH_MAX];
char abs_path[USH_PATH_MAX];
const char *payload;
const char *payload = (const char *)0;
u64 payload_len;
if (arg == (const char *)0 || arg[0] == '\0') {
@@ -1012,7 +1237,16 @@ static int ush_cmd_write(const ush_state *sh, const char *arg) {
return 0;
}
if (payload == (const char *)0 || payload[0] == '\0') {
if (ush_pipeline_stdin_text == (const char *)0) {
ush_writeln("write: usage write <file> <text>");
return 0;
}
payload = ush_pipeline_stdin_text;
payload_len = ush_pipeline_stdin_len;
} else {
payload_len = ush_strlen(payload);
}
if (cleonos_sys_fs_write(abs_path, payload, payload_len) == 0ULL) {
ush_writeln("write: failed");
@@ -1025,7 +1259,7 @@ static int ush_cmd_write(const ush_state *sh, const char *arg) {
static int ush_cmd_append(const ush_state *sh, const char *arg) {
char path_arg[USH_PATH_MAX];
char abs_path[USH_PATH_MAX];
const char *payload;
const char *payload = (const char *)0;
u64 payload_len;
if (arg == (const char *)0 || arg[0] == '\0') {
@@ -1048,7 +1282,16 @@ static int ush_cmd_append(const ush_state *sh, const char *arg) {
return 0;
}
if (payload == (const char *)0 || payload[0] == '\0') {
if (ush_pipeline_stdin_text == (const char *)0) {
ush_writeln("append: usage append <file> <text>");
return 0;
}
payload = ush_pipeline_stdin_text;
payload_len = ush_pipeline_stdin_len;
} else {
payload_len = ush_strlen(payload);
}
if (cleonos_sys_fs_append(abs_path, payload, payload_len) == 0ULL) {
ush_writeln("append: failed");
@@ -1214,35 +1457,35 @@ static int ush_cmd_not_supported(const char *name, const char *why) {
return 0;
}
void ush_execute_line(ush_state *sh, const char *line) {
char line_buf[USH_LINE_MAX];
char cmd[USH_CMD_MAX];
char arg[USH_ARG_MAX];
u64 i = 0ULL;
static int ush_execute_single_command(ush_state *sh,
const char *cmd,
const char *arg,
int allow_external,
int *out_known,
int *out_success) {
int known = 1;
int success = 0;
if (sh == (ush_state *)0 || line == (const char *)0) {
return;
if (out_known != (int *)0) {
*out_known = 1;
}
while (line[i] != '\0' && i + 1ULL < (u64)sizeof(line_buf)) {
line_buf[i] = line[i];
i++;
if (out_success != (int *)0) {
*out_success = 0;
}
line_buf[i] = '\0';
ush_trim_line(line_buf);
if (line_buf[0] == '\0' || line_buf[0] == '#') {
return;
if (sh == (ush_state *)0 || cmd == (const char *)0 || cmd[0] == '\0') {
if (out_known != (int *)0) {
*out_known = 0;
}
return 0;
}
ush_parse_line(line_buf, cmd, (u64)sizeof(cmd), arg, (u64)sizeof(arg));
ush_trim_line(arg);
if (ush_try_exec_external(sh, cmd, arg, &success) != 0) {
goto finalize_stats;
if (allow_external != 0 && ush_try_exec_external(sh, cmd, arg, &success) != 0) {
if (out_success != (int *)0) {
*out_success = success;
}
return 1;
}
if (ush_streq(cmd, "help") != 0) {
@@ -1251,6 +1494,8 @@ void ush_execute_line(ush_state *sh, const char *line) {
success = ush_cmd_ls(sh, arg);
} else if (ush_streq(cmd, "cat") != 0) {
success = ush_cmd_cat(sh, arg);
} else if (ush_streq(cmd, "grep") != 0) {
success = ush_cmd_grep(sh, arg);
} else if (ush_streq(cmd, "pwd") != 0) {
success = ush_cmd_pwd(sh);
} else if (ush_streq(cmd, "cd") != 0) {
@@ -1319,7 +1564,320 @@ void ush_execute_line(ush_state *sh, const char *line) {
ush_writeln("unknown command; type 'help'");
}
finalize_stats:
if (out_known != (int *)0) {
*out_known = known;
}
if (out_success != (int *)0) {
*out_success = success;
}
return 1;
}
static void ush_pipeline_set_stdin(const char *text, u64 len) {
ush_pipeline_stdin_text = text;
ush_pipeline_stdin_len = len;
}
static int ush_pipeline_has_meta(const char *line) {
u64 i = 0ULL;
if (line == (const char *)0) {
return 0;
}
while (line[i] != '\0') {
if (line[i] == '|' || line[i] == '>') {
return 1;
}
i++;
}
return 0;
}
static int ush_pipeline_parse_stage(ush_pipeline_stage *stage, const char *segment_text) {
char work[USH_LINE_MAX];
char path_part[USH_PATH_MAX];
const char *path_rest = "";
u64 i;
i64 op_pos = -1;
int op_mode = 0;
if (stage == (ush_pipeline_stage *)0 || segment_text == (const char *)0) {
return 0;
}
ush_copy(work, (u64)sizeof(work), segment_text);
ush_trim_line(work);
if (work[0] == '\0') {
return 0;
}
for (i = 0ULL; work[i] != '\0'; i++) {
if (work[i] == '>') {
if (op_pos >= 0) {
ush_writeln("pipe: multiple redirections in one stage are not supported");
return 0;
}
op_pos = (i64)i;
if (work[i + 1ULL] == '>') {
op_mode = 2;
i++;
} else {
op_mode = 1;
}
}
}
stage->redirect_mode = 0;
stage->redirect_path[0] = '\0';
if (op_pos >= 0) {
char *path_src;
work[(u64)op_pos] = '\0';
path_src = &work[(u64)op_pos + ((op_mode == 2) ? 2ULL : 1ULL)];
ush_trim_line(work);
ush_trim_line(path_src);
if (path_src[0] == '\0') {
ush_writeln("pipe: redirection path required");
return 0;
}
if (ush_split_first_and_rest(path_src, path_part, (u64)sizeof(path_part), &path_rest) == 0) {
ush_writeln("pipe: redirection path required");
return 0;
}
if (path_rest != (const char *)0 && path_rest[0] != '\0') {
ush_writeln("pipe: redirection path cannot contain spaces");
return 0;
}
stage->redirect_mode = op_mode;
ush_copy(stage->redirect_path, (u64)sizeof(stage->redirect_path), path_part);
}
ush_copy(stage->text, (u64)sizeof(stage->text), work);
ush_parse_line(work, stage->cmd, (u64)sizeof(stage->cmd), stage->arg, (u64)sizeof(stage->arg));
ush_trim_line(stage->arg);
if (stage->cmd[0] == '\0') {
ush_writeln("pipe: empty command stage");
return 0;
}
return 1;
}
static int ush_pipeline_parse(const char *line,
ush_pipeline_stage *stages,
u64 max_stages,
u64 *out_stage_count) {
char segment[USH_LINE_MAX];
u64 i = 0ULL;
u64 seg_pos = 0ULL;
u64 stage_count = 0ULL;
if (line == (const char *)0 || stages == (ush_pipeline_stage *)0 || max_stages == 0ULL || out_stage_count == (u64 *)0) {
return 0;
}
*out_stage_count = 0ULL;
for (;;) {
char ch = line[i];
if (ch == '|' || ch == '\0') {
segment[seg_pos] = '\0';
if (stage_count >= max_stages) {
ush_writeln("pipe: too many stages");
return 0;
}
if (ush_pipeline_parse_stage(&stages[stage_count], segment) == 0) {
return 0;
}
stage_count++;
seg_pos = 0ULL;
if (ch == '\0') {
break;
}
i++;
continue;
}
if (seg_pos + 1ULL >= (u64)sizeof(segment)) {
ush_writeln("pipe: stage text too long");
return 0;
}
segment[seg_pos++] = ch;
i++;
}
*out_stage_count = stage_count;
return 1;
}
static int ush_pipeline_write_redirect(const ush_state *sh, const ush_pipeline_stage *stage, const char *data, u64 len) {
char abs_path[USH_PATH_MAX];
u64 ok;
if (sh == (const ush_state *)0 || stage == (const ush_pipeline_stage *)0) {
return 0;
}
if (stage->redirect_mode == 0) {
return 1;
}
if (ush_resolve_path(sh, stage->redirect_path, abs_path, (u64)sizeof(abs_path)) == 0) {
ush_writeln("redirect: invalid path");
return 0;
}
if (stage->redirect_mode == 1) {
ok = cleonos_sys_fs_write(abs_path, data, len);
} else {
ok = cleonos_sys_fs_append(abs_path, data, len);
}
if (ok == 0ULL) {
ush_writeln("redirect: write failed");
return 0;
}
return 1;
}
static int ush_execute_pipeline(ush_state *sh,
const char *line,
int *out_known,
int *out_success) {
ush_pipeline_stage stages[USH_PIPELINE_MAX_STAGES];
u64 stage_count = 0ULL;
u64 i;
const char *pipe_in = (const char *)0;
u64 pipe_in_len = 0ULL;
char *capture_out = ush_pipeline_capture_a;
u64 capture_len = 0ULL;
int known = 1;
int success = 1;
if (out_known != (int *)0) {
*out_known = 1;
}
if (out_success != (int *)0) {
*out_success = 0;
}
if (ush_pipeline_parse(line, stages, USH_PIPELINE_MAX_STAGES, &stage_count) == 0) {
return 0;
}
for (i = 0ULL; i < stage_count; i++) {
int stage_known = 1;
int stage_success = 0;
int mirror_to_tty = ((i + 1ULL) == stage_count && stages[i].redirect_mode == 0) ? 1 : 0;
if (i + 1ULL < stage_count && stages[i].redirect_mode != 0) {
ush_writeln("pipe: redirection is only supported on final stage");
known = 1;
success = 0;
break;
}
ush_pipeline_set_stdin(pipe_in, pipe_in_len);
ush_output_capture_begin(capture_out, (u64)USH_PIPE_CAPTURE_MAX + 1ULL, mirror_to_tty);
(void)ush_execute_single_command(sh, stages[i].cmd, stages[i].arg, 0, &stage_known, &stage_success);
capture_len = ush_output_capture_end();
if (ush_output_capture_truncated() != 0) {
ush_writeln("[pipe] captured output truncated");
}
if (stage_known == 0) {
known = 0;
}
if (stage_success == 0) {
success = 0;
break;
}
if (stages[i].redirect_mode != 0) {
if (ush_pipeline_write_redirect(sh, &stages[i], capture_out, capture_len) == 0) {
success = 0;
break;
}
}
pipe_in = capture_out;
pipe_in_len = capture_len;
capture_out = (capture_out == ush_pipeline_capture_a) ? ush_pipeline_capture_b : ush_pipeline_capture_a;
}
ush_pipeline_set_stdin((const char *)0, 0ULL);
if (out_known != (int *)0) {
*out_known = known;
}
if (out_success != (int *)0) {
*out_success = success;
}
return 1;
}
void ush_execute_line(ush_state *sh, const char *line) {
char line_buf[USH_LINE_MAX];
char cmd[USH_CMD_MAX];
char arg[USH_ARG_MAX];
u64 i = 0ULL;
int known = 1;
int success = 0;
if (sh == (ush_state *)0 || line == (const char *)0) {
return;
}
while (line[i] != '\0' && i + 1ULL < (u64)sizeof(line_buf)) {
line_buf[i] = line[i];
i++;
}
line_buf[i] = '\0';
ush_trim_line(line_buf);
if (line_buf[0] == '\0' || line_buf[0] == '#') {
return;
}
if (ush_pipeline_has_meta(line_buf) != 0) {
if (ush_execute_pipeline(sh, line_buf, &known, &success) == 0) {
known = 1;
success = 0;
}
} else {
ush_parse_line(line_buf, cmd, (u64)sizeof(cmd), arg, (u64)sizeof(arg));
ush_trim_line(arg);
(void)ush_execute_single_command(sh, cmd, arg, 1, &known, &success);
}
sh->cmd_total++;
if (success != 0) {
@@ -1332,6 +1890,3 @@ finalize_stats:
sh->cmd_unknown++;
}
}

View File

@@ -85,6 +85,9 @@ void ush_parse_line(const char *line, char *out_cmd, u64 cmd_size, char *out_arg
void ush_write(const char *text);
void ush_write_char(char ch);
void ush_writeln(const char *text);
void ush_output_capture_begin(char *buffer, u64 buffer_size, int mirror_to_tty);
u64 ush_output_capture_end(void);
int ush_output_capture_truncated(void);
void ush_prompt(const ush_state *sh);
void ush_write_hex_u64(u64 value);
void ush_print_kv_hex(const char *label, u64 value);

View File

@@ -219,6 +219,82 @@ void ush_parse_line(const char *line, char *out_cmd, u64 cmd_size, char *out_arg
out_arg[arg_pos] = '\0';
}
static char *ush_out_capture_buffer = (char *)0;
static u64 ush_out_capture_capacity = 0ULL;
static u64 ush_out_capture_length = 0ULL;
static int ush_out_capture_active = 0;
static int ush_out_capture_mirror_tty = 1;
static int ush_out_capture_truncated = 0;
static void ush_output_capture_append(const char *text, u64 len) {
u64 writable;
u64 i;
if (ush_out_capture_active == 0 || text == (const char *)0 || len == 0ULL) {
return;
}
if (ush_out_capture_buffer == (char *)0 || ush_out_capture_capacity == 0ULL) {
ush_out_capture_truncated = 1;
return;
}
if (ush_out_capture_length + 1ULL >= ush_out_capture_capacity) {
ush_out_capture_truncated = 1;
return;
}
writable = (ush_out_capture_capacity - 1ULL) - ush_out_capture_length;
if (len > writable) {
len = writable;
ush_out_capture_truncated = 1;
}
for (i = 0ULL; i < len; i++) {
ush_out_capture_buffer[ush_out_capture_length + i] = text[i];
}
ush_out_capture_length += len;
ush_out_capture_buffer[ush_out_capture_length] = '\0';
}
void ush_output_capture_begin(char *buffer, u64 buffer_size, int mirror_to_tty) {
ush_out_capture_buffer = buffer;
ush_out_capture_capacity = buffer_size;
ush_out_capture_length = 0ULL;
ush_out_capture_active = 1;
ush_out_capture_mirror_tty = (mirror_to_tty != 0) ? 1 : 0;
ush_out_capture_truncated = 0;
if (ush_out_capture_buffer != (char *)0 && ush_out_capture_capacity > 0ULL) {
ush_out_capture_buffer[0] = '\0';
}
}
u64 ush_output_capture_end(void) {
u64 captured = ush_out_capture_length;
if (ush_out_capture_buffer != (char *)0 && ush_out_capture_capacity > 0ULL) {
if (ush_out_capture_length >= ush_out_capture_capacity) {
ush_out_capture_length = ush_out_capture_capacity - 1ULL;
}
ush_out_capture_buffer[ush_out_capture_length] = '\0';
}
ush_out_capture_buffer = (char *)0;
ush_out_capture_capacity = 0ULL;
ush_out_capture_length = 0ULL;
ush_out_capture_active = 0;
ush_out_capture_mirror_tty = 1;
return captured;
}
int ush_output_capture_truncated(void) {
return ush_out_capture_truncated;
}
void ush_write(const char *text) {
u64 len;
@@ -232,10 +308,26 @@ void ush_write(const char *text) {
return;
}
if (ush_out_capture_active != 0) {
ush_output_capture_append(text, len);
if (ush_out_capture_mirror_tty == 0) {
return;
}
}
(void)cleonos_sys_tty_write(text, len);
}
void ush_write_char(char ch) {
if (ush_out_capture_active != 0) {
ush_output_capture_append(&ch, 1ULL);
if (ush_out_capture_mirror_tty == 0) {
return;
}
}
(void)cleonos_sys_tty_write_char(ch);
}