diff options
author | Anton Kling <anton@kling.gg> | 2024-05-02 16:52:26 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-05-02 18:35:47 +0200 |
commit | ad8619ae362b4b626e99b90b1b7c4d7e59125f65 (patch) | |
tree | 2d46caa903ba9435fc51012b6ddf41292ad316f7 /userland | |
parent | faebb71b8a84e33f4f2b3f8f70f845011483c5c5 (diff) |
sh: Use string view instead of C strings
Diffstat (limited to 'userland')
-rw-r--r-- | userland/libc/include/tb/sv.h | 5 | ||||
-rw-r--r-- | userland/libc/tb/sv.c | 57 | ||||
-rw-r--r-- | userland/minibox/utilities/sh/ast.h | 4 | ||||
-rw-r--r-- | userland/minibox/utilities/sh/lexer.c | 54 | ||||
-rw-r--r-- | userland/minibox/utilities/sh/lexer.h | 5 | ||||
-rw-r--r-- | userland/minibox/utilities/sh/sh.c | 79 |
6 files changed, 128 insertions, 76 deletions
diff --git a/userland/libc/include/tb/sv.h b/userland/libc/include/tb/sv.h index 6e81b0b..54ec218 100644 --- a/userland/libc/include/tb/sv.h +++ b/userland/libc/include/tb/sv.h @@ -21,6 +21,11 @@ struct sv sv_split_delim(const struct sv input, struct sv *rest, char delim); struct sv sv_end_split_delim(const struct sv input, struct sv *rest, char delim); struct sv sv_split_space(const struct sv input, struct sv *rest); +struct sv sv_skip_chars(const struct sv input, const char *chars); +struct sv sv_split_function(const struct sv input, struct sv *rest, + int (*function)(int)); +struct sv sv_take(struct sv s, struct sv *rest, size_t n); +struct sv sv_next(struct sv s); int sv_isempty(struct sv s); char sv_peek(struct sv s); int sv_eq(struct sv a, struct sv b); diff --git a/userland/libc/tb/sv.c b/userland/libc/tb/sv.c index 45eb0d9..ac1c1e5 100644 --- a/userland/libc/tb/sv.c +++ b/userland/libc/tb/sv.c @@ -11,16 +11,46 @@ char *SV_TO_C(struct sv s) { return c_string; } -struct sv sv_split_space(const struct sv input, struct sv *rest) { +struct sv sv_next(struct sv s) { + if (0 == s.length) { + return s; + } + s.length--; + s.s++; + return s; +} + +struct sv sv_skip_chars(const struct sv input, const char *chars) { + struct sv r = input; + for (; r.length > 0;) { + int found = 0; + const char *p = chars; + for (; *p; p++) { + if (*p == r.s[0]) { + r.s++; + r.length--; + found = 1; + break; + } + } + if (!found) { + break; + } + } + return r; +} + +struct sv sv_split_function(const struct sv input, struct sv *rest, + int (*function)(int)) { struct sv r = { .s = input.s, }; for (size_t i = 0; i < input.length; i++) { - if (isspace(input.s[i])) { + if (function(input.s[i])) { r.length = i; if (rest) { - rest->s += i + 1; - rest->length -= (i + 1); + rest->s += i; + rest->length -= i; } return r; } @@ -33,6 +63,10 @@ struct sv sv_split_space(const struct sv input, struct sv *rest) { return input; } +struct sv sv_split_space(const struct sv input, struct sv *rest) { + return sv_split_function(input, rest, isspace); +} + struct sv sv_end_split_delim(const struct sv input, struct sv *rest, char delim) { for (size_t i = input.length - 1; i > 0; i--) { @@ -113,6 +147,19 @@ int sv_eq(struct sv a, struct sv b) { return 1; } +struct sv sv_take(struct sv s, struct sv *rest, size_t n) { + if (s.length < n) { + if (rest) { + rest->length = 0; + } + return s; + } + s.length = n; + rest->length -= n; + rest->s += n; + return s; +} + struct sv sv_trim_left(struct sv s, size_t n) { if (s.length < n) { s.s += s.length; @@ -135,7 +182,7 @@ struct sv sv_clone(struct sv s) { char *sv_copy_to_c(struct sv s, char *out, size_t buffer_length) { int copy_len = min(s.length + 1, buffer_length); - if(0 == copy_len) { + if (0 == copy_len) { return NULL; } if (!out) { diff --git a/userland/minibox/utilities/sh/ast.h b/userland/minibox/utilities/sh/ast.h index 7e7aaff..ae43f67 100644 --- a/userland/minibox/utilities/sh/ast.h +++ b/userland/minibox/utilities/sh/ast.h @@ -9,7 +9,7 @@ typedef enum { struct AST_VALUE { ast_value_type_t type; union { - char *string; + struct sv string; }; }; @@ -27,7 +27,7 @@ struct AST { struct AST *pipe_rhs; // in "func1 | func2" func2 is the piped rhs int file_out_fd_to_use; int file_out_append; - const char *file_out; // in "func1 > file.txt" file.txt is the file_out + struct sv file_out; // in "func1 > file.txt" file.txt is the file_out struct AST *next; }; diff --git a/userland/minibox/utilities/sh/lexer.c b/userland/minibox/utilities/sh/lexer.c index 72011e6..4ad2389 100644 --- a/userland/minibox/utilities/sh/lexer.c +++ b/userland/minibox/utilities/sh/lexer.c @@ -1,6 +1,6 @@ +#include "lexer.h" #include <assert.h> #include <ctype.h> -#include "lexer.h" #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -14,43 +14,34 @@ void free_tokens(struct TOKEN *token) { } } -int is_nonspecial_char(char c) { +int is_special_char(char c) { if (!isprint(c)) - return 0; + return 1; if (isspace(c)) - return 0; - if (isalnum(c)) return 1; - return ('>' != c && '|' != c && '&' != c); + if (isalnum(c)) + return 0; + return !(('>' != c && '|' != c && '&' != c)); } -int parse_chars(const char **code_ptr, struct TOKEN *cur) { - const char *code = *code_ptr; - if (!is_nonspecial_char(*code)) +int parse_chars(struct sv *code_ptr, struct TOKEN *cur) { + struct sv code = *code_ptr; + if (is_special_char(sv_peek(code))) return 0; cur->type = TOKEN_CHARS; - int i = 0; - for (; *code; code++, i++) { - if (!is_nonspecial_char(*code)) { - break; - } - assert(i < 256); - cur->string_rep[i] = *code; - } - cur->string_rep[i] = '\0'; + cur->string_rep = sv_split_function(code, &code, is_special_char); *code_ptr = code; return 1; } // Operands such as: &, &&, |, || etc // Is operands the right word? -int parse_operand(const char **code_ptr, struct TOKEN *cur) { - const char *code = *code_ptr; +int parse_operand(struct sv *code_ptr, struct TOKEN *cur) { + struct sv code = *code_ptr; #define TRY_PARSE_STRING(_s, _token) \ - if (0 == strncmp(code, _s, strlen(_s))) { \ - cur->type = _token; \ - strcpy(cur->string_rep, _s); \ - code += strlen(_s); \ + if (sv_partial_eq(code, C_TO_SV(_s))) { \ + cur->type = TOKEN_AND; \ + cur->string_rep = sv_take(code, &code, strlen(_s)); \ goto complete_return; \ } TRY_PARSE_STRING("&&", TOKEN_AND); @@ -68,20 +59,19 @@ complete_return: return 1; } -void skip_whitespace(const char **code_ptr) { - const char *code = *code_ptr; - for (; isspace(*code); code++) - ; - *code_ptr = code; +void skip_whitespace(struct sv *s) { + *s = sv_skip_chars(*s, " \t\n\r"); } -struct TOKEN *lex(const char *code) { +struct TOKEN *lex(struct sv code) { struct TOKEN *head = NULL; struct TOKEN *prev = NULL; - for (; *code;) { + for (; !sv_isempty(code);) { skip_whitespace(&code); - if (!*code) + if (sv_isempty(code)) { break; + } + struct TOKEN *cur = malloc(sizeof(struct TOKEN)); cur->next = NULL; if (prev) diff --git a/userland/minibox/utilities/sh/lexer.h b/userland/minibox/utilities/sh/lexer.h index 57fb30b..b8ca95c 100644 --- a/userland/minibox/utilities/sh/lexer.h +++ b/userland/minibox/utilities/sh/lexer.h @@ -1,6 +1,7 @@ #ifndef LEXER_H #define LEXER_H #include <stddef.h> +#include <tb/sv.h> typedef enum { TOKEN_CHARS, @@ -14,11 +15,11 @@ typedef enum { struct TOKEN { token_type_t type; - char string_rep[256]; + struct sv string_rep; struct TOKEN *next; }; -struct TOKEN *lex(const char *code); +struct TOKEN *lex(struct sv code); struct AST *generate_ast(struct TOKEN *token); void free_tokens(struct TOKEN *token); #endif // LEXER_H diff --git a/userland/minibox/utilities/sh/sh.c b/userland/minibox/utilities/sh/sh.c index a2db331..433c2e1 100644 --- a/userland/minibox/utilities/sh/sh.c +++ b/userland/minibox/utilities/sh/sh.c @@ -10,13 +10,13 @@ int execute_command(struct AST *ast, int input_fd); int execute_binary(struct AST *ast, int input_fd) { - char *program = ast->val.string; + char *program = SV_TO_C(ast->val.string); struct AST *child = ast->children; char *argv[100]; argv[0] = program; int i = 1; for (; child; i++, child = child->next) { - argv[i] = child->val.string; + argv[i] = SV_TO_C(child->val.string); } argv[i] = NULL; @@ -25,11 +25,12 @@ int execute_binary(struct AST *ast, int input_fd) { int slave_input = -1; int file_out_fd; - if (ast->file_out) { - file_out_fd = - open(ast->file_out, - O_WRONLY | O_CREAT | ((ast->file_out_append) ? O_APPEND : O_TRUNC), - 0666); + if (!sv_isempty(ast->file_out)) { + char *tmp = SV_TO_C(ast->file_out); + file_out_fd = open( + tmp, O_WRONLY | O_CREAT | ((ast->file_out_append) ? O_APPEND : O_TRUNC), + 0666); + free(tmp); } if (ast->pipe_rhs) { @@ -41,19 +42,27 @@ int execute_binary(struct AST *ast, int input_fd) { int pid = fork(); if (0 == pid) { - if (slave_input >= 0) + if (slave_input >= 0) { close(slave_input); + } dup2(in, STDIN_FILENO); dup2(out, STDOUT_FILENO); - if (ast->file_out) + if (!sv_isempty(ast->file_out)) { dup2(file_out_fd, ast->file_out_fd_to_use); + } execvp(program, argv); perror("execvp"); exit(1); } - if (ast->file_out) + + for (int j = 0; j < i; j++) { + free(argv[j]); + } + + if (!sv_isempty(ast->file_out)) { close(file_out_fd); + } if (ast->pipe_rhs) { if (out >= 0) @@ -67,15 +76,18 @@ int execute_binary(struct AST *ast, int input_fd) { } int execute_command(struct AST *ast, int input_fd) { - char *program = ast->val.string; - if (0 == strcmp(program, "cd")) { + struct sv program = ast->val.string; + if (sv_eq(program, C_TO_SV("cd"))) { struct AST *child = ast->children; - char *directory; - if (!child) - directory = "~"; - else + struct sv directory; + if (!child) { + directory = C_TO_SV("~"); + } else { directory = child->val.string; - int rc = chdir(directory); + } + char *dir = SV_TO_C(directory); + int rc = chdir(dir); + free(dir); if (-1 == rc) { perror("cd"); return 1; @@ -107,34 +119,29 @@ void execute_ast(struct AST *ast) { } } -char *get_line(void) { - char *str = malloc(1024); - char *p = str; +void get_line(struct sb *s) { int rc; for (;;) { - if (0 == (rc = read(0, p, 1))) { + char c; + if (0 == (rc = read(0, &c, 1))) { continue; } if (0 > rc) { perror("read"); continue; } - if (8 == *p) { - if (p == str) - continue; - putchar(*p); - p--; + if ('\b' == c) { + if (sb_delete_right(s, 1) > 0) { + putchar('\b'); + } continue; } - putchar(*p); - if ('\n' == *p) { + sb_append_char(s, c); + putchar(c); + if ('\n' == c) { break; } - p++; } - p++; - *p = '\0'; - return str; } int sh_main(int argc, char **argv) { @@ -143,15 +150,17 @@ int sh_main(int argc, char **argv) { for (;;) { char buffer[256]; printf("%s : ", getcwd(buffer, 256)); - char *line = get_line(); + struct sb line; + sb_init(&line); + get_line(&line); { - struct TOKEN *h = lex(line); + struct TOKEN *h = lex(SB_TO_SV(line)); struct AST *ast_h = generate_ast(h); execute_ast(ast_h); free_tokens(h); free_ast(ast_h); } - free(line); + sb_free(&line); } return 0; } |