summaryrefslogtreecommitdiff
path: root/userland
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-05-02 16:52:26 +0200
committerAnton Kling <anton@kling.gg>2024-05-02 18:35:47 +0200
commitad8619ae362b4b626e99b90b1b7c4d7e59125f65 (patch)
tree2d46caa903ba9435fc51012b6ddf41292ad316f7 /userland
parentfaebb71b8a84e33f4f2b3f8f70f845011483c5c5 (diff)
sh: Use string view instead of C strings
Diffstat (limited to 'userland')
-rw-r--r--userland/libc/include/tb/sv.h5
-rw-r--r--userland/libc/tb/sv.c57
-rw-r--r--userland/minibox/utilities/sh/ast.h4
-rw-r--r--userland/minibox/utilities/sh/lexer.c54
-rw-r--r--userland/minibox/utilities/sh/lexer.h5
-rw-r--r--userland/minibox/utilities/sh/sh.c79
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;
}