diff --git a/Makefile b/Makefile index 410cada..d01de32 100644 --- a/Makefile +++ b/Makefile @@ -81,8 +81,7 @@ all: $(NAME_release) .PHONY: tests_run tests_run: $(NAME_test) - - find fixtures -name "*.sh" | xargs -i \ - sh -c 'cat {} | env -i PATH="$(dir $(shell which ls))" ./$^' + @ - python3 validator.py ./$(NAME_test) .PHONY: cov cov: tests_run diff --git a/README.md b/README.md index 107eb2a..47003f3 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,9 @@ - [x] redirections - [ ] line editing (move, del, multi-line) - [ ] input shortcut (^A,^E,^R,^V,^F,^B,...) -- [ ] color highlighting in input - [ ] foreground/background jobs (`&`), (btln `fg`, `bg`, `jobs`) -- [ ] while/for/foreach loops -- [ ] if / cases +- [x] while/foreach loops +- [x] if - [x] `||`/`&&` - [ ] configuration file - [x] script with shebangs @@ -40,19 +39,13 @@ - [ ] `-e` exit on failure - [ ] `-n` (dry run mode) - [ ] `-h` help (open man?) -- [ ] autocompletion of commands - [x] globbing -- [ ] var interpreter -- [ ] inhibitor -- [ ] magic quotes -- [ ] parenthesis (sub-commands) -- [ ] direnv/wakatime integration +- [x] var interpreter +- [x] inhibitor +- [x] magic quotes +- [x] parenthesis - [x] command history (`history` btln) -- [ ] arithmetric expansion (`$(( x + 1 ))`) -- [ ] brace expansion: `{a,b,c}` and `{1..10}` - [x] heredocs - [ ] functions (`:() { :|:& }`) - [ ] special env vars: `$?`, `$$`, ... - [ ] git integration (branch) -- [ ] `x`, `e`, `o` & pipefail modes -- [ ] file inquiry operators (`-d`, `f`, ...) diff --git a/afunc.txt b/afunc.txt deleted file mode 100644 index 84736e7..0000000 --- a/afunc.txt +++ /dev/null @@ -1,36 +0,0 @@ -malloc -free -exit -opendir -readdir -closedir -getcwd -chdir -fork -stat -lstat -fstat -open -close -getline -strtok -strtok_r -read -write -execve -access -isatty -wait -wait-pid -wait3 -wait4 -signal -kill -getpid -strerror -perror -strsignal -pipe -dup -dup2 -stdin diff --git a/iftest.sh b/iftest.sh deleted file mode 100644 index e3ffc45..0000000 --- a/iftest.sh +++ /dev/null @@ -1,5 +0,0 @@ -if ls - echo YES -else - echo NO -endif diff --git a/out.txt b/out.txt deleted file mode 100644 index 45f0b6a..0000000 --- a/out.txt +++ /dev/null @@ -1,3 +0,0 @@ -plop -again -again diff --git a/src/alias.c b/src/alias.c index d67ee6d..786d4e5 100644 --- a/src/alias.c +++ b/src/alias.c @@ -17,7 +17,7 @@ #include "utils.h" static -int skip_blank(char *buffer, int i) +int skip_blank(const char *buffer, int i) { for (; buffer[i] != 0 && isblank(buffer[i]); i++); return i; @@ -26,7 +26,7 @@ int skip_blank(char *buffer, int i) static int skip_to_next_token(char *buffer, int i) { - for (; buffer[i] != 0 && is_a_token(buffer, i) == false; i++); + for (; buffer[i] != 0 && !is_a_token(buffer, i); i++); return i; } @@ -34,17 +34,17 @@ static char *find_alias(his_variable_t *variable, alias_t *alias, char *buffer) { char *cmd = malloc(sizeof(char) * (variable->size_variable + 1)); - char *new_cmd = NULL; + char *new_cmd = nullptr; if (cmd == NULL) - return NULL; + return nullptr; for (int i = variable->coord_variable; i != variable->coord_variable + variable->size_variable; i++) cmd[i - variable->coord_variable] = buffer[i]; cmd[variable->size_variable] = '\0'; for (size_t i = 0; i != alias->size; i++){ if (alias->alias_array[i] == NULL) - return NULL; + return nullptr; if (strcmp(cmd, alias->alias_array[i]) == 0){ new_cmd = cat_in_str(variable, buffer, alias->alias_to_replace[i]); buffer = new_cmd; @@ -59,10 +59,10 @@ char *get_alias(char *buffer, int i, alias_t *alias) { int coord = i; int size = 0; - his_variable_t variable = {0, 0, 0, NULL, 0}; + his_variable_t variable = {0, 0, 0, nullptr, 0}; for (; buffer[i] != 0 && !isblank(buffer[i]) - && is_a_token(buffer, i) == false; i++) + && !is_a_token(buffer, i); i++) size++; variable.coord_variable = coord; variable.size_variable = size; @@ -90,7 +90,7 @@ int parse_alias(char **buffer, size_t *buffer_len, alias_t *alias) { bool need_to_replace = true; - while (need_to_replace == true) + while (need_to_replace) need_to_replace = replace_alias(buffer, alias); return RETURN_SUCCESS; } @@ -104,8 +104,8 @@ alias_t init_alias(void) alias.alias_to_replace = malloc(sizeof(char *) * alias.size); if (!alias.alias_array || !alias.alias_to_replace) return alias; - alias.alias_array[0] = NULL; - alias.alias_to_replace[0] = NULL; + alias.alias_array[0] = nullptr; + alias.alias_to_replace[0] = nullptr; alias.size = 0; return alias; } diff --git a/src/globbing.c b/src/args.c similarity index 61% rename from src/globbing.c rename to src/args.c index ba1774c..02d8ac7 100644 --- a/src/globbing.c +++ b/src/args.c @@ -12,8 +12,10 @@ #include #include +#include "args.h" +#include "debug.h" #include "exec.h" -#include "globbing.h" +#include "utils.h" bool check_glob_result(int val, char *bin_name) { @@ -31,7 +33,8 @@ bool process_globbing(char *pattern, args_t *args, size_t *toks_i) int glob_result; char *vl; - glob_result = glob(pattern, GLOB_ERR, NULL, &globs); + U_DEBUG("Globbing pattern [%s]\n", pattern); + glob_result = glob(pattern, GLOB_ERR, nullptr, &globs); if (!check_glob_result(glob_result, args->args[0])) return false; for (size_t i = 0; i < globs.gl_pathc; i++) { @@ -43,7 +46,27 @@ bool process_globbing(char *pattern, args_t *args, size_t *toks_i) args->sz++; } globfree(&globs); - *toks_i += 1; + return true; +} + +static +bool handle_tilde(ef_t *ef, token_t *tok, args_t *args) +{ + char *home; + char *final_str; + size_t tilde_pos = strcspn(tok->str, "~"); + + tok->str[tok->sz] = '\0'; + home = get_env_value(ef->env, "HOME"); + if (home != NULL) + final_str = get_env_value(ef->env, "HOME"); + else + final_str = strdup(""); + args->args[args->sz] = insert_str(tok->str, final_str, tilde_pos); + U_DEBUG("Tilde handling [%s] pos [%lu]\n", final_str, tilde_pos); + if (args->args[args->sz] == NULL) + return false; + args->sz++; return true; } @@ -53,13 +76,15 @@ bool process_args(ast_t *node, args_t *args, size_t *toks_i, ef_t *ef) if (!ensure_args_capacity(args)) return false; - if (tok.type == T_STAR || strcspn(tok.str, "[]?") != strlen(tok.str)) + if (tok.type == T_STAR || strcspn(tok.str, "[]?") != strlen(tok.str)) { + tok.str[tok.sz] = '\0'; return (process_globbing(tok.str, args, toks_i)); + } + if (tok.type == T_TILDE) + return handle_tilde(ef, &tok, args); handle_var_case(node, ef->exec_ctx, toks_i, args); if (args->args[args->sz] == NULL) return false; - if (strchr(tok.str, '\\') != NULL) - args->args[args->sz] = tok.str; args->sz++; return true; } diff --git a/src/globbing.h b/src/args.h similarity index 100% rename from src/globbing.h rename to src/args.h diff --git a/src/ast.h b/src/ast.h index a5bc8d6..aa0002b 100644 --- a/src/ast.h +++ b/src/ast.h @@ -37,10 +37,12 @@ typedef enum size_t { T_AT = 1 << 15, // < T_WHILE = 1 << 16, // while T_STAR = 1 << 18, // * - T_NEWLINE = 1 << 19, // \n - T_EOF = 1 << 20, // \0 - T_ARG = 1 << 21, - T_INVALID = 1 << 22 + T_BACKSLASH = 1 << 19, + T_NEWLINE = 1 << 20, // \n + T_TILDE = 1 << 21, // ~ + T_EOF = 1 << 22, // \0 + T_ARG = 1 << 23, + T_INVALID = 1 << 24 } token_type_t; typedef enum { @@ -140,4 +142,6 @@ ast_t *parse_condition(ast_ctx_t *ctx); ast_t *parse_and(ast_ctx_t *ctx, ast_t *l_node); ast_t *parse_or(ast_ctx_t *ctx, ast_t *l_node); ast_t *parse_if(ast_ctx_t *ctx); +ast_t *parse_condition_and(ast_ctx_t *ctx); +ast_t *parse_pipe(ast_ctx_t *ctx, ast_t *l_node); #endif /* AST_H */ diff --git a/src/ast/ast.c b/src/ast/ast.c index b889782..9abf6d6 100644 --- a/src/ast/ast.c +++ b/src/ast/ast.c @@ -14,22 +14,34 @@ #include "ast.h" +static +bool parse_special_args(ast_ctx_t *ctx) +{ + if (memchr(ctx->act_tok.str, '~', ctx->act_tok.sz) != NULL) + ctx->act_tok.type = T_TILDE; + if (memchr(ctx->act_tok.str, '*', ctx->act_tok.sz) != NULL) + ctx->act_tok.type = T_STAR; + return true; +} + static ast_t *parse_arg(ast_ctx_t *ctx, ast_t *node) { ctx->act_tok = get_next_token(ctx); - if (ctx->act_tok.type == T_SEMICOLON) + if (ctx->act_tok.type & (T_SEMICOLON | T_NEWLINE)) return node; - if (*ctx->act_tok.str == '\\') { + if (!parse_special_args(ctx)) + return nullptr; + if (ctx->act_tok.type == T_BACKSLASH) { ctx->act_tok = get_next_token(ctx); if (ctx->act_tok.type == T_EOF) return node; ctx->act_tok.type = T_ARG; } if (ctx->act_tok.type & (T_ARG | T_REDIRECT | T_APPEND | - T_IN_REDIRECT | T_HEREDOC | T_VAR | T_STAR)) { + T_IN_REDIRECT | T_HEREDOC | T_VAR | T_STAR | T_TILDE)) { if (!ensure_node_cap(node)) - return NULL; + return nullptr; node->vector.tokens[node->vector.sz] = ctx->act_tok; node->vector.sz++; return parse_arg(ctx, node); @@ -43,13 +55,15 @@ ast_t *fill_cmd_node(ast_ctx_t *ctx) ast_t *node = create_node(ctx); if (node == NULL) - return NULL; + return nullptr; node->type = N_CMD; node->vector.cap = DEFAULT_N_CMD_CAP; node->vector.tokens = malloc(sizeof *node->vector.tokens * node->vector.cap); if (node->vector.tokens == NULL) - return NULL; + return nullptr; + if (!parse_special_args(ctx)) + return nullptr; node->tok = ctx->act_tok; node->vector.tokens[0] = ctx->act_tok; node->vector.sz = 1; @@ -67,9 +81,9 @@ ast_t *parse_cmd(ast_ctx_t *ctx) { if (ctx->act_tok.type != T_ARG) { if (ctx->act_tok.type & (T_WHILE)) - return NULL; + return nullptr; if (!parser_eat(ctx, T_ARG)) - return NULL; + return nullptr; } return fill_cmd_node(ctx); } @@ -91,58 +105,34 @@ ast_t *parse_pipe(ast_ctx_t *ctx, ast_t *l_node) ast_t *node = create_node(ctx); if (node == NULL) - return NULL; + return nullptr; node->type = N_LST; node->tok = ctx->act_tok; node->list.cap = DEFAULT_N_LST_CAP; node->list.nodes = (ast_t **)malloc(sizeof(ast_t *) * node->list.cap); if ((void *)node->list.nodes == NULL) - return NULL; + return nullptr; node->list.sz = 1; node->list.nodes[0] = l_node; if (!parser_eat(ctx, T_ARG)) - return NULL; + return nullptr; while (ctx->act_tok.type & (T_ARG | T_PIPE)) if (!parse_pipe_childs(ctx, node)) - return NULL; + return nullptr; return node; } -ast_t *parse_condition(ast_ctx_t *ctx) -{ - ast_t *l_node = parse_cmd(ctx); - - if (l_node == NULL) - return NULL; - else { - switch (ctx->act_tok.type) { - case T_PIPE: - ctx->ast = parse_pipe(ctx, l_node); - break; - default: - return l_node; - } - } - return ctx->ast; -} - ast_t *parse_semi(ast_ctx_t *ctx) { - ast_t *l_node = parse_condition(ctx); + ast_t *l_node = parse_condition_and(ctx); if (l_node == NULL) - return NULL; - switch (ctx->act_tok.type) { - case T_AND: - ctx->ast = parse_and(ctx, l_node); - break; - case T_OR: - ctx->ast = parse_or(ctx, l_node); - break; - default: - return l_node; + return nullptr; + if (ctx->act_tok.type == T_OR) { + ctx->ast = parse_or(ctx, l_node); + return ctx->ast; } - return ctx->ast; + return l_node; } static @@ -151,12 +141,12 @@ ast_t *create_semi_node(ast_ctx_t *ctx, ast_t *l_node) ast_t *node = create_node(ctx); if (node == NULL) - return NULL; + return nullptr; node->type = N_LST; node->list.cap = DEFAULT_N_LST_CAP; node->list.nodes = (ast_t **)malloc(sizeof(ast_t *) * node->list.cap); if ((void *)node->list.nodes == NULL) - return NULL; + return nullptr; node->list.sz = 1; node->list.nodes[0] = l_node; node->tok = ctx->act_tok; @@ -171,10 +161,10 @@ ast_t *fill_semi_node(ast_ctx_t *ctx, ast_t *node) if (ctx->act_tok.type & (T_SEMICOLON | T_NEWLINE)) continue; if (!ensure_list_cap(node)) - return NULL; + return nullptr; node->list.nodes[node->list.sz] = parse_semi(ctx); if (node->list.nodes[node->list.sz] == NULL) - return NULL; + return nullptr; node->list.sz++; } return node; @@ -195,7 +185,7 @@ ast_t *parse_expression(ast_ctx_t *ctx) if (ctx->act_tok.type & (T_SEMICOLON | T_NEWLINE)) { node = create_semi_node(ctx, l_node); if (node == NULL) - return NULL; + return nullptr; ctx->ast = fill_semi_node(ctx, node); } return parse_expression(ctx); diff --git a/src/ast/conditions.c b/src/ast/conditions.c index 7b9e722..27df329 100644 --- a/src/ast/conditions.c +++ b/src/ast/conditions.c @@ -19,13 +19,13 @@ ast_t *parse_and(ast_ctx_t *ctx, ast_t *l_node) ast_t *node = create_node(ctx); if (node == NULL || l_node == NULL) - return NULL; + return nullptr; node->tok = ctx->act_tok; node->type = N_BIN; node->binary.left = l_node; - node->binary.right = parse_semi(ctx); + node->binary.right = parse_condition_and(ctx); if (node->binary.right == NULL) - return NULL; + return nullptr; return node; } @@ -34,16 +34,45 @@ ast_t *parse_or(ast_ctx_t *ctx, ast_t *l_node) ast_t *node = create_node(ctx); if (node == NULL || l_node == NULL) - return NULL; + return nullptr; node->tok = ctx->act_tok; node->type = N_BIN; node->binary.left = l_node; node->binary.right = parse_semi(ctx); if (node->binary.right == NULL) - return NULL; + return nullptr; return node; } +ast_t *parse_condition_and(ast_ctx_t *ctx) +{ + ast_t *l_node = parse_condition(ctx); + + if (l_node == NULL) + return nullptr; + if (ctx->act_tok.type == T_AND) { + ctx->ast = parse_and(ctx, l_node); + return ctx->ast; + } + return l_node; +} + +ast_t *parse_condition(ast_ctx_t *ctx) +{ + ast_t *l_node = parse_cmd(ctx); + + if (l_node == NULL) + return nullptr; + switch (ctx->act_tok.type) { + case T_PIPE: + ctx->ast = parse_pipe(ctx, l_node); + break; + default: + return l_node; + } + return ctx->ast; +} + static bool fill_else_node(ast_ctx_t *ctx, ast_t *node, buff_t *buff) { @@ -52,9 +81,7 @@ bool fill_else_node(ast_ctx_t *ctx, ast_t *node, buff_t *buff) if (node->cond.nodes2[node->cond.sz2] == NULL) return false; node->cond.sz2++; - if (!ensure_cond_cap2(node)) - return false; - return true; + return ensure_cond_cap2(node); } static @@ -69,15 +96,13 @@ bool fill_if_node(ast_ctx_t *ctx, ast_t *node, bool fill_else, buff_t *buff) if (node->cond.nodes[node->cond.sz] == NULL) return false; node->cond.sz++; - if (!ensure_cond_cap(node)) - return false; - return true; + return ensure_cond_cap(node); } static ast_t *fill_if(ast_ctx_t *ctx, ast_t *node) { - buff_t buff = { .str = NULL, 0 }; + buff_t buff = { .str = nullptr, 0 }; char *old_buff = ctx->str; bool fill_else = false; @@ -85,15 +110,15 @@ ast_t *fill_if(ast_ctx_t *ctx, ast_t *node) if (isatty(STDIN_FILENO)) WRITE_CONST(STDOUT_FILENO, IF_PROMPT); if (getline(&buff.str, &buff.sz, stdin) < 0) - return NULL; + return nullptr; buff.str[strlen(buff.str) - 1] = '\0'; if (strncmp(buff.str, "endif", 5) == 0) break; if (strncmp(buff.str, "else", 4) == 0) fill_else = true; if (!fill_if_node(ctx, node, fill_else, &buff)) - return NULL; - buff = (buff_t){ .str = NULL, 0 }; + return nullptr; + buff = (buff_t){ .str = nullptr, 0 }; } ctx->str = old_buff; return node; @@ -104,7 +129,7 @@ ast_t *parse_if(ast_ctx_t *ctx) ast_t *node = create_node(ctx); if (node == NULL) - return NULL; + return nullptr; node->tok = ctx->act_tok; node->type = N_COND; node->cond.cap = DEFAULT_N_COND_CAP; @@ -115,7 +140,7 @@ ast_t *parse_if(ast_ctx_t *ctx) node->cond.nodes2 = (ast_t **)malloc(sizeof *node->cond.nodes * node->cond.cap2); if ((void *)node->cond.nodes == NULL || (void *)node->cond.nodes2 == NULL) - return NULL; + return nullptr; node->cond.exp = parse_semi(ctx); if (node->cond.exp == NULL) return WRITE_CONST(STDERR_FILENO, "if: Too few arguments.\n"), NULL; diff --git a/src/ast/tokeniser.c b/src/ast/tokeniser.c index 6419734..448f1c6 100644 --- a/src/ast/tokeniser.c +++ b/src/ast/tokeniser.c @@ -28,8 +28,8 @@ const tokens_list_t TOKENS_LIST[] = { { T_REDIRECT, ">", 1, "T_REDIRECT" }, { T_HEREDOC, "<<", 2, "T_HEREDOC" }, { T_IN_REDIRECT, "<", 1, "T_IN_REDIRECT" }, + { T_BACKSLASH, "\\", 1, "T_BACKSLASH" }, { T_NEWLINE, "\n", 1, "T_NEWLINE"}, - { T_STAR, "*", 1, "T_STAR"}, { T_EOF, "\0", 1, "T_EOF" } }; @@ -147,7 +147,7 @@ token_t get_next_token(ast_ctx_t *ctx) while ((*ctx->str && !found_token && (!isblank(*ctx->str) || check_closable(actual_token)))) get_arg_token(ctx, &found_token, actual_token); - U_DEBUG("Token T_ARG [%.*s]%d\n", (int)(ctx->str - start), start); + U_DEBUG("Token T_ARG [%.*s]\n", (int)(ctx->str - start), start); return (token_t){ .type = T_ARG, .str = start, .sz = (size_t)(ctx->str - start) }; } diff --git a/src/builtins.h b/src/builtins.h index 78e00a3..9e8e9ef 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -9,6 +9,19 @@ #ifndef BUILTINS_H #define BUILTINS_H #include "exec.h" + #include "u_str.h" + +typedef struct { + char **cmds; + size_t size; + size_t cap; +} cmd_block_t; + +typedef struct { + buff_t *buff; + bool in_else; + ef_t *ef; +} if_ctx_t; typedef struct { char const *name; diff --git a/src/builtins/builtin_history.c b/src/builtins/builtin_history.c index ddb27b7..8389433 100644 --- a/src/builtins/builtin_history.c +++ b/src/builtins/builtin_history.c @@ -5,10 +5,15 @@ ** builtin_history */ -#include +#include +#include #include +#include +#include #include "history.h" +#include "u_str.h" +#include "utils.h" /* **Il faut deux \0 parce que dans le gettokeniser @@ -26,31 +31,24 @@ ** il vas free le buffer */ -#include -#include "utils.h" -#include -#include -#include - static char *concat_cmd_arg(char *dest, char *src) { int l; int i; - char *r_value = NULL; + char *r_value = nullptr; if (!src) { r_value = u_strdup(dest); return r_value; - } else { - l = strlen(dest); - i = strlen(src); - r_value = malloc(sizeof(char)* (i + l + 2)); - if (r_value != NULL) { - strcpy(r_value, dest); - r_value[l] = ' '; - r_value[l +1] = '\0'; - strcat(r_value, src); - } + } + l = strlen(dest); + i = strlen(src); + r_value = malloc(sizeof(char)* (i + l + 2)); + if (r_value != NULL) { + strcpy(r_value, dest); + r_value[l] = ' '; + r_value[l +1] = '\0'; + strcat(r_value, src); } return r_value; } @@ -58,12 +56,12 @@ static char *concat_cmd_arg(char *dest, char *src) char *his_last_command(char *line, his_variable_t *his_variable, his_command_t *his_command) { - char *new_line = NULL; - char *new_str = NULL; + char *new_line = nullptr; + char *new_str = nullptr; if (his_command->sz == 0){ fprintf(stderr, "%d: Event not found.\n", his_command->sz); - return NULL; + return nullptr; } new_line = concat_cmd_arg(his_command[his_command->sz - 1].command, his_command[his_command->sz - 1].arg); @@ -76,7 +74,7 @@ char *his_last_same_command(char *line, his_variable_t *his_variable, his_command_t *his_command) { char *new_line = &line[his_variable->coord_variable + 1]; - char *new_str = NULL; + char *new_str = nullptr; for (int i = his_command->sz - 1; i > 0; i--) { if (his_command[i].command == NULL) { @@ -100,7 +98,7 @@ char *his_id_command(char *line, { int id = -1 + atoi(&line[his_variable->coord_variable + 1]); char *new_line; - char *new_str = NULL; + char *new_str = nullptr; if (id < 0 || id > 100 || his_command[id].command == NULL){ fprintf(stderr, "%d: Event not found.\n", id + 1); @@ -116,18 +114,18 @@ char *his_id_command(char *line, static char *get_last_word(char *str) { - char *last_word = NULL; + char *last_word = nullptr; int last_space = 0; int x = 0; if (!str) - return NULL; + return nullptr; while (str[x] != '\0') { if (isblank(str[x])) last_space = x + 1; x++; } - last_word = malloc(sizeof(char) * (x - last_space) + 1); + last_word = malloc(sizeof(char) * ((x - last_space) + 1)); if (last_word != NULL) { last_word = strncpy(last_word, &str[last_space], x - last_space); last_word[x - last_space] = '\0'; @@ -138,15 +136,15 @@ static char *get_last_word(char *str) char *his_last_word(char *line, his_variable_t *his_variable, his_command_t *his_command) { - char *new_line = NULL; - char *new_str = NULL; + char *new_line = nullptr; + char *new_str = nullptr; if (his_command[his_command->sz - 1].arg == NULL){ new_line = get_last_word(his_command[his_command->sz - 1].command); } else new_line = get_last_word(his_command[his_command->sz - 1].arg); if (!new_line) - return NULL; + return nullptr; new_str = cat_in_str(his_variable, line, new_line); printf("%s\n", new_str); free(new_line); @@ -158,8 +156,8 @@ char *his_last_arg(char *line, his_variable_t *his_variable, his_command_t *his_command) { int id = his_command->sz - 1; - char *new_line = NULL; - char *new_str = NULL; + char *new_line = nullptr; + char *new_str = nullptr; if (!his_command[id].arg) new_line = " "; diff --git a/src/builtins/builtins_alias.c b/src/builtins/builtins_alias.c index a291630..65d8906 100644 --- a/src/builtins/builtins_alias.c +++ b/src/builtins/builtins_alias.c @@ -4,15 +4,14 @@ ** File description: ** history */ -#include -#include -#include -#include -#include "common.h" -#include "env.h" -#include "exec.h" +#include +#include +#include + #include "alias.h" +#include "common.h" +#include "exec.h" #include "utils.h" void free_alias(alias_t *alias) diff --git a/src/builtins/cd.c b/src/builtins/cd.c index f888618..0f5e68f 100644 --- a/src/builtins/cd.c +++ b/src/builtins/cd.c @@ -43,7 +43,7 @@ char *get_current_dir(void) size_t max_it = 100; if (!buffer) - return NULL; + return nullptr; while (getcwd(buffer, size) == NULL && max_it > 0) { if (errno != ERANGE) return (free(buffer), NULL); @@ -82,7 +82,7 @@ int builtins_cd(ef_t *ef, char **args) if (!(ef->out_fd == STDOUT_FILENO || ef->p_i == ef->p_sz - 1)) return RETURN_SUCCESS; - if (path == NULL || u_strcmp(args[1], "~") == 0) + if (path == NULL) path = get_env_value(ef->env, "HOME"); if (path == NULL) return RETURN_FAILURE; diff --git a/src/builtins/exit.c b/src/builtins/exit.c index 881909a..6324891 100644 --- a/src/builtins/exit.c +++ b/src/builtins/exit.c @@ -12,7 +12,7 @@ #include "env.h" #include "exec.h" -int builtins_exit(ef_t *ef, char **args __attribute__((unused))) +int builtins_exit(ef_t *ef, char **args[[gnu::unused]]) { if (ef->flags & F_PIPE && !(ef->out_fd == STDOUT_FILENO || ef->p_i == ef->p_sz - 1)) diff --git a/src/builtins/expr/expr_applicators.c b/src/builtins/expr/expr_applicators.c index 9f48e6f..1137d77 100644 --- a/src/builtins/expr/expr_applicators.c +++ b/src/builtins/expr/expr_applicators.c @@ -99,6 +99,30 @@ expr_val_t apply_gt(expr_val_t *left, expr_val_t *right) return res; } +static +expr_val_t apply_eq(expr_val_t *left, expr_val_t *right) +{ + expr_val_t res = { .type = E_VAL_INT }; + + if (left->type == E_VAL_INT && right->type == E_VAL_INT) + res.val = left->val == right->val; + else + res.val = !strcmp(left->p, right->p); + return res; +} + +static +expr_val_t apply_neq(expr_val_t *left, expr_val_t *right) +{ + expr_val_t res = { .type = E_VAL_INT }; + + if (left->type == E_VAL_INT && right->type == E_VAL_INT) + res.val = left->val != right->val; + else + res.val = strcmp(left->p, right->p); + return res; +} + const expr_op_precedence_t OPERATOR_PRECEDENCE[] = { { .name = "+", .prec = 2, apply_add }, { .name = "-", .prec = 2, apply_sub }, @@ -106,6 +130,9 @@ const expr_op_precedence_t OPERATOR_PRECEDENCE[] = { { .name = "/", .prec = 3, apply_div }, { .name = "<", .prec = 1, apply_lt }, { .name = ">", .prec = 1, apply_gt }, + { .name = "=", .prec = 1, apply_eq }, + { .name = "==", .prec = 1, apply_eq }, + { .name = "!=", .prec = 1, apply_neq }, }; const size_t OPERATOR_PRECEDENCE_COUNT = COUNT_OF(OPERATOR_PRECEDENCE); diff --git a/src/builtins/expr/expr_main.c b/src/builtins/expr/expr_main.c index 1f032cb..785905b 100644 --- a/src/builtins/expr/expr_main.c +++ b/src/builtins/expr/expr_main.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "common.h" @@ -19,14 +18,16 @@ int builtins_expr(ef_t *ef[[gnu::unused]], char **args) expr_state_t state; expr_val_t ret; - for (; args[argc] != NULL; argc++); + for (; args[argc] != nullptr; argc++); if (argc < 2) - return fprintf(stderr, "%s: missing operand\n", args[0]), -1; + return fprintf(stderr, "%s: missing operand\nTry 'expr --help' for" + " more information.", args[0]), -1; state = (expr_state_t){ .args = &args[1] }; ret = expr_run(&state, 0, 0); if (ret.type == E_VAL_ERR) return printf("%s: %s\n", args[0], ret.str), -1; - if (ret.type == E_VAL_INT && strcmp("if", args[0]) == 0) + if (ret.type == E_VAL_INT && (strcmp("if", args[0]) == 0 || + strcmp("while", args[0]) == 0)) return ret.val; if (ret.type == E_VAL_INT) printf("%ld\n", ret.val); diff --git a/src/builtins/get_loop_cmd.c b/src/builtins/get_loop_cmd.c index 83b4f32..88d16d3 100644 --- a/src/builtins/get_loop_cmd.c +++ b/src/builtins/get_loop_cmd.c @@ -5,36 +5,31 @@ ** get_loop_cmd */ +#include #include #include #include #include #include -#include -#include #include #include -#include +#include -#include "ast.h" -#include "builtins.h" #include "common.h" -#include "exec.h" -#include "redirects.h" -#include "u_str.h" -#include "u_mem.h" #include "loop.h" -#include "local.h" +#include "repl.h" +#include "u_mem.h" +#include "u_str.h" static usr_cmd_t *buffers_realloc(usr_cmd_t *usr) { - char **new_buffers = u_realloc(usr->cmds, sizeof + char **new_buffers = (char **)u_realloc((void *)usr->cmds, sizeof *usr->cmds * usr->sz, sizeof *usr->cmds * (usr->cap << 1)); - if (new_buffers == NULL) - return NULL; + if ((void *)new_buffers == NULL) + return nullptr; usr->cmds = new_buffers; usr->cap <<= 1; return usr; @@ -43,7 +38,7 @@ usr_cmd_t *buffers_realloc(usr_cmd_t *usr) static usr_cmd_t *increase_buffers(usr_cmd_t *usr, size_t *buffer_len) { - usr->cmds[usr->sz] = NULL; + usr->cmds[usr->sz] = nullptr; getline(&(usr->cmds[usr->sz]), buffer_len, stdin); *buffer_len = u_strlen(usr->cmds[usr->sz]); usr->cmds[usr->sz][*buffer_len - 1] = '\0'; @@ -52,27 +47,28 @@ usr_cmd_t *increase_buffers(usr_cmd_t *usr, size_t *buffer_len) } static -usr_cmd_t *handle_end(usr_cmd_t *us, char prompt[]) +usr_cmd_t *handle_end(usr_cmd_t *us, char const *prompt) { us->sz--; - if (!us->cmds[us->sz] || strcmp("end", us->cmds[us->sz])){ + if (!us->cmds[us->sz] || strcmp("end", us->cmds[us->sz]) != 0){ printf("%s: end not found.\n", prompt); free_array(us->cmds); - us->cmds = NULL; + us->cmds = nullptr; exit(RETURN_FAILURE); - return NULL; + return nullptr; } free(us->cmds[us->sz]); - us->cmds[us->sz] = NULL; + us->cmds[us->sz] = nullptr; return us; } static -usr_cmd_t *get_first_cmd(usr_cmd_t *usr, char prompt[], size_t *bf_len) +usr_cmd_t *get_first_cmd(exec_ctx_t *exec_ctx, usr_cmd_t *usr, + char const *prompt, size_t *bf_len) { - if (isatty(STDIN_FILENO)) + if (isatty(exec_ctx->read_fd)) printf("%s? ", prompt); - usr->cmds[usr->sz] = NULL; + usr->cmds[usr->sz] = nullptr; getline(&(usr->cmds[usr->sz]), bf_len, stdin); *bf_len = u_strlen(usr->cmds[usr->sz]); usr->cmds[usr->sz][*bf_len - 1] = '\0'; @@ -80,23 +76,24 @@ usr_cmd_t *get_first_cmd(usr_cmd_t *usr, char prompt[], size_t *bf_len) return usr; } -usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char prompt[]) +usr_cmd_t *get_usr_loop_cmd(exec_ctx_t *exec_ctx, usr_cmd_t *usr_cmd, + char const *prompt) { size_t buffer_len; if (usr_cmd == NULL) - return NULL; - usr_cmd->cmds = malloc(sizeof(char *) * usr_cmd->cap); - if (usr_cmd->cmds == NULL) - return NULL; - usr_cmd = get_first_cmd(usr_cmd, prompt, &buffer_len); - while (strcmp("end", usr_cmd->cmds[usr_cmd->sz - 1])){ - if (isatty(STDIN_FILENO)) + return nullptr; + usr_cmd->cmds = (char **)malloc(sizeof(char *) * usr_cmd->cap); + if ((void *)usr_cmd->cmds == NULL) + return nullptr; + usr_cmd = get_first_cmd(exec_ctx, usr_cmd, prompt, &buffer_len); + while (strcmp("end", usr_cmd->cmds[usr_cmd->sz - 1]) != 0){ + if (isatty(exec_ctx->read_fd)) printf("%s? ", prompt); if (usr_cmd->sz >= usr_cmd->cap) usr_cmd = buffers_realloc(usr_cmd); if (usr_cmd == NULL) - return NULL; + return nullptr; increase_buffers(usr_cmd, &buffer_len); } usr_cmd = handle_end(usr_cmd, prompt); diff --git a/src/builtins/history.c b/src/builtins/history.c index ccc1754..a070bc6 100644 --- a/src/builtins/history.c +++ b/src/builtins/history.c @@ -6,8 +6,8 @@ */ #include + #include "common.h" -#include "env.h" #include "exec.h" int builtins_history(ef_t *ef, char **args __attribute__((unused))) diff --git a/src/builtins/if.c b/src/builtins/if.c index 7a4ed34..aa115ea 100644 --- a/src/builtins/if.c +++ b/src/builtins/if.c @@ -14,6 +14,7 @@ #include "common.h" #include "debug.h" #include "exec.h" +#include "repl.h" #include "u_str.h" static @@ -21,8 +22,7 @@ int get_argc(char **args) { int i = 0; - for (; *args != NULL; args++) - i++; + for (; args[i] != nullptr; i++); return i; } @@ -33,8 +33,8 @@ bool ensure_cmds_cap(char ***cmd, size_t sz, size_t *cap) if (sz + 1 < *cap) return true; - tmp = (char **)realloc((void *)*cmd, sizeof(**cmd) * *cap << 1); - if (tmp == nullptr) + tmp = (char **)realloc(*cmd, sizeof(char *) * (*cap << 1)); + if (!tmp) return false; *cap <<= 1; *cmd = tmp; @@ -42,50 +42,124 @@ bool ensure_cmds_cap(char ***cmd, size_t sz, size_t *cap) } static -bool if_repl(ef_t *ef, char **args, char *cmd) +bool init_block(cmd_block_t *blk) { - buff_t buff = { .str = nullptr, 0 }; - char **cmds; - size_t cap = DEFAULT_N_CMD_CAP; - size_t sz = 0; + blk->size = 0; + blk->cap = DEFAULT_N_CMD_CAP; + blk->cmds = (char **)malloc(sizeof(char *) * blk->cap); + return blk->cmds != NULL; +} - if (strcmp("then", cmd) != 0) - return visitor(cmd, ef->exec_ctx), true; - cmds = (char **)malloc(cap * sizeof(char **)); - if ((void *)cmds == NULL) +static +void free_block(cmd_block_t *blk) +{ + for (size_t i = 0; i < blk->size; i++) + free(blk->cmds[i]); + free((void *)blk->cmds); +} + +static +bool append_block(cmd_block_t *blk, const char *line) +{ + if (!ensure_cmds_cap(&blk->cmds, blk->size, &blk->cap)) return false; - while (true) { - if (isatty(STDIN_FILENO)) - WRITE_CONST(ef->out_fd, IF_PROMPT); - if (getline(&buff.str, &buff.sz, stdin) == -1) - break; - if (!ensure_cmds_cap(&cmds, sz, &cap)) - return false; - cmds[sz] = strdup(buff.str); + blk->cmds[blk->size] = strdup(line); + blk->size++; + return true; +} + +static +bool handle_if_buff(if_ctx_t *ctx, cmd_block_t *then_blk, + cmd_block_t *else_blk, bool *in_else) +{ + if (strcmp(ctx->buff->str, "else") == 0) { + *in_else = true; + return true; } + if (strcmp(ctx->buff->str, "endif") == 0) + return false; + if (!*in_else) { + if (!append_block(then_blk, ctx->buff->str)) + return false; + } else + if (!append_block(else_blk, ctx->buff->str)) + return false; + return true; +} + +static +bool read_if_blocks(ef_t *ef, if_ctx_t *ctx, cmd_block_t *then_blk, + cmd_block_t *else_blk) +{ + bool in_else = false; + + while (true) { + if (isatty(ef->exec_ctx->read_fd)) + WRITE_CONST(ctx->ef->out_fd, IF_PROMPT); + if (getline(&ctx->buff->str, &ctx->buff->sz, stdin) == -1) + return false; + ctx->buff->str[strcspn(ctx->buff->str, "\n")] = '\0'; + if (strcmp(ctx->buff->str, "else") == 0) { + in_else = true; + continue; + } + if (strcmp(ctx->buff->str, "endif") == 0) + break; + if (!handle_if_buff(ctx, then_blk, else_blk, &in_else)) + return false; + } + return true; +} + +static +void exec_block(cmd_block_t *blk, ef_t *ef) +{ + for (size_t i = 0; i < blk->size; i++) + visitor(blk->cmds[i], ef->exec_ctx); +} + +static +bool handle_if_logic(ef_t *ef, bool cond, char *last) +{ + if_ctx_t ctx = {.buff = &(buff_t){ .str = nullptr, .sz = 0 }, .ef = ef}; + cmd_block_t then_blk; + cmd_block_t else_blk; + + if (strcmp("then", last) != 0) + return cond ? visitor(last, ef->exec_ctx), true : true; + if (!init_block(&then_blk) || !init_block(&else_blk)) + return false; + if (!read_if_blocks(ef, &ctx, &then_blk, &else_blk)) + return false; + if (cond) + exec_block(&then_blk, ef); + else + exec_block(&else_blk, ef); + free_block(&then_blk); + free_block(&else_blk); + free(ctx.buff->str); return true; } int builtins_if(ef_t *ef, char **args) { int result; - char *cmd; + char *last; if (args[1] == NULL) return WRITE_CONST(STDERR_FILENO, "if: Too few arguments.\n"), RETURN_FAILURE; if (args[2] == NULL) - return WRITE_CONST(STDERR_FILENO, "if: Empty if\n"), RETURN_FAILURE; - cmd = strdup(args[get_argc(args) - 1]); - if (cmd == NULL) + return WRITE_CONST(STDERR_FILENO, "if: Empty if.\n"), RETURN_FAILURE; + last = strdup(args[get_argc(args) - 1]); + if (!last) return RETURN_FAILURE; args[get_argc(args) - 1] = nullptr; result = builtins_expr(ef, args); U_DEBUG("If expr result [%d]\n", result); if (result == -1) - return free(cmd), RETURN_FAILURE; - if (result) - if (!if_repl(ef, args, cmd)) - return free(cmd), RETURN_FAILURE; - return free(cmd), RETURN_SUCCESS; + return free(last), RETURN_FAILURE; + if (!handle_if_logic(ef, result != 0, last)) + return free(last), RETURN_FAILURE; + return free(last), RETURN_SUCCESS; } diff --git a/src/builtins/local.c b/src/builtins/local.c index 29b7d1c..f30404d 100644 --- a/src/builtins/local.c +++ b/src/builtins/local.c @@ -6,16 +6,15 @@ */ #include -#include -#include -#include #include +#include +#include +#include +#include "builtins_handler.h" #include "common.h" -#include "env.h" -#include "exec.h" -#include "u_str.h" #include "u_mem.h" +#include "u_str.h" bool check_local_var(char *var, char *func_name) { @@ -33,14 +32,14 @@ char *get_local_value(local_t *local, char const *key) int key_len = u_strlen(key); for (size_t i = 0; i < local->sz; i++) { - if (local->local_var[i] == NULL) + if (local->local_var[i] == nullptr) continue; if (u_strcspn(local->local_var[i], '\t') != key_len) continue; if (u_strcmp(local->local_var[i], key) == 0) return local->local_var[i] + key_len + 1; } - return NULL; + return nullptr; } local_t create_local(void) @@ -48,9 +47,9 @@ local_t create_local(void) local_t local = {.sz = 0, .cap = 2}; local.local_var = (char **)malloc(sizeof(char *) * local.cap); - if (local.local_var == NULL) - return (local_t){.sz = 0, .cap = 2, .local_var = NULL}; - local.local_var[local.sz] = NULL; + if (local.local_var == nullptr) + return (local_t){.sz = 0, .cap = 2, .local_var = nullptr}; + local.local_var[local.sz] = nullptr; local.sz++; return local; } @@ -58,7 +57,7 @@ local_t create_local(void) static bool ensure_local_capacity(local_t *local) { - char **new_ptr = NULL; + char **new_ptr = nullptr; if (local->sz < local->cap) return true; @@ -74,17 +73,17 @@ bool ensure_local_capacity(local_t *local) bool set_local(local_t *local, char *var, char *value) { - char *new_loc = NULL; + char *new_loc = nullptr; size_t key_len = u_strlen(var); size_t value_len = u_strlen(value); - if (get_local_value(local, var) != NULL) + if (get_local_value(local, var) != nullptr) unset_local(local, var); local->sz++; if (!ensure_local_capacity(local)) return false; new_loc = malloc(sizeof(char) * (key_len + value_len + 2)); - if (new_loc == NULL) + if (new_loc == nullptr) return false; u_bzero(new_loc, key_len + value_len + 2); u_strcpy(new_loc, var); @@ -92,7 +91,7 @@ bool set_local(local_t *local, char *var, char *value) if (value_len > 0) u_strcpy(new_loc + key_len + 1, value); local->local_var[local->sz - 1] = new_loc; - local->local_var[local->sz] = NULL; + local->local_var[local->sz] = nullptr; return true; } @@ -110,7 +109,7 @@ bool unset_local(local_t *local, char *var) int key_len = u_strlen(var); for (size_t i = 0; i < local->sz; i++) { - if (local->local_var[i] == NULL) + if (local->local_var[i] == nullptr) continue; if (u_strcspn(local->local_var[i], '\t') != key_len) continue; diff --git a/src/builtins/loop.c b/src/builtins/loop.c index 41849b5..7925195 100644 --- a/src/builtins/loop.c +++ b/src/builtins/loop.c @@ -4,34 +4,34 @@ ** File description: ** foreach */ + +#include +#include #include #include #include #include #include -#include -#include #include #include -#include +#include #include "ast.h" #include "builtins.h" #include "common.h" +#include "debug.h" #include "exec.h" -#include "redirects.h" -#include "u_str.h" -#include "u_mem.h" -#include "loop.h" #include "local.h" +#include "loop.h" +#include "u_str.h" -void exit_child(int sig __attribute__((unused))) +void exit_child(int sig[[gnu::unused]]) { _exit(sig); } static -bool checking_for_error(ef_t *ef, char **args) +bool checking_for_error(char **args) { if (my_array_len(args) < 3) return (WRITE_CONST(STDERR_FILENO, "foreach: Too few arguments.\n"), @@ -42,7 +42,7 @@ bool checking_for_error(ef_t *ef, char **args) } static -bool checking_while_error(ef_t *ef, char **args) +bool checking_while_error(char **args) { if (my_array_len(args) < 2) return (WRITE_CONST(STDERR_FILENO, "while: Too few arguments.\n"), @@ -69,7 +69,7 @@ int foreach_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmds) int status = 0; char **save_cmds = arraydup(usr_cmds->cmds); - if (save_cmds == NULL) + if ((void *)save_cmds == nullptr) exit(84); for (int i = 2; args[i]; i++){ if (!set_local(ef->exec_ctx->local, args[1], args[i])) @@ -83,45 +83,53 @@ int foreach_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmds) } static -int while_loop(ef_t *ef, usr_cmd_t *usr_cmds) +int while_loop(ef_t *ef, usr_cmd_t *usr_cmds, char **args) { int status = 0; char **save_cmds = arraydup(usr_cmds->cmds); + int expr_result; - if (save_cmds == NULL) + if ((void *)save_cmds == nullptr) exit(84); - while (true){ + expr_result = builtins_expr(ef, args); + if (expr_result == -1) + return RETURN_FAILURE; + while (expr_result != 0) { + U_DEBUG("While expr result [%d]\n", expr_result); status = do_a_lap(ef, usr_cmds->cmds); free_array(usr_cmds->cmds); usr_cmds->cmds = arraydup(save_cmds); + expr_result = builtins_expr(ef, args); + if (expr_result == -1) + return RETURN_FAILURE; } free_array(save_cmds); return status; } static -int choose_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmd, char prompt[]) +int choose_loop(ef_t *ef, char **args, usr_cmd_t *usr_cmd, char const *prompt) { if (strcmp(prompt, "foreach") == 0) return foreach_loop(ef, args, usr_cmd); - return while_loop(ef, usr_cmd); + return while_loop(ef, usr_cmd, args); } static -void launch_loop(ef_t *ef, char **args, char prompt[]) +void launch_loop(ef_t *ef, char **args, char const *prompt) { int status = RETURN_FAILURE; usr_cmd_t *usr_cmds = malloc(sizeof(usr_cmd_t)); ef->exec_ctx->local->in_a_loop = true; - if (usr_cmds == NULL) + if (usr_cmds == nullptr) exit(84); usr_cmds->cap = 2; usr_cmds->sz = 0; signal(SIGINT, exit_child); signal(EOF, exit_child); - usr_cmds = get_usr_loop_cmd(usr_cmds, prompt); - if (usr_cmds == NULL) + usr_cmds = get_usr_loop_cmd(ef->exec_ctx, usr_cmds, prompt); + if (usr_cmds == nullptr) exit(84); status = choose_loop(ef, args, usr_cmds, prompt); free_array(usr_cmds->cmds); @@ -134,7 +142,7 @@ int builtins_foreach(ef_t *ef, char **args) int status = 0; pid_t pid; - if (checking_for_error(ef, args)) + if (checking_for_error(args)) return RETURN_FAILURE; pid = fork(); if (pid == 0) @@ -152,7 +160,7 @@ int builtins_while(ef_t *ef, char **args) int status = 0; pid_t pid; - if (checking_while_error(ef, args)) + if (checking_while_error(args)) return RETURN_FAILURE; pid = fork(); if (pid == 0) diff --git a/src/builtins/repeat.c b/src/builtins/repeat.c index ded5289..2affa22 100644 --- a/src/builtins/repeat.c +++ b/src/builtins/repeat.c @@ -4,13 +4,12 @@ ** File description: ** repeat */ -#include -#include -#include -#include + #include -#include #include +#include +#include +#include #include "builtins.h" #include "common.h" @@ -18,7 +17,7 @@ #include "u_str.h" static -bool checking_error(ef_t *ef, char **args, long *nb_loop) +bool checking_error(char **args, long *nb_loop) { char *end; @@ -39,7 +38,7 @@ int builtins_repeat(ef_t *ef, char **args) int status = 0; pid_t pid; - if (checking_error(ef, args, &nb_loop)) + if (checking_error(args, &nb_loop)) return RETURN_FAILURE; pid = fork(); if (pid == 0){ diff --git a/src/builtins/unset.c b/src/builtins/unset.c index ced6864..9944e6c 100644 --- a/src/builtins/unset.c +++ b/src/builtins/unset.c @@ -5,14 +5,12 @@ ** unset */ -#include -#include -#include -#include #include +#include +#include +#include #include "common.h" -#include "env.h" #include "exec.h" #include "u_str.h" diff --git a/src/builtins/which.c b/src/builtins/which.c index 618d8d3..fa0f3da 100644 --- a/src/builtins/which.c +++ b/src/builtins/which.c @@ -31,13 +31,15 @@ bool search_builtin(ef_t *ef, char *arg) if (u_strlen(BUILTINS[i].name) != (int)strlen(arg)) continue; if (u_strcmp(BUILTINS[i].name, arg) == 0) - return dprintf(ef->out_fd, "%s is a shell built-in\n", arg), true; + return dprintf(ef->out_fd, "%s: shell built-in command.\n", arg), + true; } for (size_t i = 0; i < OOTHER_BUILTINS_SZ; i++) { if (u_strlen(OOTHER_BUILTINS[i]) != (int)strlen(arg)) continue; if (u_strcmp(OOTHER_BUILTINS[i], arg) == 0) - return dprintf(ef->out_fd, "%s is a shell built-in\n", arg), true; + return dprintf(ef->out_fd, "%s: shell built-in command.\n", arg), + true; } return false; } @@ -54,12 +56,13 @@ bool search_cmd(ef_t *ef, char *arg) return free(alias_path.str), NULL; parse_alias(&alias_path.str, &alias_path.sz, ef->exec_ctx->alias); if (strcmp(arg, alias_path.str) != 0) - return dprintf(ef->out_fd, "%s: aliased to %s\n", arg, + return dprintf(ef->out_fd, "%s:\t aliased to %s\n", arg, alias_path.str), true; if (search_builtin(ef, arg)) return true; if (strcmp(arg, bin_path) != 0) return dprintf(ef->out_fd, "%s\n", bin_path), true; + fprintf(stderr, "%s: Command not found.\n", arg); free(alias_path.str); return true; } diff --git a/src/builtins/yes.c b/src/builtins/yes.c index 2790f4e..58e37ea 100644 --- a/src/builtins/yes.c +++ b/src/builtins/yes.c @@ -4,19 +4,20 @@ ** File description: ** yes */ -#include -#include -#include -#include + #include -#include #include +#include +#include +#include +#include +#include #include "builtins.h" #include "common.h" #include "exec.h" -#include "u_str.h" #include "u_mem.h" +#include "u_str.h" static int len_buffer(char **args) @@ -31,13 +32,13 @@ int len_buffer(char **args) static char *define_prompt(char **args) { - char *buffer = NULL; + char *buffer = nullptr; if (args[1] == NULL) return u_strdup("y\n"); buffer = malloc(sizeof(char) * (len_buffer(args) + 1)); if (buffer == NULL) - return NULL; + return nullptr; u_bzero(buffer, len_buffer(args) + 1); strcpy(buffer, args[1]); buffer[strlen(buffer)] = ' '; @@ -58,14 +59,12 @@ int builtins_yes(ef_t *ef, char **args) if (buffer == NULL) return RETURN_FAILURE; pid = fork(); - if (pid == 0){ - while (true){ - signal(SIGINT, exit_child); + if (pid == 0) { + signal(SIGINT, exit_child); + while (true) write(ef->out_fd, buffer, strlen(buffer)); - } - exit(RETURN_SUCCESS); } else - wait(NULL); + wait(nullptr); free(buffer); return RETURN_SUCCESS; } diff --git a/src/builtins_handler.h b/src/builtins_handler.h index ac137a9..5bb4fa5 100644 --- a/src/builtins_handler.h +++ b/src/builtins_handler.h @@ -24,6 +24,9 @@ typedef struct { bool is_running; struct termios saved_term_settings; local_t *local; + opt_t *opt; + int read_fd; + int isatty; } exec_ctx_t; size_t update_command(char **buffer, diff --git a/src/common.h b/src/common.h index a515665..7959c82 100644 --- a/src/common.h +++ b/src/common.h @@ -7,7 +7,9 @@ #ifndef COMMON_H #define COMMON_H - #include "exec.h" + #include + + #define PROMPT_HEADER "ā”Œā”€[" #define IF_PROMPT "if? " enum { @@ -15,5 +17,9 @@ enum { RETURN_FAILURE = 1 }; -void free_everything(exec_ctx_t *exec_ctx); +typedef struct { + uint8_t flags; + char *script_file; + char *cmd; +} opt_t; #endif /* COMMON_H */ diff --git a/src/exec.c b/src/exec.c index f4dcc1a..09cba4b 100644 --- a/src/exec.c +++ b/src/exec.c @@ -13,13 +13,13 @@ #include #include +#include "args.h" #include "ast.h" #include "builtins.h" #include "common.h" #include "debug.h" #include "env.h" #include "exec.h" -#include "globbing.h" #include "path.h" #include "repl.h" #include "u_mem.h" @@ -75,7 +75,7 @@ char **parse_args(ef_t *ef, ast_t *node) * DEFAULT_ARGS_CAP), .sz = 0, .cap = DEFAULT_ARGS_CAP }; if (!args.args) - return NULL; + return nullptr; for (size_t i = 0; i < node->vector.sz; i++) { if (ef->skip_sz > 0 && i >= ef->skip_i && i < ef->skip_i + ef->skip_sz) continue; @@ -83,8 +83,8 @@ char **parse_args(ef_t *ef, ast_t *node) return free((void *)args.args), NULL; } if (!ensure_args_capacity(&args)) - return NULL; - args.args[args.sz] = NULL; + return nullptr; + args.args[args.sz] = nullptr; return args.args; } diff --git a/src/loop.h b/src/loop.h index b8f8544..3832047 100644 --- a/src/loop.h +++ b/src/loop.h @@ -10,11 +10,14 @@ #include #include + #include "exec.h" + typedef struct { size_t sz; size_t cap; char **cmds; } usr_cmd_t; -usr_cmd_t *get_usr_loop_cmd(usr_cmd_t *usr_cmd, char prompt[]); +usr_cmd_t *get_usr_loop_cmd(exec_ctx_t *exec_ctx, usr_cmd_t *usr_cmd, + char const *prompt); #endif /* LOOP_H */ diff --git a/src/main.c b/src/main.c index 3bf4d19..e525dab 100644 --- a/src/main.c +++ b/src/main.c @@ -5,12 +5,52 @@ ** _ */ +#include +#include + +#include "common.h" #include "debug.h" #include "shell.h" -int main(int ac __attribute__((unused)), char **av __attribute__((unused)), - char **env) +const char OPT_FLAGS[] = "hc:"; + +static +void print_usages(FILE *file, char *bin) { - U_DEBUG_MSG("Debug mode activated.\n"); - return shell(env); + fprintf(file, "Usage: %s [-c command] [-dixv]" + " [file]\n", bin); +} + +static +bool parse_args(opt_t *opt, int ac, char **av) +{ + for (int o = getopt(ac, av, OPT_FLAGS); o != -1; + o = getopt(ac, av, OPT_FLAGS)) { + switch (o) { + case 'h': + exit((print_usages(stdout, av[0]), RETURN_SUCCESS)); + case 'c': + opt->cmd = optarg; + break; + default: + return print_usages(stderr, av[0]), false; + } + } + if (optind < ac) { + opt->script_file = av[optind]; + U_DEBUG("Script file [%s]\n", opt->script_file); + } else { + U_DEBUG_MSG("No script file provided.\n"); + } + return true; +} + +int main(int ac, char **av, char **env) +{ + opt_t opt = { 0, .script_file = nullptr, .cmd = nullptr }; + + U_DEBUG_MSG("Debug mode activated.\n"); + if (!parse_args(&opt, ac, av)) + return RETURN_FAILURE; + return shell(&opt, env); } diff --git a/src/parse_history.c b/src/parse_history.c index 16e5bae..6fde9d7 100644 --- a/src/parse_history.c +++ b/src/parse_history.c @@ -4,20 +4,16 @@ ** File description: ** his for history */ + #include -#include #include #include -#include #include +#include -#include "utils.h" -#include "common.h" -#include "env.h" -#include "exec.h" -#include "u_mem.h" -#include "u_str.h" #include "history.h" +#include "u_str.h" +#include "utils.h" const parsing_history_t tab_fnct[] = { {"!!", &his_last_command}, diff --git a/src/readline.c b/src/readline.c index 9ebef6d..f6a845f 100644 --- a/src/readline.c +++ b/src/readline.c @@ -16,6 +16,7 @@ #include "common.h" #include "readline.h" +#include "debug.h" #include "repl.h" #include "u_str.h" @@ -70,23 +71,24 @@ bool ensure_buff_capacity(buff_t *buff) } static -bool append_null_terminator(buff_t *buff) +bool append_null_terminator(buff_t *buff, exec_ctx_t *exec_ctx) { if (!ensure_buff_av_capacity(buff, 1)) return false; buff->str[buff->sz - 1] = '\0'; buff->sz++; - if (isatty(STDIN_FILENO)) + if (isatty(exec_ctx->read_fd)) WRITE_CONST(STDOUT_FILENO, "\n"); return true; } static -int8_t handle_line_buff(buff_t *buff, char *read_buff, ssize_t read_size) +int8_t handle_line_buff(exec_ctx_t *exec_ctx, buff_t *buff, char *read_buff, + ssize_t read_size) { - if (handle_keys(buff, read_buff)) + if (handle_keys(exec_ctx, buff, read_buff)) return RETURN_SUCCESS; - if (isatty(STDIN_FILENO) && str_printable(read_buff, read_size)) + if (isatty(exec_ctx->read_fd) && str_printable(read_buff, read_size)) write(STDOUT_FILENO, read_buff, read_size); if (!ensure_buff_av_capacity(buff, read_size)) return RETURN_FAILURE; @@ -96,7 +98,7 @@ int8_t handle_line_buff(buff_t *buff, char *read_buff, ssize_t read_size) return -1; } -bool readline(buff_t *buff) +bool readline(exec_ctx_t *exec_ctx, buff_t *buff, int fd) { char read_buff[2] = ""; ssize_t read_size = 0; @@ -105,13 +107,13 @@ bool readline(buff_t *buff) return false; while (strchr(read_buff, '\n') == NULL && *read_buff != '\r') { memset(read_buff, '\0', sizeof read_buff); - read_size = read(STDIN_FILENO, &read_buff, sizeof read_buff - 1); + read_size = read(fd, &read_buff, sizeof read_buff - 1); if (read_size < 0) return false; if (read_size == 0) return true; - if (handle_line_buff(buff, read_buff, read_size) > -1) + if (handle_line_buff(exec_ctx, buff, read_buff, read_size) > -1) return true; } - return append_null_terminator(buff); + return append_null_terminator(buff, exec_ctx); } diff --git a/src/readline.h b/src/readline.h index 67d6510..ada2c11 100644 --- a/src/readline.h +++ b/src/readline.h @@ -10,7 +10,8 @@ #define BUFF_INIT_SZ 16 #include + #include "exec.h" #include "u_str.h" -bool readline(buff_t *buff); +bool readline(exec_ctx_t *exec_ctx, buff_t *buff, int fd); #endif /* READLINE */ diff --git a/src/repl.c b/src/repl.c index 217c76f..8f961f1 100644 --- a/src/repl.c +++ b/src/repl.c @@ -6,19 +6,47 @@ */ #include +#include #include #include +#include "common.h" #include "exec.h" +#include "repl.h" #include "u_str.h" +#include "vt100_esc_codes.h" + + +void print_shell_prompt(exec_ctx_t *exec_ctx) +{ + env_t *env_ptr = exec_ctx->env; + char const *ps1 = get_env_value(env_ptr, "PS1"); + char hostname[64]; + + if (ps1 == nullptr) { + if (gethostname(hostname, 64) < 0) + return; + printf(BLUE PROMPT_HEADER GREEN "%s" RESET "@" CYAN "%s" BLUE "] " + RESET "-" BLUE " [" RESET "%s" BLUE + "] " RESET "-" BLUE " [" YELLOW "%d" BLUE + "]\n└─[" PURPLE "$" BLUE "] " RESET, + get_env_value(env_ptr, "USER"), + hostname, + get_env_value(env_ptr, "PWD"), + exec_ctx->history_command->sz); + } else + printf("%s", ps1); +} void init_shell_repl(exec_ctx_t *exec_ctx) { struct termios repl_settings; + setvbuf(stdout, nullptr, _IONBF, 0); signal(SIGINT, SIG_IGN); exec_ctx->is_running = true; - if (isatty(STDIN_FILENO)) { + if (isatty(exec_ctx->read_fd)) { + WRITE_CONST(STDOUT_FILENO, BLINKING_VERTICAL_CURSOR); tcgetattr(STDIN_FILENO, &repl_settings); exec_ctx->saved_term_settings = repl_settings; repl_settings.c_iflag = IXON; @@ -33,20 +61,20 @@ void restore_term_flags(exec_ctx_t *exec_ctx) } static -void ignore_sigint(void) +void ignore_sigint(exec_ctx_t *exec_ctx) { WRITE_CONST(STDIN_FILENO, "\n"); - WRITE_CONST(STDOUT_FILENO, SHELL_PROMPT); + print_shell_prompt(exec_ctx); } -bool handle_keys(buff_t *buff, char *read_buff) +bool handle_keys(exec_ctx_t *exec_ctx, buff_t *buff, char const *read_buff) { switch (*read_buff) { case CTRL('d'): buff->sz = 0; return true; case CTRL('c'): - ignore_sigint(); + ignore_sigint(exec_ctx); return false; default: return false; diff --git a/src/repl.h b/src/repl.h index 25f4868..d046ee7 100644 --- a/src/repl.h +++ b/src/repl.h @@ -12,5 +12,6 @@ void init_shell_repl(exec_ctx_t *exec_ctx); void restore_term_flags(exec_ctx_t *exec_ctx); -bool handle_keys(buff_t *buff, char *read_buff); +bool handle_keys(exec_ctx_t *exec_ctx, buff_t *buff, char const *read_buff); +void print_shell_prompt(exec_ctx_t *exec_ctx); #endif /* REPL_H */ diff --git a/src/shell.c b/src/shell.c index 92cb6a3..68ee13f 100644 --- a/src/shell.c +++ b/src/shell.c @@ -5,6 +5,7 @@ ** _ */ +#include #include #include #include @@ -20,7 +21,7 @@ #include "repl.h" #include "shell.h" #include "u_str.h" -#include "visitor.h" +#include "utils.h" __attribute__((unused)) static @@ -45,20 +46,20 @@ void check_basic_error(char const *buffer) } static -void write_prompt(int is_a_tty) +void write_prompt(int is_a_tty, exec_ctx_t *exec_ctx) { if (is_a_tty) - WRITE_CONST(STDOUT_FILENO, SHELL_PROMPT); + print_shell_prompt(exec_ctx); } static bool change_shell_command(buff_t *buff, exec_ctx_t *exec_ctx) { - char *tmp_buff = NULL; + char *tmp_buff = nullptr; size_t buffer_len; buff->sz = 0; - if (!readline(buff)) + if (!readline(exec_ctx, buff, exec_ctx->read_fd)) return false; if (!buff->sz) return false; @@ -78,15 +79,14 @@ bool change_shell_command(buff_t *buff, exec_ctx_t *exec_ctx) static int shell_loop(int is_a_tty, exec_ctx_t *exec_ctx) { - buff_t buff = { .str = NULL, 0, .cap = BUFF_INIT_SZ }; + buff_t buff = { .str = nullptr, 0, .cap = BUFF_INIT_SZ }; init_shell_repl(exec_ctx); while (true) { - write_prompt(is_a_tty); + write_prompt(is_a_tty, exec_ctx); if (!change_shell_command(&buff, exec_ctx)) return exec_ctx->history->last_exit_code; } - free(exec_ctx->history_command); return free(buff.str), exec_ctx->history->last_exit_code; } @@ -96,10 +96,10 @@ his_command_t *init_cmd_history(void) his_command_t *cmd_history = malloc(sizeof(his_command_t) * 100); if (cmd_history == NULL) - return NULL; + return nullptr; for (int i = 0; i != 100; i++){ - cmd_history[i].arg = NULL; - cmd_history[i].command = NULL; + cmd_history[i].arg = nullptr; + cmd_history[i].command = nullptr; cmd_history[i].id = i; } cmd_history->sz = 0; @@ -121,24 +121,37 @@ bool error_in_init(exec_ctx_t *exec_ctx) return false; } -#include -int shell(char **env_ptr) +static +int get_read_fd(opt_t *opt) +{ + int fd; + + if (opt->script_file == NULL) + return STDIN_FILENO; + fd = open(opt->script_file, O_RDONLY); + if (fd < 0) + return perror(opt->script_file), -1; + return fd; +} + +int shell(opt_t *opt, char **env_ptr) { alias_t alias = init_alias(); env_t env = parse_env(env_ptr); - history_t history = { .cmd_history = NULL, .last_exit_code = 0, - .last_chdir = NULL}; + history_t history = { .cmd_history = nullptr, .last_exit_code = 0, + .last_chdir = nullptr}; his_command_t *cmd_history = init_cmd_history(); local_t local = create_local(); - exec_ctx_t exec_ctx = {.env = &env, .local = &local, - .history = &history, .history_command = cmd_history, .alias = &alias}; + exec_ctx_t exec_ctx = {.env = &env, .local = &local, .opt = opt, + .read_fd = get_read_fd(opt), .history = &history, + .history_command = cmd_history, .alias = &alias}; int shell_result; - if (error_in_init(&exec_ctx) == true) + if (exec_ctx.read_fd == -1 || (int)error_in_init(&exec_ctx)) return RETURN_FAILURE; U_DEBUG_CALL(debug_env_entries, &env); - shell_result = shell_loop(isatty(STDIN_FILENO), &exec_ctx); - if (isatty(STDIN_FILENO)) { + shell_result = shell_loop(isatty(exec_ctx.read_fd), &exec_ctx); + if (isatty(exec_ctx.read_fd)) { WRITE_CONST(STDOUT_FILENO, "exit\n"); restore_term_flags(&exec_ctx); } diff --git a/src/shell.h b/src/shell.h index ec0f497..eea4258 100644 --- a/src/shell.h +++ b/src/shell.h @@ -7,9 +7,7 @@ #ifndef SHELL_H #define SHELL_H - #include "vt100_esc_codes.h" - - #define SHELL_PROMPT RED "|> " RESET + #include "common.h" typedef struct { char **cmd_history; @@ -17,5 +15,5 @@ typedef struct { char *last_chdir; } history_t; -int shell(char **env); +int shell(opt_t *opt, char **env); #endif /* SHELL_H */ diff --git a/src/utils.h b/src/utils.h index 3431f06..703c7cb 100644 --- a/src/utils.h +++ b/src/utils.h @@ -9,10 +9,12 @@ #ifndef UTILS_H #define UTILS_H #include "history.h" - #include "u_str.h" + #include "exec.h" char *strn_to_ndup(int start, int size, char *str); bool is_a_token(char *str, int index_str); char *cat_in_str(his_variable_t *his_variable, char *str, char *cpy); int len_array(char **array); +char *insert_str(const char *base, const char *insert, size_t pos); +void free_everything(exec_ctx_t *exec_ctx); #endif /* UTILS_H */ diff --git a/src/utils/insert_str.c b/src/utils/insert_str.c new file mode 100644 index 0000000..baf6f51 --- /dev/null +++ b/src/utils/insert_str.c @@ -0,0 +1,29 @@ +/* +** EPITECH PROJECT, 2025 +** __ +** File description: +** _ +*/ + +#include +#include +#include + +char *insert_str(const char *base, const char *insert, size_t pos) +{ + size_t base_len = strlen(base); + size_t insert_len = strlen(insert); + size_t new_len; + char *res; + + if (pos >= base_len) + pos = base_len; + new_len = base_len - 1 + insert_len; + res = malloc(sizeof(char) * (new_len + 1)); + if (res == nullptr) + return nullptr; + memcpy(res, base, pos); + strncpy(res + pos, insert, insert_len); + memcpy(res + pos + insert_len, base + pos + 1, base_len - pos - 1 + 1); + return res; +} diff --git a/src/visit_condition.c b/src/visit_condition.c index 83e7cf0..fcf78fa 100644 --- a/src/visit_condition.c +++ b/src/visit_condition.c @@ -21,13 +21,9 @@ int visit_and(ef_t *ef, ast_t *node) if (!node->binary.left || !node->binary.right) return WRITE_CONST(STDERR_FILENO, "Invalid null l/r command.\n"), RETURN_FAILURE; - result = visit_list(ef, node->binary.left); - if (!result) { - if (node->binary.right->tok.type & (T_AND | T_OR)) - result = visit_condition(ef, node->binary.right); - else - result = visit_list(ef, node->binary.right); - } + result = visit_condition(ef, node->binary.left); + if (!result) + result = visit_condition(ef, node->binary.right); return result; } @@ -38,13 +34,10 @@ int visit_or(ef_t *ef, ast_t *node) if (!node->binary.left || !node->binary.right) return WRITE_CONST(STDERR_FILENO, "Invalid null l/r command.\n"), RETURN_FAILURE; - result = visit_list(ef, node->binary.left); + result = visit_condition(ef, node->binary.left); if (result) { ef->history->last_exit_code = 0; - if (node->binary.right->tok.type & (T_AND | T_OR)) - result = visit_condition(ef, node->binary.right); - else - result = visit_list(ef, node->binary.right); + result = visit_condition(ef, node->binary.right); } return result; } diff --git a/src/visitor.c b/src/visitor.c index fff12a1..4c4217a 100644 --- a/src/visitor.c +++ b/src/visitor.c @@ -116,7 +116,7 @@ int visit_condition(ef_t *ef, ast_t *node) case T_OR: return visit_or(ef, node); default: - return RETURN_FAILURE; + return visit_list(ef, node); } } @@ -200,7 +200,7 @@ int visitor(char *buffer, exec_ctx_t *exec_ctx) return RETURN_FAILURE; result = visitor_launcher(&ef); if (ef.flags & F_EXIT) - builtins_exit(&ef, NULL); + builtins_exit(&ef, nullptr); free_ast(&ctx); return result == -1 ? RETURN_FAILURE : result; } diff --git a/src/vt100_esc_codes.h b/src/vt100_esc_codes.h index a2860b7..24dd8f3 100644 --- a/src/vt100_esc_codes.h +++ b/src/vt100_esc_codes.h @@ -11,6 +11,9 @@ #define ESC "\033" #define CFMT(n) ESC "[" #n "m" + // special + #define BLINKING_VERTICAL_CURSOR ESC "[5 q" + // move #define MOVE_RIGHT(n) ESC "[" #n "C" diff --git a/ulib/str/arraydup.c b/ulib/str/arraydup.c index 2bf8d11..c32dda4 100644 --- a/ulib/str/arraydup.c +++ b/ulib/str/arraydup.c @@ -9,16 +9,16 @@ char **arraydup(char **array) { - char **dup_array = NULL; + char **dup_array = nullptr; int i = 0; - if (array == NULL) - return NULL; - dup_array = malloc(sizeof(char *) * (my_array_len(array) + 1)); - if (dup_array == NULL) - return NULL; - for (; array[i] != NULL; i++) + if (array == nullptr) + return nullptr; + dup_array = (char **)malloc(sizeof(char *) * (my_array_len(array) + 1)); + if (dup_array == nullptr) + return nullptr; + for (; array[i] != nullptr; i++) dup_array[i] = u_strdup(array[i]); - dup_array[i] = NULL; + dup_array[i] = nullptr; return dup_array; } diff --git a/validation_tests.py b/validation_tests.py index e004941..3629182 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -39,7 +39,7 @@ TESTS = [ cmds=[ "/bin/ls\n", "/../bin/ls\n", - # "~/../../bin/sh --version\n", + "~/../../bin/ls\n", "fixtures/exec.sh\n", ], depends_on=("ARGS",) @@ -124,7 +124,7 @@ TESTS = [ "echo kek | grep kek\n", "ls | grep Makefile\n", "who | wc -l\n", - "ls | | cat\n", # Syntax error + "ls | | cat\n", ], depends_on=("ARGS",) ), @@ -196,59 +196,121 @@ TESTS = [ "aa||aa\n", "ls||aa\n", "&&\n", + "ls && ls || ls && ls\n", + "ls && ls a || ls && ls\n", + "ls && ls || ls && ls a\n", + "ls && ls || ls && a\n", + "ls aa && ls || ls\n", ], depends_on=() ), Test( - key="QUOTES", - name="quotes handling", + key="BACKTICKS", + name="backticks", cmds=[ - "echo 'plop'\n", - "echo \"plop\"\n", - "echo 'plop kek'\n", - "echo \"plop kek\"\n", - "echo 'plop\"kek'\"\n", - "echo \"plop'kek\"'\n", - "echo \"Hello $USER\"\n", - "echo 'Hello $USER'\n", - "echo Hello $USER\n", - "echo \"$USER\"\n", - "echo '$USER'\n", - ], - depends_on=("ENV_EXPANSION",) + "echo `ls`\n", + "echo `ls\n", + "echo ls`\n", + ], + depends_on=() ), Test( - key="VAR_INTERP", - name="variable assignment and interpolation", + key="IF", + name="if", cmds=[ - "setenv FOO bar\n", - "echo $FOO\n", - "echo '$FOO'\n", - "echo \"$FOO\"\n", - "setenv BAR 'quoted value'\n", - "echo $BAR\n", - "unsetenv FOO\n", - "echo $FOO\n", + "if 1 ls\n", + "if 0 ls\n", + "if 1 then\necho YES\nelse\necho NO\nendif\n", + "if 0 then\necho YES\nelse\necho NO\nendif\n", + "if\n", + "if 0\n", ], - depends_on=("ENV", "QUOTES") + depends_on=() ), - ##Test( - ## key="BACKTICKS", - ## name="backticks", - ## cmds=[ - ## "echo `ls`\n", - ## "echo `ls`l\n", - ## "echo l`ls`\n", - ## "echo ``\n", - ## "`ls`\n", - ## "``\n", - ## "echo `ls\n", - ## "echo ls`\n", - ## "`\n", - ## ], - ## depends_on=() - ##), + Test( + key="EXPR", + name="expr builtin command", + cmds=[ + "expr 1 + 2", + "expr 4 - 2", + #"expr 3 \\* 5", + #"expr 5 = 5", + #"expr 5 \\< 10", + #"expr 5 \\> 3", + ], + depends_on=("ARGS",) + ), + + Test( + key="TILDE", + name="tilde", + cmds=[ + "echo ~", + ], + depends_on=("ARGS",) + ), + + Test( + key="GLOB", + name="globbing", + cmds=[ + "ls *\n", + "echo *.nix\n", + "echo *file*\n", + "echo fixtures/*.sh\n", + "echo doesnotexist*\n", + "ls *.c *.h\n", + "echo *.txt > out.txt\n", + "cat < out.txt\n", + ], + depends_on=("REDIR",) + ), + + Test( + key="REPEAT", + name="repeat loop", + cmds=[ + "repeat 3 echo plop\n", + "repeat 3\n", + "repeat\n", + ], + depends_on=("ARGS",) + ), + + Test( + key="FOREACH", + name="foreach loop", + cmds=[ + "foreach i (1 2 3)\necho $i\nend\n", + "foreach i", + "foreach", + ], + depends_on=("ARGS",) + ), + + Test( + key="WHICH", + name="which/where commands", + cmds=[ + "which ls\n", + "which cd\n", + "alias ll ls\nwhere ll\n", + #"alias ll ls\nwhich ll\n", + ], + depends_on=("ALIAS",) + ), + + Test( + key="BUILTIN_ERR", + name="invalid builtin usage", + cmds=[ + "cd too many args here\n", + "unsetenv\n", + "setenv ONLYKEY\n", + ], + depends_on=("CD", "ENV") + ), ] diff --git a/validator.py b/validator.py index c4cb129..ef40071 100755 --- a/validator.py +++ b/validator.py @@ -66,7 +66,7 @@ class Test: key: str, name: str, cmds: list[str], - depends_on: tuple[str, ...] = () + depends_on: tuple[str, ...] = (), ): self.key = key self.name = name @@ -74,8 +74,8 @@ class Test: self.depends_on = depends_on self.has_run = False - def _run_each_cmd(self, cmd: str): - result_42sh = run_shell(["./42sh"], cmd) + def _run_each_cmd(self, cmd: str, tested_bin): + result_42sh = run_shell([tested_bin], cmd) result_tcsh = run_shell(["tcsh"], cmd) if result_42sh.exit_code == 84 and result_tcsh.exit_code != 0: @@ -88,7 +88,7 @@ class Test: print("\033[31m.\033[0m", end='') # ]] return cmd, result_42sh, result_tcsh - def run(self, test_map) -> bool: + def run(self, test_map, tested_bin) -> bool: if self.has_run: return True @@ -104,7 +104,7 @@ class Test: continue if not dep.has_run: - success &= dep.run(test_map) + success &= dep.run(test_map, tested_bin) if not success: return False @@ -112,7 +112,7 @@ class Test: failures = [] for cmd in self.cmds: - if (failure := self._run_each_cmd(cmd)) is not None: + if (failure := self._run_each_cmd(cmd, tested_bin)) is not None: failures.append(failure) if not failures: print(" \033[32mOK\033[0m") # ]] @@ -130,7 +130,10 @@ def main(): success = True for test in TESTS: - success &= test.run(test_map=test_map) + success &= test.run( + test_map=test_map, + tested_bin=sys.argv[1] if len(sys.argv) > 1 else "./42sh" + ) return not success