mirror of
https://github.com/Savapitech/42sh.git
synced 2026-03-18 21:50:35 +01:00
Merge branch 'main' into magic_quotes
This commit is contained in:
3
Makefile
3
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
|
||||
|
||||
19
README.md
19
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`, ...)
|
||||
|
||||
36
afunc.txt
36
afunc.txt
@@ -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
|
||||
20
src/alias.c
20
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;
|
||||
}
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
12
src/ast.h
12
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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) };
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5,10 +5,15 @@
|
||||
** builtin_history
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 <string.h>
|
||||
#include "utils.h"
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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 = " ";
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
** File description:
|
||||
** history
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "env.h"
|
||||
#include "exec.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "alias.h"
|
||||
#include "common.h"
|
||||
#include "exec.h"
|
||||
#include "utils.h"
|
||||
|
||||
void free_alias(alias_t *alias)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -5,36 +5,31 @@
|
||||
** get_loop_cmd
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "env.h"
|
||||
#include "exec.h"
|
||||
|
||||
int builtins_history(ef_t *ef, char **args __attribute__((unused)))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -6,16 +6,15 @@
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -4,34 +4,34 @@
|
||||
** File description:
|
||||
** foreach
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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)
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
** File description:
|
||||
** repeat
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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){
|
||||
|
||||
@@ -5,14 +5,12 @@
|
||||
** unset
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "env.h"
|
||||
#include "exec.h"
|
||||
#include "u_str.h"
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -4,19 +4,20 @@
|
||||
** File description:
|
||||
** yes
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
10
src/common.h
10
src/common.h
@@ -7,7 +7,9 @@
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
#include "exec.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#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 */
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,14 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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 */
|
||||
|
||||
48
src/main.c
48
src/main.c
@@ -5,12 +5,52 @@
|
||||
** _
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -4,20 +4,16 @@
|
||||
** File description:
|
||||
** his for history
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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},
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#define BUFF_INIT_SZ 16
|
||||
#include <stdbool.h>
|
||||
|
||||
#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 */
|
||||
|
||||
38
src/repl.c
38
src/repl.c
@@ -6,19 +6,47 @@
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
53
src/shell.c
53
src/shell.c
@@ -5,6 +5,7 @@
|
||||
** _
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -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 <signal.h>
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
29
src/utils/insert_str.c
Normal file
29
src/utils/insert_str.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
** EPITECH PROJECT, 2025
|
||||
** __
|
||||
** File description:
|
||||
** _
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
),
|
||||
]
|
||||
|
||||
17
validator.py
17
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user