diff --git a/cleonos/c/apps/cat_main.c b/cleonos/c/apps/cat_main.c index 3159ce7..67e7f9d 100644 --- a/cleonos/c/apps/cat_main.c +++ b/cleonos/c/apps/cat_main.c @@ -1,4 +1,6 @@ #include "cmd_runtime.h" +#include + static int ush_cmd_cat(const ush_state *sh, const char *arg) { char path[USH_PATH_MAX]; char buf[USH_CAT_MAX + 1ULL]; @@ -8,28 +10,28 @@ static int ush_cmd_cat(const ush_state *sh, const char *arg) { 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); + (void)fputs(ush_pipeline_stdin_text, 1); return 1; } - ush_writeln("cat: file path required"); + (void)puts("cat: file path required"); return 0; } if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("cat: invalid path"); + (void)puts("cat: invalid path"); return 0; } if (cleonos_sys_fs_stat_type(path) != 1ULL) { - ush_writeln("cat: file not found"); + (void)puts("cat: file not found"); return 0; } size = cleonos_sys_fs_stat_size(path); if (size == (u64)-1) { - ush_writeln("cat: failed to stat file"); + (void)puts("cat: failed to stat file"); return 0; } @@ -41,7 +43,7 @@ static int ush_cmd_cat(const ush_state *sh, const char *arg) { got = cleonos_sys_fs_read(path, buf, req); if (got == 0ULL) { - ush_writeln("cat: read failed"); + (void)puts("cat: read failed"); return 0; } @@ -50,10 +52,10 @@ static int ush_cmd_cat(const ush_state *sh, const char *arg) { } buf[got] = '\0'; - ush_writeln(buf); + (void)puts(buf); if (size > got) { - ush_writeln("[cat] output truncated"); + (void)puts("[cat] output truncated"); } return 1; diff --git a/cleonos/c/apps/cmd_runtime.c b/cleonos/c/apps/cmd_runtime.c index 47d93c2..f2bca2b 100644 --- a/cleonos/c/apps/cmd_runtime.c +++ b/cleonos/c/apps/cmd_runtime.c @@ -4,16 +4,10 @@ const char *ush_pipeline_stdin_text = (const char *)0; u64 ush_pipeline_stdin_len = 0ULL; void ush_zero(void *ptr, u64 size) { - u64 i; - char *bytes = (char *)ptr; - - if (bytes == (char *)0) { + if (ptr == (void *)0 || size == 0ULL) { return; } - - for (i = 0ULL; i < size; i++) { - bytes[i] = 0; - } + (void)memset(ptr, 0, (size_t)size); } void ush_init_state(ush_state *sh) { @@ -27,84 +21,47 @@ void ush_init_state(ush_state *sh) { } u64 ush_strlen(const char *str) { - u64 len = 0ULL; - - if (str == (const char *)0) { - return 0ULL; - } - - while (str[len] != '\0') { - len++; - } - - return len; + return (str == (const char *)0) ? 0ULL : (u64)strlen(str); } int ush_streq(const char *left, const char *right) { - u64 i = 0ULL; - if (left == (const char *)0 || right == (const char *)0) { return 0; } - - while (left[i] != '\0' && right[i] != '\0') { - if (left[i] != right[i]) { - return 0; - } - i++; - } - - return (left[i] == right[i]) ? 1 : 0; + return (strcmp(left, right) == 0) ? 1 : 0; } int ush_is_space(char ch) { - return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') ? 1 : 0; + return (isspace((unsigned char)ch) != 0) ? 1 : 0; } int ush_is_printable(char ch) { - return (ch >= 32 && ch <= 126) ? 1 : 0; + return (isprint((unsigned char)ch) != 0) ? 1 : 0; } int ush_has_suffix(const char *name, const char *suffix) { - u64 name_len; - u64 suffix_len; - u64 i; + size_t name_len; + size_t suffix_len; if (name == (const char *)0 || suffix == (const char *)0) { return 0; } - name_len = ush_strlen(name); - suffix_len = ush_strlen(suffix); + name_len = strlen(name); + suffix_len = strlen(suffix); if (suffix_len > name_len) { return 0; } - for (i = 0ULL; i < suffix_len; i++) { - if (name[name_len - suffix_len + i] != suffix[i]) { - return 0; - } - } - - return 1; + return (strncmp(name + (name_len - suffix_len), suffix, suffix_len) == 0) ? 1 : 0; } int ush_contains_char(const char *text, char needle) { - u64 i = 0ULL; - if (text == (const char *)0) { return 0; } - - while (text[i] != '\0') { - if (text[i] == needle) { - return 1; - } - i++; - } - - return 0; + return (strchr(text, (int)needle) != (char *)0) ? 1 : 0; } int ush_parse_u64_dec(const char *text, u64 *out_value) { @@ -118,7 +75,7 @@ int ush_parse_u64_dec(const char *text, u64 *out_value) { while (text[i] != '\0') { u64 digit; - if (text[i] < '0' || text[i] > '9') { + if (isdigit((unsigned char)text[i]) == 0) { return 0; } @@ -137,45 +94,34 @@ int ush_parse_u64_dec(const char *text, u64 *out_value) { } void ush_copy(char *dst, u64 dst_size, const char *src) { - u64 i = 0ULL; - if (dst == (char *)0 || src == (const char *)0 || dst_size == 0ULL) { return; } - - while (src[i] != '\0' && i + 1ULL < dst_size) { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; + (void)strncpy(dst, src, (size_t)(dst_size - 1ULL)); + dst[dst_size - 1ULL] = '\0'; } void ush_trim_line(char *line) { - u64 start = 0ULL; - u64 i = 0ULL; - u64 len; + size_t start = 0U; + size_t len; if (line == (char *)0) { return; } - while (line[start] != '\0' && ush_is_space(line[start]) != 0) { + while (line[start] != '\0' && isspace((unsigned char)line[start]) != 0) { start++; } - if (start > 0ULL) { - while (line[start + i] != '\0') { - line[i] = line[start + i]; - i++; - } - line[i] = '\0'; + if (start > 0U) { + size_t remain = strlen(line + start) + 1U; + (void)memmove(line, line + start, remain); } - len = ush_strlen(line); + len = strlen(line); - while (len > 0ULL && ush_is_space(line[len - 1ULL]) != 0) { - line[len - 1ULL] = '\0'; + while (len > 0U && isspace((unsigned char)line[len - 1U]) != 0) { + line[len - 1U] = '\0'; len--; } } @@ -220,37 +166,14 @@ void ush_parse_line(const char *line, char *out_cmd, u64 cmd_size, char *out_arg } void ush_write(const char *text) { - u64 len; - const char *cursor; - u64 left; - if (text == (const char *)0) { return; } - - len = ush_strlen(text); - - if (len == 0ULL) { - return; - } - - cursor = text; - left = len; - - while (left > 0ULL) { - u64 wrote = cleonos_sys_fd_write(1ULL, cursor, left); - - if (wrote == 0ULL || wrote == (u64)-1) { - break; - } - - cursor += wrote; - left -= wrote; - } + (void)fputs(text, 1); } void ush_write_char(char ch) { - (void)cleonos_sys_fd_write(1ULL, &ch, 1ULL); + (void)fputc((int)(unsigned char)ch, 1); } void ush_writeln(const char *text) { @@ -470,11 +393,9 @@ int ush_path_is_under_system(const char *path) { if (path == (const char *)0) { return 0; } - - if (path[0] != '/' || path[1] != 's' || path[2] != 'y' || path[3] != 's' || path[4] != 't' || path[5] != 'e' || path[6] != 'm') { + if (strncmp(path, "/system", 7U) != 0) { return 0; } - return (path[7] == '\0' || path[7] == '/') ? 1 : 0; } @@ -482,11 +403,9 @@ int ush_path_is_under_temp(const char *path) { if (path == (const char *)0) { return 0; } - - if (path[0] != '/' || path[1] != 't' || path[2] != 'e' || path[3] != 'm' || path[4] != 'p') { + if (strncmp(path, "/temp", 5U) != 0) { return 0; } - return (path[5] == '\0' || path[5] == '/') ? 1 : 0; } diff --git a/cleonos/c/apps/cmd_runtime.h b/cleonos/c/apps/cmd_runtime.h index 06005ab..daa3f97 100644 --- a/cleonos/c/apps/cmd_runtime.h +++ b/cleonos/c/apps/cmd_runtime.h @@ -2,6 +2,10 @@ #define CLEONOS_CMD_RUNTIME_H #include +#include +#include +#include +#include typedef long long i64; diff --git a/cleonos/c/apps/grep_main.c b/cleonos/c/apps/grep_main.c index 8a9d785..1afbd86 100644 --- a/cleonos/c/apps/grep_main.c +++ b/cleonos/c/apps/grep_main.c @@ -1,10 +1,12 @@ #include "cmd_runtime.h" +#include + static void ush_grep_write_u64_dec(u64 value) { char tmp[32]; u64 len = 0ULL; if (value == 0ULL) { - ush_write_char('0'); + (void)putchar('0'); return; } @@ -15,7 +17,7 @@ static void ush_grep_write_u64_dec(u64 value) { while (len > 0ULL) { len--; - ush_write_char(tmp[len]); + (void)putchar((unsigned char)tmp[len]); } } @@ -73,14 +75,14 @@ static u64 ush_grep_emit_matches(const char *input, u64 input_len, const char *p if (with_line_number != 0) { ush_grep_write_u64_dec(line_no); - ush_write(":"); + (void)fputs(":", 1); } for (j = 0ULL; j < line_len; j++) { - ush_write_char(input[start + j]); + (void)putchar((unsigned char)input[start + j]); } - ush_write_char('\n'); + (void)putchar('\n'); } start = i + 1ULL; @@ -108,12 +110,12 @@ static int ush_cmd_grep(const ush_state *sh, const char *arg) { 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] [file]"); + (void)puts("grep: usage grep [-n] [file]"); return 0; } if (ush_split_first_and_rest(arg, first, (u64)sizeof(first), &rest) == 0) { - ush_writeln("grep: usage grep [-n] [file]"); + (void)puts("grep: usage grep [-n] [file]"); return 0; } @@ -121,7 +123,7 @@ static int ush_cmd_grep(const ush_state *sh, const char *arg) { with_line_number = 1; if (ush_split_first_and_rest(rest, second, (u64)sizeof(second), &rest2) == 0) { - ush_writeln("grep: usage grep [-n] [file]"); + (void)puts("grep: usage grep [-n] [file]"); return 0; } @@ -133,43 +135,43 @@ static int ush_cmd_grep(const ush_state *sh, const char *arg) { 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] [file]"); + (void)puts("grep: usage grep [-n] [file]"); return 0; } file_arg = third; if (rest2 != (const char *)0 && rest2[0] != '\0') { - ush_writeln("grep: usage grep [-n] [file]"); + (void)puts("grep: usage grep [-n] [file]"); return 0; } } if (pattern == (const char *)0 || pattern[0] == '\0') { - ush_writeln("grep: pattern required"); + (void)puts("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"); + (void)puts("grep: invalid path"); return 0; } if (cleonos_sys_fs_stat_type(path) != 1ULL) { - ush_writeln("grep: file not found"); + (void)puts("grep: file not found"); return 0; } size = cleonos_sys_fs_stat_size(path); if (size == (u64)-1) { - ush_writeln("grep: failed to stat file"); + (void)puts("grep: failed to stat file"); return 0; } if (size > (u64)USH_COPY_MAX) { - ush_writeln("grep: file too large for user buffer"); + (void)puts("grep: file too large for user buffer"); return 0; } @@ -180,7 +182,7 @@ static int ush_cmd_grep(const ush_state *sh, const char *arg) { got = cleonos_sys_fs_read(path, file_buf, size); if (got == 0ULL || got != size) { - ush_writeln("grep: read failed"); + (void)puts("grep: read failed"); return 0; } @@ -189,7 +191,7 @@ static int ush_cmd_grep(const ush_state *sh, const char *arg) { input_len = got; } else { if (ush_pipeline_stdin_text == (const char *)0) { - ush_writeln("grep: file path required (or pipeline input)"); + (void)puts("grep: file path required (or pipeline input)"); return 0; } diff --git a/cleonos/c/apps/head_main.c b/cleonos/c/apps/head_main.c index f231fbe..d0e0450 100644 --- a/cleonos/c/apps/head_main.c +++ b/cleonos/c/apps/head_main.c @@ -1,4 +1,5 @@ #include "cmd_runtime.h" +#include static int ush_head_parse_args(const char *arg, u64 *out_line_count, char *out_file, u64 out_file_size) { char first[USH_PATH_MAX]; @@ -69,24 +70,24 @@ static int ush_head_load_input(const ush_state *sh, const char *file_arg, const if (file_arg != (const char *)0 && file_arg[0] != '\0') { if (ush_resolve_path(sh, file_arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("head: invalid path"); + (void)puts("head: invalid path"); return 0; } if (cleonos_sys_fs_stat_type(path) != 1ULL) { - ush_writeln("head: file not found"); + (void)puts("head: file not found"); return 0; } size = cleonos_sys_fs_stat_size(path); if (size == (u64)-1) { - ush_writeln("head: failed to stat file"); + (void)puts("head: failed to stat file"); return 0; } if (size > (u64)USH_COPY_MAX) { - ush_writeln("head: file too large for user buffer"); + (void)puts("head: file too large for user buffer"); return 0; } @@ -100,7 +101,7 @@ static int ush_head_load_input(const ush_state *sh, const char *file_arg, const got = cleonos_sys_fs_read(path, file_buf, size); if (got == 0ULL || got != size) { - ush_writeln("head: read failed"); + (void)puts("head: read failed"); return 0; } @@ -111,7 +112,7 @@ static int ush_head_load_input(const ush_state *sh, const char *file_arg, const } if (ush_pipeline_stdin_text == (const char *)0) { - ush_writeln("head: file path required (or pipeline input)"); + (void)puts("head: file path required (or pipeline input)"); return 0; } @@ -133,7 +134,7 @@ static void ush_head_emit(const char *input, u64 input_len, u64 line_count) { break; } - ush_write_char(input[i]); + (void)putchar((unsigned char)input[i]); if (input[i] == '\n') { emitted++; @@ -152,7 +153,7 @@ static int ush_cmd_head(const ush_state *sh, const char *arg) { } if (ush_head_parse_args(arg, &line_count, file_arg, (u64)sizeof(file_arg)) == 0) { - ush_writeln("head: usage head [-n N] [file]"); + (void)puts("head: usage head [-n N] [file]"); return 0; } diff --git a/cleonos/c/apps/hello_main.c b/cleonos/c/apps/hello_main.c index 405f9c8..3a304c2 100644 --- a/cleonos/c/apps/hello_main.c +++ b/cleonos/c/apps/hello_main.c @@ -1,7 +1,6 @@ -#include +#include int cleonos_app_main(void) { - static const char msg[] = "[USER][HELLO] Hello world from /hello.elf\n"; - (void)cleonos_sys_fd_write(1ULL, msg, (u64)(sizeof(msg) - 1U)); + (void)printf("[USER][HELLO] Hello world from %s\n", "/hello.elf"); return 0; } diff --git a/cleonos/c/apps/ls_main.c b/cleonos/c/apps/ls_main.c index 9bcb465..71744c7 100644 --- a/cleonos/c/apps/ls_main.c +++ b/cleonos/c/apps/ls_main.c @@ -1,4 +1,23 @@ #include "cmd_runtime.h" +#include + +static void clio_write(const char *text) { + (void)fputs(text, 1); +} + +static void clio_writeln(const char *text) { + (void)fputs(text, 1); + (void)putchar('\n'); +} + +static void clio_write_char(char ch) { + (void)putchar((unsigned char)ch); +} + +static void clio_write_hex_u64(u64 value) { + (void)printf("0X%llX", (unsigned long long)value); +} + static int ush_ls_join_path(const char *dir_path, const char *name, char *out_path, u64 out_size) { u64 p = 0ULL; u64 i; @@ -80,30 +99,30 @@ static int ush_ls_is_dot_entry(const char *name) { static void ush_ls_print_one(const char *name, u64 type, u64 size, int long_mode) { if (long_mode == 0) { - ush_writeln(name); + clio_writeln(name); return; } if (type == 2ULL) { - ush_write("d "); + clio_write("d "); } else if (type == 1ULL) { - ush_write("f "); + clio_write("f "); } else { - ush_write("? "); + clio_write("? "); } - ush_write(name); + clio_write(name); if (type == 1ULL) { - ush_write(" size="); - ush_write_hex_u64(size); + clio_write(" size="); + clio_write_hex_u64(size); } else if (type == 2ULL) { - ush_write(" "); + clio_write(" "); } else { - ush_write(" "); + clio_write(" "); } - ush_write_char('\n'); + clio_write_char('\n'); } static int ush_ls_parse_args(const char *arg, @@ -186,19 +205,19 @@ static int ush_ls_dir(const char *path, u64 i; if (depth > 16ULL) { - ush_writeln("ls: recursion depth limit reached"); + clio_writeln("ls: recursion depth limit reached"); return 0; } count = cleonos_sys_fs_child_count(path); if (print_header != 0) { - ush_write(path); - ush_writeln(":"); + clio_write(path); + clio_writeln(":"); } if (count == 0ULL) { - ush_writeln("(empty)"); + clio_writeln("(empty)"); } for (i = 0ULL; i < count; i++) { @@ -249,7 +268,7 @@ static int ush_ls_dir(const char *path, } if (cleonos_sys_fs_stat_type(child_path) == 2ULL) { - ush_write_char('\n'); + clio_write_char('\n'); (void)ush_ls_dir(child_path, long_mode, recursive, 1, depth + 1ULL); } } @@ -265,12 +284,12 @@ static int ush_cmd_ls(const ush_state *sh, const char *arg) { int recursive; if (ush_ls_parse_args(arg, &long_mode, &recursive, target, (u64)sizeof(target)) == 0) { - ush_writeln("ls: usage ls [-l] [-R] [path]"); + clio_writeln("ls: usage ls [-l] [-R] [path]"); return 0; } if (ush_resolve_path(sh, target, path, (u64)sizeof(path)) == 0) { - ush_writeln("ls: invalid path"); + clio_writeln("ls: invalid path"); return 0; } @@ -283,7 +302,7 @@ static int ush_cmd_ls(const ush_state *sh, const char *arg) { } if (type != 2ULL) { - ush_writeln("ls: path not found"); + clio_writeln("ls: path not found"); return 0; } diff --git a/cleonos/c/apps/shell/shell_internal.h b/cleonos/c/apps/shell/shell_internal.h index 1b3ac05..d2593ba 100644 --- a/cleonos/c/apps/shell/shell_internal.h +++ b/cleonos/c/apps/shell/shell_internal.h @@ -2,6 +2,10 @@ #define CLEONOS_USER_SHELL_INTERNAL_H #include +#include +#include +#include +#include typedef long long i64; diff --git a/cleonos/c/apps/shell/shell_util.c b/cleonos/c/apps/shell/shell_util.c index 1e28bb6..86e2b0a 100644 --- a/cleonos/c/apps/shell/shell_util.c +++ b/cleonos/c/apps/shell/shell_util.c @@ -5,106 +5,53 @@ void ush_init_state(ush_state *sh) { return; } - sh->line[0] = '\0'; - sh->line_len = 0ULL; - sh->cursor = 0ULL; - sh->rendered_len = 0ULL; + (void)memset(sh, 0, sizeof(*sh)); ush_copy(sh->cwd, (u64)sizeof(sh->cwd), "/"); - - sh->history_count = 0ULL; sh->history_nav = -1; - sh->nav_saved_line[0] = '\0'; - sh->nav_saved_len = 0ULL; - sh->nav_saved_cursor = 0ULL; - - sh->cmd_total = 0ULL; - sh->cmd_ok = 0ULL; - sh->cmd_fail = 0ULL; - sh->cmd_unknown = 0ULL; - sh->exit_requested = 0; - sh->exit_code = 0ULL; } u64 ush_strlen(const char *str) { - u64 len = 0ULL; - - if (str == (const char *)0) { - return 0ULL; - } - - while (str[len] != '\0') { - len++; - } - - return len; + return (str == (const char *)0) ? 0ULL : (u64)strlen(str); } int ush_streq(const char *left, const char *right) { - u64 i = 0ULL; - if (left == (const char *)0 || right == (const char *)0) { return 0; } - - while (left[i] != '\0' && right[i] != '\0') { - if (left[i] != right[i]) { - return 0; - } - i++; - } - - return (left[i] == right[i]) ? 1 : 0; + return (strcmp(left, right) == 0) ? 1 : 0; } int ush_is_space(char ch) { - return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') ? 1 : 0; + return (isspace((unsigned char)ch) != 0) ? 1 : 0; } int ush_is_printable(char ch) { - return (ch >= 32 && ch <= 126) ? 1 : 0; + return (isprint((unsigned char)ch) != 0) ? 1 : 0; } int ush_has_suffix(const char *name, const char *suffix) { - u64 name_len; - u64 suffix_len; - u64 i; + size_t name_len; + size_t suffix_len; if (name == (const char *)0 || suffix == (const char *)0) { return 0; } - name_len = ush_strlen(name); - suffix_len = ush_strlen(suffix); + name_len = strlen(name); + suffix_len = strlen(suffix); if (suffix_len > name_len) { return 0; } - - for (i = 0ULL; i < suffix_len; i++) { - if (name[name_len - suffix_len + i] != suffix[i]) { - return 0; - } - } - - return 1; + return (strncmp(name + (name_len - suffix_len), suffix, suffix_len) == 0) ? 1 : 0; } int ush_contains_char(const char *text, char needle) { - u64 i = 0ULL; - if (text == (const char *)0) { return 0; } - - while (text[i] != '\0') { - if (text[i] == needle) { - return 1; - } - i++; - } - - return 0; + return (strchr(text, (int)needle) != (char *)0) ? 1 : 0; } int ush_parse_u64_dec(const char *text, u64 *out_value) { @@ -118,7 +65,7 @@ int ush_parse_u64_dec(const char *text, u64 *out_value) { while (text[i] != '\0') { u64 digit; - if (text[i] < '0' || text[i] > '9') { + if (isdigit((unsigned char)text[i]) == 0) { return 0; } @@ -137,45 +84,34 @@ int ush_parse_u64_dec(const char *text, u64 *out_value) { } void ush_copy(char *dst, u64 dst_size, const char *src) { - u64 i = 0ULL; - if (dst == (char *)0 || src == (const char *)0 || dst_size == 0ULL) { return; } - - while (src[i] != '\0' && i + 1ULL < dst_size) { - dst[i] = src[i]; - i++; - } - - dst[i] = '\0'; + (void)strncpy(dst, src, (size_t)(dst_size - 1ULL)); + dst[dst_size - 1ULL] = '\0'; } void ush_trim_line(char *line) { - u64 start = 0ULL; - u64 i = 0ULL; - u64 len; + size_t start = 0U; + size_t len; if (line == (char *)0) { return; } - while (line[start] != '\0' && ush_is_space(line[start]) != 0) { + while (line[start] != '\0' && isspace((unsigned char)line[start]) != 0) { start++; } - if (start > 0ULL) { - while (line[start + i] != '\0') { - line[i] = line[start + i]; - i++; - } - line[i] = '\0'; + if (start > 0U) { + size_t remain = strlen(line + start) + 1U; + (void)memmove(line, line + start, remain); } - len = ush_strlen(line); + len = strlen(line); - while (len > 0ULL && ush_is_space(line[len - 1ULL]) != 0) { - line[len - 1ULL] = '\0'; + while (len > 0U && isspace((unsigned char)line[len - 1U]) != 0) { + line[len - 1U] = '\0'; len--; } } @@ -231,7 +167,6 @@ static int ush_out_fd_mirror_tty = 1; 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; @@ -254,9 +189,7 @@ static void ush_output_capture_append(const char *text, u64 len) { ush_out_capture_truncated = 1; } - for (i = 0ULL; i < len; i++) { - ush_out_capture_buffer[ush_out_capture_length + i] = text[i]; - } + (void)memcpy(ush_out_capture_buffer + ush_out_capture_length, text, (size_t)len); ush_out_capture_length += len; ush_out_capture_buffer[ush_out_capture_length] = '\0'; @@ -341,19 +274,7 @@ void ush_write(const char *text) { } if (should_write_tty != 0) { - const char *cursor = text; - u64 left = len; - - while (left > 0ULL) { - u64 wrote = cleonos_sys_fd_write(1ULL, cursor, left); - - if (wrote == 0ULL || wrote == (u64)-1) { - break; - } - - cursor += wrote; - left -= wrote; - } + (void)fputs(text, 1); } } @@ -377,7 +298,7 @@ void ush_write_char(char ch) { } if (should_write_tty != 0) { - (void)cleonos_sys_fd_write(1ULL, &ch, 1ULL); + (void)fputc((int)(unsigned char)ch, 1); } } diff --git a/cleonos/c/apps/spin_main.c b/cleonos/c/apps/spin_main.c index 416bb7f..c7060b6 100644 --- a/cleonos/c/apps/spin_main.c +++ b/cleonos/c/apps/spin_main.c @@ -1,11 +1,11 @@ -#include +#include int cleonos_app_main(void) { static const char banner[] = "spin: busy loop started (test Alt+Ctrl+C force stop)\n"; - volatile u64 noise = 0xC1E0C1E0ULL; + volatile unsigned long long noise = 0xC1E0C1E0ULL; - (void)cleonos_sys_fd_write(1ULL, banner, (u64)(sizeof(banner) - 1U)); + (void)fputs(banner, 1); for (;;) { noise ^= (noise << 7); diff --git a/cleonos/c/apps/tail_main.c b/cleonos/c/apps/tail_main.c index 2073035..43957d2 100644 --- a/cleonos/c/apps/tail_main.c +++ b/cleonos/c/apps/tail_main.c @@ -1,4 +1,5 @@ #include "cmd_runtime.h" +#include static int ush_tail_parse_args(const char *arg, u64 *out_line_count, char *out_file, u64 out_file_size) { char first[USH_PATH_MAX]; @@ -69,24 +70,24 @@ static int ush_tail_load_input(const ush_state *sh, const char *file_arg, const if (file_arg != (const char *)0 && file_arg[0] != '\0') { if (ush_resolve_path(sh, file_arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("tail: invalid path"); + (void)puts("tail: invalid path"); return 0; } if (cleonos_sys_fs_stat_type(path) != 1ULL) { - ush_writeln("tail: file not found"); + (void)puts("tail: file not found"); return 0; } size = cleonos_sys_fs_stat_size(path); if (size == (u64)-1) { - ush_writeln("tail: failed to stat file"); + (void)puts("tail: failed to stat file"); return 0; } if (size > (u64)USH_COPY_MAX) { - ush_writeln("tail: file too large for user buffer"); + (void)puts("tail: file too large for user buffer"); return 0; } @@ -100,7 +101,7 @@ static int ush_tail_load_input(const ush_state *sh, const char *file_arg, const got = cleonos_sys_fs_read(path, file_buf, size); if (got == 0ULL || got != size) { - ush_writeln("tail: read failed"); + (void)puts("tail: read failed"); return 0; } @@ -111,7 +112,7 @@ static int ush_tail_load_input(const ush_state *sh, const char *file_arg, const } if (ush_pipeline_stdin_text == (const char *)0) { - ush_writeln("tail: file path required (or pipeline input)"); + (void)puts("tail: file path required (or pipeline input)"); return 0; } @@ -174,7 +175,7 @@ static int ush_cmd_tail(const ush_state *sh, const char *arg) { } if (ush_tail_parse_args(arg, &line_count, file_arg, (u64)sizeof(file_arg)) == 0) { - ush_writeln("tail: usage tail [-n N] [file]"); + (void)puts("tail: usage tail [-n N] [file]"); return 0; } @@ -191,7 +192,7 @@ static int ush_cmd_tail(const ush_state *sh, const char *arg) { start_offset = ush_tail_find_start_offset(input, input_len, skip_lines); for (i = start_offset; i < input_len; i++) { - ush_write_char(input[i]); + (void)putchar((unsigned char)input[i]); } return 1; diff --git a/cleonos/c/apps/wc_main.c b/cleonos/c/apps/wc_main.c index 88ac4bd..9f962c0 100644 --- a/cleonos/c/apps/wc_main.c +++ b/cleonos/c/apps/wc_main.c @@ -1,11 +1,12 @@ #include "cmd_runtime.h" +#include static void ush_wc_write_u64_dec(u64 value) { char tmp[32]; u64 len = 0ULL; if (value == 0ULL) { - ush_write_char('0'); + (void)putchar('0'); return; } @@ -16,7 +17,7 @@ static void ush_wc_write_u64_dec(u64 value) { while (len > 0ULL) { len--; - ush_write_char(tmp[len]); + (void)putchar((unsigned char)tmp[len]); } } @@ -61,24 +62,24 @@ static int ush_wc_load_input(const ush_state *sh, const char *file_arg, const ch if (file_arg != (const char *)0 && file_arg[0] != '\0') { if (ush_resolve_path(sh, file_arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("wc: invalid path"); + (void)puts("wc: invalid path"); return 0; } if (cleonos_sys_fs_stat_type(path) != 1ULL) { - ush_writeln("wc: file not found"); + (void)puts("wc: file not found"); return 0; } size = cleonos_sys_fs_stat_size(path); if (size == (u64)-1) { - ush_writeln("wc: failed to stat file"); + (void)puts("wc: failed to stat file"); return 0; } if (size > (u64)USH_COPY_MAX) { - ush_writeln("wc: file too large for user buffer"); + (void)puts("wc: file too large for user buffer"); return 0; } @@ -92,7 +93,7 @@ static int ush_wc_load_input(const ush_state *sh, const char *file_arg, const ch got = cleonos_sys_fs_read(path, file_buf, size); if (got == 0ULL || got != size) { - ush_writeln("wc: read failed"); + (void)puts("wc: read failed"); return 0; } @@ -103,7 +104,7 @@ static int ush_wc_load_input(const ush_state *sh, const char *file_arg, const ch } if (ush_pipeline_stdin_text == (const char *)0) { - ush_writeln("wc: file path required (or pipeline input)"); + (void)puts("wc: file path required (or pipeline input)"); return 0; } @@ -127,7 +128,7 @@ static int ush_cmd_wc(const ush_state *sh, const char *arg) { } if (ush_wc_parse_args(arg, file_arg, (u64)sizeof(file_arg)) == 0) { - ush_writeln("wc: usage wc [file]"); + (void)puts("wc: usage wc [file]"); return 0; } @@ -153,11 +154,11 @@ static int ush_cmd_wc(const ush_state *sh, const char *arg) { } ush_wc_write_u64_dec(lines); - ush_write(" "); + (void)putchar(' '); ush_wc_write_u64_dec(words); - ush_write(" "); + (void)putchar(' '); ush_wc_write_u64_dec(bytes); - ush_write_char('\n'); + (void)putchar('\n'); return 1; } diff --git a/cleonos/c/include/cleonos_stdio.h b/cleonos/c/include/cleonos_stdio.h new file mode 100644 index 0000000..be99024 --- /dev/null +++ b/cleonos/c/include/cleonos_stdio.h @@ -0,0 +1,6 @@ +#ifndef CLEONOS_STDIO_H +#define CLEONOS_STDIO_H + +#include + +#endif diff --git a/cleonos/c/include/ctype.h b/cleonos/c/include/ctype.h new file mode 100644 index 0000000..93d9f74 --- /dev/null +++ b/cleonos/c/include/ctype.h @@ -0,0 +1,16 @@ +#ifndef CLEONOS_LIBC_CTYPE_H +#define CLEONOS_LIBC_CTYPE_H + +int isspace(int ch); +int isdigit(int ch); +int isalpha(int ch); +int isalnum(int ch); +int isxdigit(int ch); +int isupper(int ch); +int islower(int ch); +int isprint(int ch); +int iscntrl(int ch); +int tolower(int ch); +int toupper(int ch); + +#endif diff --git a/cleonos/c/include/stdio.h b/cleonos/c/include/stdio.h new file mode 100644 index 0000000..7738b8b --- /dev/null +++ b/cleonos/c/include/stdio.h @@ -0,0 +1,27 @@ +#ifndef CLEONOS_LIBC_STDIO_H +#define CLEONOS_LIBC_STDIO_H + +#include + +#ifndef EOF +#define EOF (-1) +#endif + +int putchar(int ch); +int getchar(void); +int fputc(int ch, int fd); +int fgetc(int fd); +int fputs(const char *text, int fd); +int puts(const char *text); + +int vsnprintf(char *out, unsigned long out_size, const char *fmt, va_list args); +int snprintf(char *out, unsigned long out_size, const char *fmt, ...); + +int vdprintf(int fd, const char *fmt, va_list args); +int dprintf(int fd, const char *fmt, ...); +int vfprintf(int fd, const char *fmt, va_list args); +int fprintf(int fd, const char *fmt, ...); +int vprintf(const char *fmt, va_list args); +int printf(const char *fmt, ...); + +#endif diff --git a/cleonos/c/include/stdlib.h b/cleonos/c/include/stdlib.h new file mode 100644 index 0000000..6c6d30e --- /dev/null +++ b/cleonos/c/include/stdlib.h @@ -0,0 +1,36 @@ +#ifndef CLEONOS_LIBC_STDLIB_H +#define CLEONOS_LIBC_STDLIB_H + +#include + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif + +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif + +#ifndef RAND_MAX +#define RAND_MAX 32767 +#endif + +int abs(int value); +long labs(long value); +long long llabs(long long value); + +int atoi(const char *text); +long atol(const char *text); +long long atoll(const char *text); +long strtol(const char *text, char **out_end, int base); +unsigned long strtoul(const char *text, char **out_end, int base); +long long strtoll(const char *text, char **out_end, int base); +unsigned long long strtoull(const char *text, char **out_end, int base); + +void srand(unsigned int seed); +int rand(void); + +void exit(int status); +void abort(void); + +#endif diff --git a/cleonos/c/include/string.h b/cleonos/c/include/string.h new file mode 100644 index 0000000..fb4dc38 --- /dev/null +++ b/cleonos/c/include/string.h @@ -0,0 +1,29 @@ +#ifndef CLEONOS_LIBC_STRING_H +#define CLEONOS_LIBC_STRING_H + +#include + +void *memset(void *dst, int value, size_t size); +void *memcpy(void *dst, const void *src, size_t size); +void *memmove(void *dst, const void *src, size_t size); +int memcmp(const void *left, const void *right, size_t size); +void *memchr(const void *src, int value, size_t size); + +size_t strlen(const char *text); +size_t strnlen(const char *text, size_t max_size); +char *strcpy(char *dst, const char *src); +char *strncpy(char *dst, const char *src, size_t size); +int strcmp(const char *left, const char *right); +int strncmp(const char *left, const char *right, size_t size); +char *strchr(const char *text, int ch); +char *strrchr(const char *text, int ch); +char *strstr(const char *haystack, const char *needle); +size_t strspn(const char *text, const char *accept); +size_t strcspn(const char *text, const char *reject); +char *strpbrk(const char *text, const char *accept); +char *strtok_r(char *text, const char *delim, char **saveptr); +char *strtok(char *text, const char *delim); +char *strcat(char *dst, const char *src); +char *strncat(char *dst, const char *src, size_t size); + +#endif diff --git a/cleonos/c/src/libc_ctype.c b/cleonos/c/src/libc_ctype.c new file mode 100644 index 0000000..de5a8b7 --- /dev/null +++ b/cleonos/c/src/libc_ctype.c @@ -0,0 +1,45 @@ +#include + +int isspace(int ch) { + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\v' || ch == '\f') ? 1 : 0; +} + +int isdigit(int ch) { + return (ch >= '0' && ch <= '9') ? 1 : 0; +} + +int isalpha(int ch) { + return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) ? 1 : 0; +} + +int isalnum(int ch) { + return (isalpha(ch) != 0 || isdigit(ch) != 0) ? 1 : 0; +} + +int isxdigit(int ch) { + return (isdigit(ch) != 0 || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) ? 1 : 0; +} + +int isupper(int ch) { + return (ch >= 'A' && ch <= 'Z') ? 1 : 0; +} + +int islower(int ch) { + return (ch >= 'a' && ch <= 'z') ? 1 : 0; +} + +int isprint(int ch) { + return (ch >= 0x20 && ch <= 0x7E) ? 1 : 0; +} + +int iscntrl(int ch) { + return (ch >= 0x00 && ch <= 0x1F) || ch == 0x7F ? 1 : 0; +} + +int tolower(int ch) { + return (isupper(ch) != 0) ? (ch - 'A' + 'a') : ch; +} + +int toupper(int ch) { + return (islower(ch) != 0) ? (ch - 'a' + 'A') : ch; +} diff --git a/cleonos/c/src/libc_stdlib.c b/cleonos/c/src/libc_stdlib.c new file mode 100644 index 0000000..1cc96cb --- /dev/null +++ b/cleonos/c/src/libc_stdlib.c @@ -0,0 +1,254 @@ +#include + +#include +#include + +#include + +static int clib_digit_value(int ch) { + if (ch >= '0' && ch <= '9') { + return ch - '0'; + } + + if (ch >= 'a' && ch <= 'z') { + return 10 + (ch - 'a'); + } + + if (ch >= 'A' && ch <= 'Z') { + return 10 + (ch - 'A'); + } + + return -1; +} + +static const char *clib_skip_space(const char *text) { + const char *p = text; + + if (p == (const char *)0) { + return (const char *)0; + } + + while (*p != '\0' && isspace((unsigned char)*p) != 0) { + p++; + } + + return p; +} + +int abs(int value) { + return (value < 0) ? -value : value; +} + +long labs(long value) { + return (value < 0L) ? -value : value; +} + +long long llabs(long long value) { + return (value < 0LL) ? -value : value; +} + +int atoi(const char *text) { + return (int)strtol(text, (char **)0, 10); +} + +long atol(const char *text) { + return strtol(text, (char **)0, 10); +} + +long long atoll(const char *text) { + return strtoll(text, (char **)0, 10); +} + +unsigned long strtoul(const char *text, char **out_end, int base) { + const char *p = clib_skip_space(text); + int negative = 0; + unsigned long value = 0UL; + int any = 0; + int overflow = 0; + + if (out_end != (char **)0) { + *out_end = (char *)text; + } + + if (p == (const char *)0) { + return 0UL; + } + + if (*p == '+' || *p == '-') { + negative = (*p == '-') ? 1 : 0; + p++; + } + + if (base == 0) { + if (p[0] == '0') { + if ((p[1] == 'x' || p[1] == 'X') && isxdigit((unsigned char)p[2]) != 0) { + base = 16; + p += 2; + } else { + base = 8; + } + } else { + base = 10; + } + } else if (base == 16) { + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + } + } + + if (base < 2 || base > 36) { + return 0UL; + } + + while (*p != '\0') { + int digit = clib_digit_value((unsigned char)*p); + + if (digit < 0 || digit >= base) { + break; + } + + any = 1; + + if (value > (ULONG_MAX - (unsigned long)digit) / (unsigned long)base) { + overflow = 1; + value = ULONG_MAX; + } else if (overflow == 0) { + value = value * (unsigned long)base + (unsigned long)digit; + } + + p++; + } + + if (any == 0) { + return 0UL; + } + + if (out_end != (char **)0) { + *out_end = (char *)p; + } + + if (negative != 0) { + return (unsigned long)(0UL - value); + } + + return value; +} + +long strtol(const char *text, char **out_end, int base) { + const char *p = clib_skip_space(text); + int negative = 0; + unsigned long long value = 0ULL; + unsigned long long limit; + int any = 0; + int overflow = 0; + + if (out_end != (char **)0) { + *out_end = (char *)text; + } + + if (p == (const char *)0) { + return 0L; + } + + if (*p == '+' || *p == '-') { + negative = (*p == '-') ? 1 : 0; + p++; + } + + if (base == 0) { + if (p[0] == '0') { + if ((p[1] == 'x' || p[1] == 'X') && isxdigit((unsigned char)p[2]) != 0) { + base = 16; + p += 2; + } else { + base = 8; + } + } else { + base = 10; + } + } else if (base == 16) { + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + } + } + + if (base < 2 || base > 36) { + return 0L; + } + + limit = (negative != 0) ? ((unsigned long long)LONG_MAX + 1ULL) : (unsigned long long)LONG_MAX; + + while (*p != '\0') { + int digit = clib_digit_value((unsigned char)*p); + + if (digit < 0 || digit >= base) { + break; + } + + any = 1; + + if (value > (limit - (unsigned long long)digit) / (unsigned long long)base) { + overflow = 1; + value = limit; + } else if (overflow == 0) { + value = value * (unsigned long long)base + (unsigned long long)digit; + } + + p++; + } + + if (any == 0) { + return 0L; + } + + if (out_end != (char **)0) { + *out_end = (char *)p; + } + + if (overflow != 0) { + return (negative != 0) ? LONG_MIN : LONG_MAX; + } + + if (negative != 0) { + if (value == ((unsigned long long)LONG_MAX + 1ULL)) { + return LONG_MIN; + } + return -(long)value; + } + + return (long)value; +} + +long long strtoll(const char *text, char **out_end, int base) { + return (long long)strtol(text, out_end, base); +} + +unsigned long long strtoull(const char *text, char **out_end, int base) { + return (unsigned long long)strtoul(text, out_end, base); +} + +static unsigned long clib_rand_state = 1UL; + +void srand(unsigned int seed) { + clib_rand_state = (unsigned long)seed; + if (clib_rand_state == 0UL) { + clib_rand_state = 1UL; + } +} + +int rand(void) { + clib_rand_state = (1103515245UL * clib_rand_state) + 12345UL; + return (int)((clib_rand_state >> 16) & (unsigned long)RAND_MAX); +} + +void exit(int status) { + (void)cleonos_sys_exit((u64)(unsigned long long)status); + + for (;;) { + (void)cleonos_sys_yield(); + } +} + +void abort(void) { + exit(EXIT_FAILURE); +} diff --git a/cleonos/c/src/libc_string.c b/cleonos/c/src/libc_string.c new file mode 100644 index 0000000..bbb1bd7 --- /dev/null +++ b/cleonos/c/src/libc_string.c @@ -0,0 +1,445 @@ +#include + +void *memset(void *dst, int value, size_t size) { + unsigned char *d = (unsigned char *)dst; + unsigned char byte = (unsigned char)value; + size_t i; + + if (d == (unsigned char *)0) { + return dst; + } + + for (i = 0U; i < size; i++) { + d[i] = byte; + } + + return dst; +} + +void *memcpy(void *dst, const void *src, size_t size) { + unsigned char *d = (unsigned char *)dst; + const unsigned char *s = (const unsigned char *)src; + size_t i; + + if (d == (unsigned char *)0 || s == (const unsigned char *)0) { + return dst; + } + + for (i = 0U; i < size; i++) { + d[i] = s[i]; + } + + return dst; +} + +void *memmove(void *dst, const void *src, size_t size) { + unsigned char *d = (unsigned char *)dst; + const unsigned char *s = (const unsigned char *)src; + size_t i; + + if (d == (unsigned char *)0 || s == (const unsigned char *)0 || d == s || size == 0U) { + return dst; + } + + if (d < s || d >= s + size) { + for (i = 0U; i < size; i++) { + d[i] = s[i]; + } + } else { + for (i = size; i > 0U; i--) { + d[i - 1U] = s[i - 1U]; + } + } + + return dst; +} + +int memcmp(const void *left, const void *right, size_t size) { + const unsigned char *a = (const unsigned char *)left; + const unsigned char *b = (const unsigned char *)right; + size_t i; + + if (a == b || size == 0U) { + return 0; + } + + if (a == (const unsigned char *)0) { + return -1; + } + + if (b == (const unsigned char *)0) { + return 1; + } + + for (i = 0U; i < size; i++) { + if (a[i] != b[i]) { + return (a[i] < b[i]) ? -1 : 1; + } + } + + return 0; +} + +void *memchr(const void *src, int value, size_t size) { + const unsigned char *s = (const unsigned char *)src; + unsigned char needle = (unsigned char)value; + size_t i; + + if (s == (const unsigned char *)0) { + return (void *)0; + } + + for (i = 0U; i < size; i++) { + if (s[i] == needle) { + return (void *)(s + i); + } + } + + return (void *)0; +} + +size_t strlen(const char *text) { + size_t len = 0U; + + if (text == (const char *)0) { + return 0U; + } + + while (text[len] != '\0') { + len++; + } + + return len; +} + +size_t strnlen(const char *text, size_t max_size) { + size_t len = 0U; + + if (text == (const char *)0) { + return 0U; + } + + while (len < max_size && text[len] != '\0') { + len++; + } + + return len; +} + +char *strcpy(char *dst, const char *src) { + size_t i = 0U; + + if (dst == (char *)0 || src == (const char *)0) { + return dst; + } + + while (src[i] != '\0') { + dst[i] = src[i]; + i++; + } + + dst[i] = '\0'; + return dst; +} + +char *strncpy(char *dst, const char *src, size_t size) { + size_t i = 0U; + + if (dst == (char *)0 || src == (const char *)0) { + return dst; + } + + while (i < size && src[i] != '\0') { + dst[i] = src[i]; + i++; + } + + while (i < size) { + dst[i++] = '\0'; + } + + return dst; +} + +int strcmp(const char *left, const char *right) { + size_t i = 0U; + + if (left == right) { + return 0; + } + + if (left == (const char *)0) { + return -1; + } + + if (right == (const char *)0) { + return 1; + } + + while (left[i] != '\0' && right[i] != '\0') { + if (left[i] != right[i]) { + return (left[i] < right[i]) ? -1 : 1; + } + i++; + } + + if (left[i] == right[i]) { + return 0; + } + + return (left[i] < right[i]) ? -1 : 1; +} + +int strncmp(const char *left, const char *right, size_t size) { + size_t i = 0U; + + if (size == 0U || left == right) { + return 0; + } + + if (left == (const char *)0) { + return -1; + } + + if (right == (const char *)0) { + return 1; + } + + while (i < size && left[i] != '\0' && right[i] != '\0') { + if (left[i] != right[i]) { + return (left[i] < right[i]) ? -1 : 1; + } + i++; + } + + if (i == size) { + return 0; + } + + if (left[i] == right[i]) { + return 0; + } + + return (left[i] < right[i]) ? -1 : 1; +} + +char *strchr(const char *text, int ch) { + char needle = (char)ch; + size_t i = 0U; + + if (text == (const char *)0) { + return (char *)0; + } + + while (text[i] != '\0') { + if (text[i] == needle) { + return (char *)(text + i); + } + i++; + } + + if (needle == '\0') { + return (char *)(text + i); + } + + return (char *)0; +} + +char *strrchr(const char *text, int ch) { + char needle = (char)ch; + const char *last = (const char *)0; + size_t i = 0U; + + if (text == (const char *)0) { + return (char *)0; + } + + while (text[i] != '\0') { + if (text[i] == needle) { + last = text + i; + } + i++; + } + + if (needle == '\0') { + return (char *)(text + i); + } + + return (char *)last; +} + +char *strstr(const char *haystack, const char *needle) { + size_t i; + size_t j; + size_t nlen; + + if (haystack == (const char *)0 || needle == (const char *)0) { + return (char *)0; + } + + nlen = strlen(needle); + if (nlen == 0U) { + return (char *)haystack; + } + + for (i = 0U; haystack[i] != '\0'; i++) { + if (haystack[i] != needle[0]) { + continue; + } + + for (j = 1U; j < nlen; j++) { + if (haystack[i + j] == '\0' || haystack[i + j] != needle[j]) { + break; + } + } + + if (j == nlen) { + return (char *)(haystack + i); + } + } + + return (char *)0; +} + +static int clib_delim_contains(const char *delim, char ch) { + size_t i = 0U; + + if (delim == (const char *)0) { + return 0; + } + + while (delim[i] != '\0') { + if (delim[i] == ch) { + return 1; + } + i++; + } + + return 0; +} + +size_t strspn(const char *text, const char *accept) { + size_t n = 0U; + + if (text == (const char *)0 || accept == (const char *)0) { + return 0U; + } + + while (text[n] != '\0' && clib_delim_contains(accept, text[n]) != 0) { + n++; + } + + return n; +} + +size_t strcspn(const char *text, const char *reject) { + size_t n = 0U; + + if (text == (const char *)0 || reject == (const char *)0) { + return 0U; + } + + while (text[n] != '\0' && clib_delim_contains(reject, text[n]) == 0) { + n++; + } + + return n; +} + +char *strpbrk(const char *text, const char *accept) { + size_t i = 0U; + + if (text == (const char *)0 || accept == (const char *)0) { + return (char *)0; + } + + while (text[i] != '\0') { + if (clib_delim_contains(accept, text[i]) != 0) { + return (char *)(text + i); + } + i++; + } + + return (char *)0; +} + +char *strtok_r(char *text, const char *delim, char **saveptr) { + char *start; + char *cursor; + + if (delim == (const char *)0 || saveptr == (char **)0) { + return (char *)0; + } + + if (text != (char *)0) { + cursor = text; + } else { + cursor = *saveptr; + } + + if (cursor == (char *)0) { + return (char *)0; + } + + while (*cursor != '\0' && clib_delim_contains(delim, *cursor) != 0) { + cursor++; + } + + if (*cursor == '\0') { + *saveptr = cursor; + return (char *)0; + } + + start = cursor; + while (*cursor != '\0' && clib_delim_contains(delim, *cursor) == 0) { + cursor++; + } + + if (*cursor == '\0') { + *saveptr = cursor; + } else { + *cursor = '\0'; + *saveptr = cursor + 1; + } + + return start; +} + +char *strtok(char *text, const char *delim) { + static char *state = (char *)0; + return strtok_r(text, delim, &state); +} + +char *strcat(char *dst, const char *src) { + size_t dlen = strlen(dst); + size_t i = 0U; + + if (dst == (char *)0 || src == (const char *)0) { + return dst; + } + + while (src[i] != '\0') { + dst[dlen + i] = src[i]; + i++; + } + + dst[dlen + i] = '\0'; + return dst; +} + +char *strncat(char *dst, const char *src, size_t size) { + size_t dlen = strlen(dst); + size_t i = 0U; + + if (dst == (char *)0 || src == (const char *)0) { + return dst; + } + + while (i < size && src[i] != '\0') { + dst[dlen + i] = src[i]; + i++; + } + + dst[dlen + i] = '\0'; + return dst; +} diff --git a/cleonos/c/src/stdio.c b/cleonos/c/src/stdio.c new file mode 100644 index 0000000..9997baa --- /dev/null +++ b/cleonos/c/src/stdio.c @@ -0,0 +1,500 @@ +#include + +#include + +typedef unsigned long clio_size_t; + +#define CLIO_SINK_FD 1 +#define CLIO_SINK_BUF 2 + +struct clio_sink { + int mode; + int fd; + char *buffer; + clio_size_t capacity; + clio_size_t count; + int failed; +}; + +static clio_size_t clio_strlen(const char *text) { + clio_size_t len = 0UL; + + if (text == (const char *)0) { + return 0UL; + } + + while (text[len] != '\0') { + len++; + } + + return len; +} + +static int clio_write_all_fd(int fd, const char *text, clio_size_t len) { + const char *cursor = text; + clio_size_t left = len; + + if (fd < 0 || (text == (const char *)0 && len != 0UL)) { + return EOF; + } + + while (left > 0UL) { + u64 wrote = cleonos_sys_fd_write((u64)fd, cursor, (u64)left); + clio_size_t progressed; + + if (wrote == 0ULL || wrote == (u64)-1) { + return EOF; + } + + progressed = (wrote > (u64)left) ? left : (clio_size_t)wrote; + cursor += progressed; + left -= progressed; + } + + if (len > 0x7FFFFFFFUL) { + return 0x7FFFFFFF; + } + + return (int)len; +} + +static void clio_sink_init_fd(struct clio_sink *sink, int fd) { + sink->mode = CLIO_SINK_FD; + sink->fd = fd; + sink->buffer = (char *)0; + sink->capacity = 0UL; + sink->count = 0UL; + sink->failed = 0; +} + +static void clio_sink_init_buffer(struct clio_sink *sink, char *out, clio_size_t out_size) { + sink->mode = CLIO_SINK_BUF; + sink->fd = -1; + sink->buffer = out; + sink->capacity = out_size; + sink->count = 0UL; + sink->failed = 0; + + if (out != (char *)0 && out_size > 0UL) { + out[0] = '\0'; + } +} + +static void clio_sink_finalize_buffer(struct clio_sink *sink) { + if (sink->mode != CLIO_SINK_BUF || sink->buffer == (char *)0 || sink->capacity == 0UL) { + return; + } + + if (sink->count < sink->capacity) { + sink->buffer[sink->count] = '\0'; + } else { + sink->buffer[sink->capacity - 1UL] = '\0'; + } +} + +static int clio_sink_emit(struct clio_sink *sink, const char *text, clio_size_t len) { + if (sink == (struct clio_sink *)0 || text == (const char *)0 || len == 0UL) { + return 1; + } + + if (sink->mode == CLIO_SINK_FD) { + if (clio_write_all_fd(sink->fd, text, len) == EOF) { + sink->failed = 1; + return 0; + } + } else { + if (sink->buffer != (char *)0 && sink->capacity > 0UL) { + clio_size_t i; + clio_size_t start = sink->count; + clio_size_t writable = 0UL; + + if (start + 1UL < sink->capacity) { + writable = (sink->capacity - 1UL) - start; + } + + if (len < writable) { + writable = len; + } + + for (i = 0UL; i < writable; i++) { + sink->buffer[start + i] = text[i]; + } + } + } + + sink->count += len; + return 1; +} + +static clio_size_t clio_u64_to_base(unsigned long long value, + unsigned int base, + int uppercase, + char *out, + clio_size_t out_size) { + char tmp[64]; + clio_size_t pos = 0UL; + clio_size_t i = 0UL; + + if (out == (char *)0 || out_size < 2UL || base < 2U || base > 16U) { + return 0UL; + } + + if (value == 0ULL) { + out[0] = '0'; + out[1] = '\0'; + return 1UL; + } + + while (value != 0ULL && pos < (clio_size_t)sizeof(tmp)) { + unsigned long long digit = value % (unsigned long long)base; + + if (digit < 10ULL) { + tmp[pos++] = (char)('0' + digit); + } else { + char alpha = (uppercase != 0) ? 'A' : 'a'; + tmp[pos++] = (char)(alpha + (char)(digit - 10ULL)); + } + + value /= (unsigned long long)base; + } + + if (pos + 1UL > out_size) { + return 0UL; + } + + while (pos > 0UL) { + pos--; + out[i++] = tmp[pos]; + } + + out[i] = '\0'; + return i; +} + +static clio_size_t clio_i64_to_dec(long long value, char *out, clio_size_t out_size) { + unsigned long long magnitude; + clio_size_t offset = 0UL; + clio_size_t len; + + if (out == (char *)0 || out_size < 2UL) { + return 0UL; + } + + if (value < 0LL) { + out[offset++] = '-'; + if (offset + 2UL > out_size) { + return 0UL; + } + magnitude = (unsigned long long)(-(value + 1LL)) + 1ULL; + } else { + magnitude = (unsigned long long)value; + } + + len = clio_u64_to_base(magnitude, 10U, 0, out + offset, out_size - offset); + + if (len == 0UL) { + return 0UL; + } + + return offset + len; +} + +static int clio_vformat(struct clio_sink *sink, const char *fmt, va_list args) { + const char *cursor = fmt; + + if (sink == (struct clio_sink *)0 || fmt == (const char *)0) { + return EOF; + } + + while (*cursor != '\0') { + if (*cursor != '%') { + if (clio_sink_emit(sink, cursor, 1UL) == 0) { + return EOF; + } + cursor++; + continue; + } + + cursor++; + + if (*cursor == '%') { + if (clio_sink_emit(sink, "%", 1UL) == 0) { + return EOF; + } + cursor++; + continue; + } + + { + int length_mode = 0; /* 0: default, 1: l, 2: ll, 3: z */ + char spec = *cursor; + char number_buf[64]; + clio_size_t out_len = 0UL; + + if (spec == 'l') { + cursor++; + spec = *cursor; + length_mode = 1; + + if (spec == 'l') { + cursor++; + spec = *cursor; + length_mode = 2; + } + } else if (spec == 'z') { + cursor++; + spec = *cursor; + length_mode = 3; + } + + if (spec == '\0') { + break; + } + + if (spec == 's') { + const char *text = va_arg(args, const char *); + + if (text == (const char *)0) { + text = "(null)"; + } + + out_len = clio_strlen(text); + + if (clio_sink_emit(sink, text, out_len) == 0) { + return EOF; + } + } else if (spec == 'c') { + char out = (char)va_arg(args, int); + + if (clio_sink_emit(sink, &out, 1UL) == 0) { + return EOF; + } + } else if (spec == 'd' || spec == 'i') { + long long value; + + if (length_mode == 2) { + value = va_arg(args, long long); + } else if (length_mode == 1) { + value = (long long)va_arg(args, long); + } else if (length_mode == 3) { + value = (long long)va_arg(args, long long); + } else { + value = (long long)va_arg(args, int); + } + + out_len = clio_i64_to_dec(value, number_buf, (clio_size_t)sizeof(number_buf)); + if (out_len == 0UL || clio_sink_emit(sink, number_buf, out_len) == 0) { + return EOF; + } + } else if (spec == 'u' || spec == 'x' || spec == 'X') { + unsigned long long value; + unsigned int base = (spec == 'u') ? 10U : 16U; + int upper = (spec == 'X') ? 1 : 0; + + if (length_mode == 2) { + value = va_arg(args, unsigned long long); + } else if (length_mode == 1) { + value = (unsigned long long)va_arg(args, unsigned long); + } else if (length_mode == 3) { + value = (unsigned long long)va_arg(args, unsigned long long); + } else { + value = (unsigned long long)va_arg(args, unsigned int); + } + + out_len = clio_u64_to_base(value, base, upper, number_buf, (clio_size_t)sizeof(number_buf)); + if (out_len == 0UL || clio_sink_emit(sink, number_buf, out_len) == 0) { + return EOF; + } + } else if (spec == 'p') { + const void *ptr = va_arg(args, const void *); + unsigned long long value = (unsigned long long)(unsigned long)ptr; + + if (clio_sink_emit(sink, "0x", 2UL) == 0) { + return EOF; + } + + out_len = clio_u64_to_base(value, 16U, 0, number_buf, (clio_size_t)sizeof(number_buf)); + if (out_len == 0UL || clio_sink_emit(sink, number_buf, out_len) == 0) { + return EOF; + } + } else { + char fallback[2]; + fallback[0] = spec; + fallback[1] = '\0'; + + if (clio_sink_emit(sink, "%", 1UL) == 0 || clio_sink_emit(sink, fallback, 1UL) == 0) { + return EOF; + } + } + + cursor++; + } + } + + if (sink->mode == CLIO_SINK_BUF) { + clio_sink_finalize_buffer(sink); + } + + if (sink->failed != 0) { + return EOF; + } + + if (sink->count > 0x7FFFFFFFUL) { + return 0x7FFFFFFF; + } + + return (int)sink->count; +} + +int putchar(int ch) { + char out = (char)(ch & 0xFF); + return (clio_write_all_fd(1, &out, 1UL) == EOF) ? EOF : (int)(unsigned char)out; +} + +int getchar(void) { + char ch = '\0'; + + for (;;) { + u64 got = cleonos_sys_fd_read(0ULL, &ch, 1ULL); + + if (got == 1ULL) { + return (int)(unsigned char)ch; + } + + if (got == (u64)-1) { + return EOF; + } + + (void)cleonos_sys_yield(); + } +} + +int fputc(int ch, int fd) { + char out = (char)(ch & 0xFF); + return (clio_write_all_fd(fd, &out, 1UL) == EOF) ? EOF : (int)(unsigned char)out; +} + +int fgetc(int fd) { + char ch = '\0'; + + if (fd < 0) { + return EOF; + } + + for (;;) { + u64 got = cleonos_sys_fd_read((u64)fd, &ch, 1ULL); + + if (got == 1ULL) { + return (int)(unsigned char)ch; + } + + if (got == (u64)-1) { + return EOF; + } + + (void)cleonos_sys_yield(); + } +} + +int fputs(const char *text, int fd) { + clio_size_t len; + + if (text == (const char *)0) { + return EOF; + } + + len = clio_strlen(text); + return clio_write_all_fd(fd, text, len); +} + +int puts(const char *text) { + int wrote = fputs(text, 1); + + if (wrote == EOF) { + return EOF; + } + + if (putchar('\n') == EOF) { + return EOF; + } + + return wrote + 1; +} + +int vsnprintf(char *out, unsigned long out_size, const char *fmt, va_list args) { + struct clio_sink sink; + va_list args_copy; + int rc; + + clio_sink_init_buffer(&sink, out, out_size); + va_copy(args_copy, args); + rc = clio_vformat(&sink, fmt, args_copy); + va_end(args_copy); + + return rc; +} + +int snprintf(char *out, unsigned long out_size, const char *fmt, ...) { + va_list args; + int rc; + + va_start(args, fmt); + rc = vsnprintf(out, out_size, fmt, args); + va_end(args); + + return rc; +} + +int vdprintf(int fd, const char *fmt, va_list args) { + struct clio_sink sink; + va_list args_copy; + int rc; + + clio_sink_init_fd(&sink, fd); + va_copy(args_copy, args); + rc = clio_vformat(&sink, fmt, args_copy); + va_end(args_copy); + + return rc; +} + +int dprintf(int fd, const char *fmt, ...) { + va_list args; + int rc; + + va_start(args, fmt); + rc = vdprintf(fd, fmt, args); + va_end(args); + + return rc; +} + +int vfprintf(int fd, const char *fmt, va_list args) { + return vdprintf(fd, fmt, args); +} + +int fprintf(int fd, const char *fmt, ...) { + va_list args; + int rc; + + va_start(args, fmt); + rc = vdprintf(fd, fmt, args); + va_end(args); + + return rc; +} + +int vprintf(const char *fmt, va_list args) { + return vdprintf(1, fmt, args); +} + +int printf(const char *fmt, ...) { + va_list args; + int rc; + + va_start(args, fmt); + rc = vdprintf(1, fmt, args); + va_end(args); + + return rc; +}