Add bonus

This commit is contained in:
savalet
2025-02-26 22:59:05 +01:00
parent 4d3b04c650
commit e8e770ac33
28 changed files with 1271 additions and 0 deletions

126
bonus/Makefile Normal file
View File

@@ -0,0 +1,126 @@
##
## EPITECH PROJECT, 2024
## __
## File description:
## ./Makefile
##
MAKEFLAGS += -j
BIN_NAME := mysh
LIB_NAME := libu.a
SRC := $(wildcard src/*.c)
LIB_SRC := $(wildcard ulib/*.c)
LIB_SRC += $(wildcard ulib/write/printf/*.c)
LIB_SRC += $(wildcard ulib/math/*.c)
LIB_SRC += $(wildcard ulib/mem/*.c)
LIB_SRC += $(wildcard ulib/str/*.c)
LIB_SRC += $(wildcard ulib/write/*.c)
BUILD_DIR := .build
CC := gcc
CFLAGS += -Wall -Wextra -Werror=write-strings -iquote ulib
CFLAGS += -Wno-unused-parameter -Wunused-result -fanalyzer
CFLAGS += -Wp,-U_FORTIFY_SOURCE -Wcast-qual -Wduplicated-branches
CFLAGS += -Wduplicated-cond -Wformat=2 -Wshadow -fno-builtin
CFLAGS += -Wstrict-aliasing=0 -Wstrict-prototypes -Wunreachable-code
CFLAGS += -Wwrite-strings -Werror=declaration-after-statement
CFLAGS += -Werror=format-nonliteral -Werror=int-conversion -Werror=return-type
CFLAGS += -Werror=vla-larger-than=0 -Wno-discarded-qualifiers
LDFLAGS += -L .
LDLIBS := -lu
include utils.mk
.PHONY: _start all
_start: all
# call mk-profile release, SRC, additional CFLAGS
define mk-profile
NAME_$(strip $1) := $4
OBJ_$(strip $1) := $$($(strip $2):%.c=$$(BUILD_DIR)/$(strip $1)/%.o)
LIB_NAME_$(strip $1) := $(BUILD_DIR)/$(strip $1)/$(LIB_NAME)
LIB_OBJ_$(strip $1) := $$(LIB_SRC:%.c=$$(BUILD_DIR)/$(strip $1)/%.o)
$$(BUILD_DIR)/$(strip $1)/%.o: %.c
@ mkdir -p $$(dir $$@)
@ $$(CC) $$(CFLAGS) -o $$@ -c $$<
@ $$(LOG_TIME) "$$(C_GREEN) CC $$(C_PURPLE) $$(notdir $$@) $$(C_RESET)"
$$(LIB_NAME_$(strip $1)): $$(LIB_OBJ_$(strip $1))
@ ar rc $$@ $$(LIB_OBJ_$(strip $1))
@ $$(LOG_TIME) "$$(C_CYAN) AR $$(C_PURPLE) $$(notdir $$@) $$(C_RESET)"
$$(NAME_$(strip $1)): CFLAGS += -L $$(BUILD_DIR)/$(strip $1) $3
$$(NAME_$(strip $1)): $$(LIB_NAME_$(strip $1)) $$(OBJ_$(strip $1))
@ $$(CC) $$(CFLAGS) $$(OBJ_$(strip $1)) $$(LDFLAGS) $$(LDLIBS) -o $$@
@ $$(LOG_TIME) "$$(C_GREEN) CC $$(C_PURPLE) $$(notdir $$@) $$(C_RESET)"
@ $$(LOG_TIME) "$$(C_GREEN) OK Compilation finished $$(C_RESET)"
endef
$(eval $(call mk-profile, release, SRC, , $(BIN_NAME)))
$(eval $(call mk-profile, debug, SRC, -D U_DEBUG_MODE -g3, debug))
$(eval $(call mk-profile, test, SRC, --coverage, test))
$(eval $(call mk-profile, afl, SRC, -D AFL_MODE, afl_runner))
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))" ./$^'
.PHONY: cov
cov: tests_run
gcovr . \
--gcov-ignore-errors=no_working_dir_found \
--exclude-unreachable-branches \
--exclude tests
.PHONY: afl
afl: CC := AFL_USE_ASAN=1 afl-gcc-fast
afl: $(NAME_afl)
define newline
endef
AFL_FLAGS := -i afl/inputs
AFL_FLAGS += -x afl/tokens
AFL_FLAGS += -o afl/generated
PROCS ?= $(shell nproc)
.PHONY: afl_run
afl_run: afl
@ mkdir -p afl/generated
screen -dmS main_instance \
afl-fuzz $(AFL_FLAGS) -M fuzzer_1 -- ./afl_runner
$(foreach instance, $(shell seq 1 $(PROCS)),\
screen -dmS afl_$(instance) \
afl-fuzz $(AFL_FLAGS) -S fuzzer_$(instance) -- ./afl_runner$(newline))
watch -n 0.25 -- afl-whatsup -s afl/generated
clean:
@ $(RM) $(OBJ)
@ $(LOG_TIME) "$(C_YELLOW) RM $(C_PURPLE) $(OBJ) $(C_RESET)"
fclean:
@ $(RM) -r $(NAME_release) $(NAME_debug) $(BUILD_DIR)
@ $(LOG_TIME) "$(C_YELLOW) RM $(C_PURPLE) $(NAME_release) $(NAME_debug) \
$(C_RESET)"
.NOTPARALLEL: re
re: fclean all
.PHONY: all clean fclean re

36
bonus/afunc.txt Normal file
View File

@@ -0,0 +1,36 @@
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

150
bonus/src/builtins.c Normal file
View File

@@ -0,0 +1,150 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include "debug.h"
#include "env.h"
#include "shell.h"
#include "u_mem.h"
#include "u_str.h"
int builtins_exit(env_t *env, char **args __attribute__((unused)), char *buff,
history_t *history)
{
free_env(env);
free((void *)args);
free(buff);
exit(history->last_exit_code);
}
int builtins_env(env_t *env, char **args __attribute__((unused)),
char *buff __attribute__((unused)),
history_t *history __attribute__((unused)))
{
for (size_t i = 0; i < env->sz; i++) {
if (env->env[i] == NULL)
continue;
write(STDOUT_FILENO, env->env[i], u_strlen(env->env[i]));
WRITE_CONST(STDOUT_FILENO, "\n");
}
return RETURN_SUCCESS;
}
int builtins_setenv(env_t *env, char **args,
char *buff __attribute__((unused)),
history_t *history __attribute__((unused)))
{
if (args[1] == NULL)
return builtins_env(env, args, buff, history);
if (args[2] != NULL && args[3] != NULL) {
WRITE_CONST(STDERR_FILENO, "setenv: Too many arguments.\n");
return RETURN_FAILURE;
}
if (!isalpha(args[1][0]))
return (WRITE_CONST(STDERR_FILENO, "setenv: Variable name must begin"
" with a letter.\n"), RETURN_FAILURE);
if (!u_str_is_only_alnum(args[1]))
return (WRITE_CONST(STDERR_FILENO, "setenv: Variable name must contain"
" alphanumeric characters.\n"), RETURN_FAILURE);
if (!set_env(env, args[1], args[2]))
return RETURN_FAILURE;
return RETURN_SUCCESS;
}
int builtins_unsetenv(env_t *env, char **args,
__attribute__((unused)) char *buff,
history_t *history __attribute__((unused)))
{
if (args[1] == NULL)
return (WRITE_CONST(STDERR_FILENO, "unsetenv: Too few arguments.\n"),
RETURN_FAILURE);
if (!unset_env(env, args[1]))
return RETURN_FAILURE;
return RETURN_SUCCESS;
}
static
void cd_print_error(void)
{
switch (errno) {
case EACCES:
WRITE_CONST(STDERR_FILENO, ": Permission denied.\n");
break;
case ENOENT:
WRITE_CONST(STDERR_FILENO, ": No such file or directory.\n");
break;
case ENOTDIR:
WRITE_CONST(STDERR_FILENO, ": Not a directory.\n");
break;
default:
WRITE_CONST(STDERR_FILENO, ": Unknown error.\n");
}
}
static
char *get_current_dir(void)
{
size_t size = 64;
char *buffer = malloc(size);
char *new_buffer;
size_t max_it = 100;
if (!buffer)
return NULL;
while (getcwd(buffer, size) == NULL && max_it > 0) {
if (errno != ERANGE)
return (free(buffer), NULL);
size <<= 1;
new_buffer = u_realloc(buffer, u_strlen(buffer) + 1, size);
if (!new_buffer)
return (free(buffer), NULL);
buffer = new_buffer;
max_it--;
}
return buffer;
}
static
int builtins_cd_chdir(char *path, history_t *history, char **args, env_t *env)
{
char *act_pwd;
if (history->last_chdir != NULL && args[1] != NULL
&& u_strcmp(args[1], "-") == 0)
path = history->last_chdir;
act_pwd = get_current_dir();
U_DEBUG("last chdir %s\n", history->last_chdir);
if (chdir(path) < 0) {
write(STDERR_FILENO, path, u_strlen(path));
cd_print_error();
return RETURN_FAILURE;
}
free(history->last_chdir);
history->last_chdir = act_pwd;
return RETURN_SUCCESS;
}
int builtins_cd(env_t *env, char **args, char *buff __attribute__((unused)),
history_t *history __attribute__((unused)))
{
char *path = args[1];
if (path == NULL || u_strcmp(args[1], "~") == 0)
path = get_env_value(env, "HOME");
if (path == NULL)
return RETURN_FAILURE;
if (args[1] != NULL && args[2] != NULL) {
WRITE_CONST(STDERR_FILENO, "cd: Too many arguments.\n");
return RETURN_FAILURE;
}
return builtins_cd_chdir(path, history, args, env);
}

48
bonus/src/builtins.h Normal file
View File

@@ -0,0 +1,48 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef BUILTINS_H
#define BUILTINS_H
#include "env.h"
#include "shell.h"
typedef struct {
char const *name;
int (*ptr)(env_t *env, char **args, char *buff, history_t *history);
} builtins_t;
extern const builtins_t BUILTINS[];
extern const size_t BUILTINS_SZ;
int builtins_exit(env_t *env, char **args __attribute__((unused)),
char *buff, history_t *history);
int builtins_env(env_t *env, char **args __attribute__((unused)),
char *buff __attribute__((unused)),
history_t *history __attribute__((unused)));
int builtins_setenv(env_t *env, char **args,
char *buff __attribute__((unused)),
history_t *history __attribute__((unused)));
int builtins_unsetenv(env_t *env, char **args,
char *buff __attribute__((unused)),
history_t *history __attribute__((unused)));
int builtins_cd(env_t *env, char **args,
char *buff __attribute__((unused)),
history_t *history __attribute__((unused)));
int builtins_builtins(env_t *env __attribute__((unused)),
char **args __attribute__((unused)), char *buff __attribute__((unused)),
history_t *history __attribute__((unused)));
int builtins_funny_double_dot(env_t *env __attribute__((unused)),
char **args __attribute__((unused)), char *buff __attribute__((unused)),
history_t *history __attribute__((unused)));
#endif /* BUILTIND_H */

30
bonus/src/builtins2.c Normal file
View File

@@ -0,0 +1,30 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <unistd.h>
#include "builtins.h"
#include "common.h"
#include "env.h"
#include "shell.h"
#include "u_str.h"
int builtins_builtins(env_t *env __attribute__((unused)),
char **args __attribute__((unused)), char *buff __attribute__((unused)),
history_t *history __attribute__((unused)))
{
for (size_t i = 0; i < BUILTINS_SZ; i++)
write(STDOUT_FILENO, BUILTINS[i].name, u_strlen(BUILTINS[i].name));
return RETURN_SUCCESS;
}
int builtins_funny_double_dot(env_t *env __attribute__((unused)),
char **args __attribute__((unused)), char *buff __attribute__((unused)),
history_t *history __attribute__((unused)))
{
return RETURN_SUCCESS;
}

14
bonus/src/common.h Normal file
View File

@@ -0,0 +1,14 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef COMMON_H
#define COMMON_H
enum {
RETURN_SUCCESS = 0,
RETURN_FAILURE = 1
};
#endif /* COMMON_H */

36
bonus/src/debug.h Normal file
View File

@@ -0,0 +1,36 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef DEBUG_H
#define DEBUG_H
#include "vt100_esc_codes.h"
#include <stdio.h>
#define OMIT
#ifdef U_DEBUG_MODE
#define HEAD __FILE_NAME__, __LINE__
#define HEAD_FMT_FILE BOLD BLUE "%s" RESET
#define HEAD_FMT_LINE ":" BOLD PURPLE "%d" RESET
#define HEAD_FMT HEAD_FMT_FILE HEAD_FMT_LINE " "
#define ERR(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
#define DEBUG_INTERNAL(fmt, ...) ERR(HEAD_FMT fmt, HEAD, __VA_ARGS__)
#define U_DEBUG(fmt, ...) DEBUG_INTERNAL(fmt, __VA_ARGS__)
#define U_DEBUG_MSG(msg) DEBUG_INTERNAL("%s\n", msg)
#define U_DEBUG_CALL(func, ...) func(__VA_ARGS__)
#else
#define U_DEBUG_CALL(func, ...) OMIT
#define U_DEBUG_MSG(msg) OMIT
#define U_DEBUG(fmt, ...) OMIT
#endif
#endif /* DEBUG_H */

136
bonus/src/env.c Normal file
View File

@@ -0,0 +1,136 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "env.h"
#include "u_mem.h"
#include "u_str.h"
char *get_env_value(env_t *env, char const *key)
{
int key_len = u_strlen(key);
for (size_t i = 0; i < env->sz; i++) {
if (env->env[i] == NULL)
continue;
if (u_strcspn(env->env[i], '=') != key_len)
continue;
if (u_strcmp(env->env[i], key) == 0)
return env->env[i] + key_len + 1;
}
return NULL;
}
static
void unset_env_move(env_t *env, size_t i)
{
while (env->env[i]) {
env->env[i] = env->env[i + 1];
i++;
}
}
bool unset_env(env_t *env, char *key)
{
int key_len = u_strlen(key);
for (size_t i = 0; i < env->sz; i++) {
if (env->env[i] == NULL)
continue;
if (u_strcspn(env->env[i], '=') != key_len)
continue;
if (u_strcmp(env->env[i], key) == 0) {
unset_env_move(env, i);
env->sz--;
return true;
}
}
return false;
}
void free_env(env_t *env)
{
for (size_t i = 0; i < env->sz; i++) {
if (env->env[i] == NULL)
continue;
free(env->env[i]);
}
free((void *)env->env);
}
static __attribute__((nonnull))
bool ensure_env_capacity(env_t *env)
{
char **new_ptr;
if (env->sz < env->cap)
return true;
new_ptr = (char **)u_realloc((void *)env->env, sizeof *env->env * env->sz,
sizeof *env->env * env->cap << 1);
if (!new_ptr)
return false;
env->cap <<= 1;
env->env = new_ptr;
return true;
}
static
void env_bzero(char **env, size_t sz)
{
for (size_t i = 0; i < sz; i++)
env[i] = NULL;
}
bool set_env(env_t *env, char *key, char *value)
{
char *new_env = NULL;
size_t key_len = u_strlen(key);
size_t value_len = u_strlen(value);
if (get_env_value(env, key) != NULL)
unset_env(env, key);
env->sz++;
if (!ensure_env_capacity(env))
return false;
new_env = malloc(sizeof(char) * (key_len + value_len + 2));
if (new_env == NULL)
return false;
u_bzero(new_env, key_len + value_len + 2);
u_strcpy(new_env, key);
new_env[key_len] = '=';
if (value_len > 0)
u_strcpy(new_env + key_len + 1, value);
env->env[env->sz - 1] = new_env;
return true;
}
env_t parse_env(char **env)
{
env_t new_env = { 0, .cap = BASE_ENV_CAP };
new_env.env = (char **)malloc(sizeof(char *) * new_env.cap);
if (!new_env.env)
return (env_t){ 0, .env = NULL };
env_bzero(new_env.env, new_env.sz);
for (; *env != NULL; env++) {
if (!ensure_env_capacity(&new_env))
return (free((void *)new_env.env), (env_t){ 0 });
new_env.env[new_env.sz] = u_strdup(*env);
if (new_env.env[new_env.sz] == NULL)
return (free((void *)new_env.env), (env_t){ 0 });
new_env.sz++;
}
if (!ensure_env_capacity(&new_env))
return (free((void *)new_env.env), (env_t){ 0 });
new_env.env[new_env.sz] = NULL;
return new_env;
}

30
bonus/src/env.h Normal file
View File

@@ -0,0 +1,30 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef ENV_H
#define ENV_H
#include <stdbool.h>
#include <stddef.h>
#define BASE_ENV_CAP 128
typedef struct {
size_t sz;
size_t cap;
char **env;
} env_t;
__attribute__((unused))
void free_env(env_t *env);
__attribute__((unused))
env_t parse_env(char **env);
__attribute__((unused))
char *get_env_value(env_t *env, char const *key);
__attribute__((unused))
bool unset_env(env_t *env, char *key);
__attribute__((nonnull(1, 2)))
bool set_env(env_t *env, char *key, char *value);
#endif

242
bonus/src/exec.c Normal file
View File

@@ -0,0 +1,242 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include "builtins.h"
#include "common.h"
#include "debug.h"
#include "env.h"
#include "exec.h"
#include "u_mem.h"
#include "u_str.h"
const builtins_t BUILTINS[] = {
{ "builtins", &builtins_builtins },
{ "cd", &builtins_cd },
{ "chdir", &builtins_cd },
{ "env", &builtins_env },
{ "printenv", &builtins_env },
{ "setenv", &builtins_setenv },
{ "unsetenv", &builtins_unsetenv },
{ ":", &builtins_funny_double_dot },
{ "exit", &builtins_exit }
};
const size_t BUILTINS_SZ = sizeof BUILTINS / sizeof *BUILTINS;
static
char *build_full_path(const char *token, const char *binary)
{
size_t len_token = u_strlen(token);
size_t len_bin = u_strlen(binary);
char *full_path = malloc(len_token + len_bin + 2);
if (!full_path)
return NULL;
u_strcpy(full_path, token);
full_path[len_token] = '/';
u_strcpy(full_path + len_token + 1, binary);
full_path[len_token + len_bin + 1] = '\0';
return full_path;
}
static
char *find_binary(const char *path_env, const char *binary)
{
static char *saveptr = NULL;
static char *path = NULL;
char *token;
char *full_path;
if (path_env) {
path = u_strdup(path_env);
if (!path)
return NULL;
token = strtok_r(path, ":", &saveptr);
} else
token = strtok_r(NULL, ":", &saveptr);
if (!token)
return free(path), u_strdup(binary);
full_path = build_full_path(token, binary);
if (!full_path)
return NULL;
return access(full_path, X_OK) == 0 ? full_path : (free(full_path),
find_binary(NULL, binary));
}
static __attribute__((nonnull))
bool ensure_args_capacity(char ***args, size_t const sz, size_t *cap)
{
char **new_ptr;
if (sz < *cap)
return true;
new_ptr = (char **)u_realloc((void *)*args, sizeof *args * sz,
sizeof *args * *cap << 1);
if (!new_ptr)
return false;
*cap <<= 1;
*args = new_ptr;
return true;
}
static
char **parse_args(char *buffer)
{
size_t sz = 0;
size_t cap = DEFAULT_ARGS_CAP;
char **args = (char **)malloc(sizeof *args * cap);
char *token;
if (!args)
return NULL;
token = strtok(buffer, " \t\v");
while (token != NULL) {
ensure_args_capacity(&args, sz, &cap);
args[sz] = token;
U_DEBUG("Args [%lu] [%s]\n", sz, args[sz]);
sz++;
token = strtok(NULL, " \t\v");
}
ensure_args_capacity(&args, sz, &cap);
args[sz] = NULL;
return args;
}
static
int command_error(char *cmd, char **args, int error)
{
struct stat st;
if (access(cmd, F_OK) == -1) {
write(STDERR_FILENO, args[0], u_strlen(args[0]));
WRITE_CONST(STDERR_FILENO, ": Command not found.\n");
return 84;
}
stat(cmd, &st);
if (S_ISDIR(st.st_mode) || access(cmd, X_OK)) {
write(STDERR_FILENO, args[0], u_strlen(args[0]));
WRITE_CONST(STDERR_FILENO, ": Permission denied.\n");
return 84;
}
if (error == ENOEXEC) {
write(STDERR_FILENO, args[0], u_strlen(args[0]));
WRITE_CONST(STDERR_FILENO, ": Exec format error."
" Binary file not executable.\n");
return 0;
}
return 84;
}
static
int launch_bin(char *full_bin_path, char **args, env_t *env, char *buff)
{
int status;
pid_t pid = fork();
if (pid == 0) {
#if defined(AFL_MODE)
exit(0);
#else
if (execve(full_bin_path, args, env->env) < 0) {
status = command_error(full_bin_path, args, errno);
free_env(env);
free((void *)args);
free(buff);
exit(status);
}
#endif
}
waitpid(pid, &status, 0);
return status;
}
static
void status_handler(int status, history_t *history)
{
char *strsig;
if (WIFEXITED(status))
history->last_exit_code = WEXITSTATUS(status);
if (!WIFEXITED(status) && WIFSIGNALED(status)) {
if (WTERMSIG(status) != SIGFPE && WTERMSIG(status) != SIGINT &&
WTERMSIG(status) != SIGTRAP) {
strsig = strsignal(WTERMSIG(status));
write(STDERR_FILENO, strsig, u_strlen(strsig));
}
if (WTERMSIG(status) == SIGTRAP)
WRITE_CONST(STDERR_FILENO, "Trace/BPT trap");
if (WTERMSIG(status) == SIGFPE)
WRITE_CONST(STDERR_FILENO, "Floating exception");
if (WCOREDUMP(status))
WRITE_CONST(STDERR_FILENO, " (core dumped)");
WRITE_CONST(STDERR_FILENO, "\n");
}
U_DEBUG("Exit code [%d]\n", history->last_exit_code);
}
static
bool builtins_launcher(char *buffer, env_t *env, history_t *history,
char **args)
{
int buffer_l = u_strlen(buffer);
for (size_t i = 0; i < BUILTINS_SZ; i++) {
if (u_strlen(BUILTINS[i].name) != buffer_l)
continue;
if (u_strcmp(BUILTINS[i].name, buffer) == 0) {
history->last_exit_code =
BUILTINS[i].ptr(env, args, buffer, history);
return true;
}
}
return false;
}
static
char *parse_full_bin_path(env_t *env, char *bin_name)
{
char const *path = get_env_value(env, "PATH");
char *full_bin_path;
if (path == NULL)
path = DEFAULT_PATH;
U_DEBUG("Used path [%s]\n", path);
full_bin_path = find_binary(path, bin_name);
U_DEBUG("Exec bin [%s]\n", full_bin_path);
if (full_bin_path == NULL)
return NULL;
return full_bin_path;
}
int execute(char *buffer, env_t *env, history_t *history)
{
char *full_bin_path;
char **args = parse_args(buffer);
int status;
if (!args)
return RETURN_FAILURE;
if (builtins_launcher(buffer, env, history, args))
return RETURN_SUCCESS;
full_bin_path = parse_full_bin_path(env, args[0]);
if (full_bin_path == NULL)
return (free((void *)args), RETURN_FAILURE);
U_DEBUG("Found bin [%s]\n", full_bin_path);
status = launch_bin(full_bin_path, args, env, buffer);
status_handler(status, history);
free(full_bin_path);
free((void *)args);
return RETURN_SUCCESS;
}

23
bonus/src/exec.h Normal file
View File

@@ -0,0 +1,23 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef EXEC_H
#define EXEC_H
#include "env.h"
#include "shell.h"
#define DEFAULT_ARGS_CAP 1
#define DEFAULT_PATH "/usr/bin:."
typedef struct {
char **args;
size_t count;
size_t cap;
} args_t;
__attribute__((nonnull))
int execute(char *buffer, env_t *env, history_t *history);
#endif /* EXEC_H */

16
bonus/src/main.c Normal file
View File

@@ -0,0 +1,16 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include "debug.h"
#include "shell.h"
int main(int ac __attribute__((unused)), char **av __attribute__((unused)),
char **env)
{
U_DEBUG_MSG("Debug mode activated.");
return shell(env);
}

68
bonus/src/shell.c Normal file
View File

@@ -0,0 +1,68 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include "debug.h"
#include "env.h"
#include "exec.h"
#include "shell.h"
#include "u_str.h"
__attribute__((unused))
static
void debug_env_entries(env_t *env)
{
for (size_t i = 0; i < env->sz; i++) {
if (env->env[i] == NULL)
continue;
U_DEBUG("Env entry [%lu] [%s]\n", i, env->env[i]);
}
}
static
int shell_loop(env_t *env, int is_a_tty, history_t *history)
{
char *buffer = NULL;
size_t buffer_sz;
size_t buffer_len;
while (true) {
if (is_a_tty)
WRITE_CONST(STDOUT_FILENO, SHELL_PROMPT);
if (getline(&buffer, &buffer_sz, stdin) == -1)
break;
buffer_len = u_strlen(buffer);
if (buffer_len < 2 || !u_str_is_alnum(buffer))
continue;
if (buffer[buffer_len - 1] == '\n')
buffer[buffer_len - 1] = '\0';
U_DEBUG("Buffer [%lu] [%s]\n", buffer_len, buffer);
execute(buffer, env, history);
}
if (is_a_tty)
WRITE_CONST(STDOUT_FILENO, "exit\n");
return (free(buffer), history->last_exit_code);
}
int shell(char **env_ptr)
{
env_t env = parse_env(env_ptr);
history_t history = { .cmd_history = NULL, 0, .last_chdir = NULL };
int shell_result;
if (!env.env)
return RETURN_FAILURE;
U_DEBUG_CALL(debug_env_entries, &env);
shell_result = shell_loop(&env, isatty(STDIN_FILENO), &history);
free_env(&env);
return shell_result;
}

19
bonus/src/shell.h Normal file
View File

@@ -0,0 +1,19 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef SHELL_H
#define SHELL_H
#include "vt100_esc_codes.h"
#define SHELL_PROMPT RED "|> " RESET
typedef struct {
char **cmd_history;
int last_exit_code;
char *last_chdir;
} history_t;
int shell(char **env);
#endif /* SHELL_H */

View File

@@ -0,0 +1,27 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef CR_VT100_ESC_CODES_H
#define CR_VT100_ESC_CODES_H
#define ESC "\033"
#define CFMT(n) ESC "[" #n "m"
// move
#define MOVE_RIGHT(n) ESC "[" #n "C"
// colors
#define RESET CFMT(0)
#define BOLD CFMT(1)
#define RED CFMT(31)
#define GREEN CFMT(32)
#define YELLOW CFMT(33)
#define BLUE CFMT(34)
#define PURPLE CFMT(35)
#define CYAN CFMT(36)
#endif

1
bonus/ulib/lib.h Symbolic link
View File

@@ -0,0 +1 @@
../../include/lib.h

18
bonus/ulib/mem/bzero.c Normal file
View File

@@ -0,0 +1,18 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <stdbool.h>
#include <stddef.h>
__attribute__((nonnull(1)))
bool u_bzero(char *restrict str, size_t sz)
{
if (sz > 0)
for (size_t i = 0; i < sz; i++)
str[i] = 0;
return true;
}

15
bonus/ulib/mem/memcpy.c Normal file
View File

@@ -0,0 +1,15 @@
/*
** EPITECH PROJECT, 2024
** CPoolDay08
** File description:
** ./u_realloc.c
*/
#include <stddef.h>
void *u_memcpy(char *dst, char const *src, size_t sz)
{
for (size_t i = 0; i < sz; i++)
dst[i] = src[i];
return dst;
}

28
bonus/ulib/mem/realloc.c Normal file
View File

@@ -0,0 +1,28 @@
/*
** EPITECH PROJECT, 2024
** CPoolDay08
** File description:
** ./u_realloc.c
*/
#include <stddef.h>
#include <stdlib.h>
#include "u_mem.h"
void *u_realloc(void *ptr, size_t actual_size, size_t new_size)
{
void *new;
if (ptr == NULL)
return ptr;
if (!actual_size && !new_size)
return NULL;
new = malloc(new_size);
if (new == NULL)
return NULL;
if (actual_size > 0 && new_size > 0)
u_memcpy(new, ptr, actual_size);
free(ptr);
return new;
}

View File

@@ -0,0 +1,25 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#include <ctype.h>
#include <stdbool.h>
bool u_str_is_alnum(char *str)
{
for (; *str != '\0'; str++)
if (isalnum(*str))
return true;
return false;
}
bool u_str_is_only_alnum(char *str)
{
for (; *str != '\0'; str++)
if (!isalnum(*str))
return false;
return true;
}

16
bonus/ulib/str/strcmp.c Normal file
View File

@@ -0,0 +1,16 @@
/*
** EPITECH PROJECT, 2024
** B-CPE-100-REN-1-1-cpoolday06-savinien.petitjean
** File description:
** Task 1
*/
int u_strcmp(char const *s1, char const *s2)
{
int i = 0;
for (; s1[i] == s2[i] && s1[i] != '\0'; i++);
if (i > 0 && (s1[i] == '\0' || s2[i] == '\0'))
return s1[i - 1] - s2[i - 1];
return s1[i] - s2[i];
}

16
bonus/ulib/str/strcpy.c Normal file
View File

@@ -0,0 +1,16 @@
/*
** EPITECH PROJECT, 2024
** B-CPE-100-REN-1-1-cpoolday06-savinien.petitjean
** File description:
** Task 1
*/
__attribute__((nonnull(1, 2)))
char *u_strcpy(char *dest, char const *src)
{
int i = 0;
for (; src[i] != '\0'; i++)
dest[i] = src[i];
return (dest);
}

16
bonus/ulib/str/strcspn.c Normal file
View File

@@ -0,0 +1,16 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
int u_strcspn(char *str, char c)
{
char *old_str = str;
for (; *str != '\0'; str++)
if (*str == c)
return str - old_str;
return 0;
}

23
bonus/ulib/str/strdup.c Normal file
View File

@@ -0,0 +1,23 @@
/*
** EPITECH PROJECT, 2024
** CPoolDay08
** File description:
** ./u_strdup.c
*/
#include <stdlib.h>
#include "u_mem.h"
#include "u_str.h"
char *u_strdup(char const *src)
{
char *dest;
int len = u_strlen(src);
dest = malloc(sizeof(char) * (len + 1));
if (dest == NULL)
return NULL;
u_bzero(dest, len + 1);
return u_strcpy(dest, src);
}

19
bonus/ulib/str/strlen.c Normal file
View File

@@ -0,0 +1,19 @@
/*
** EPITECH PROJECT, 2024
** B-CPE-100-REN-1-1-cpoolday06-savinien.petitjean
** File description:
** Task 3
*/
#include <ctype.h>
#include <stddef.h>
int u_strlen(char const *str)
{
char const *p = str;
if (str == NULL)
return 0;
for (; *p != '\0'; p++);
return (p - str);
}

20
bonus/ulib/u_mem.h Normal file
View File

@@ -0,0 +1,20 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef MEM_H
#define MEM_H
#include <stdbool.h>
#include <stddef.h>
#define IDX_OF(array, i, mem_s) (array + ((i) * (mem_s)))
void *u_memcpy(char *dst, char const *src, size_t sz);
void *u_realloc(void *ptr, size_t actual_size, size_t new_size);
void u_swap(int *, int *);
bool u_bzero(char *restrict str, size_t sz);
int swap_uint32(int src);
#endif /* MEM_H */

37
bonus/ulib/u_str.h Normal file
View File

@@ -0,0 +1,37 @@
/*
** EPITECH PROJECT, 2025
** __
** File description:
** _
*/
#ifndef STRING_H
#define STRING_H
#include <stdbool.h>
#include <stddef.h>
#define WRITE_CONST(fd, str) write(fd, str, sizeof str - 1)
typedef struct {
char *str;
size_t sz;
size_t cap;
} buff_t;
int u_getnbr(char const *);
char *u_strcat(char *, char const *);
char *u_strncat(char *, char const *, int);
char *u_strdup(char const *);
int u_strlen(char const *);
char *u_strcpy(char *, char const *);
char *u_strncpy(char *, char const *, int);
char *u_revstr(char *);
char *u_strstr(char *, char const *);
int u_strcmp(char const *, char const *);
int u_strncmp(char const *, char const *, int);
char *u_numstr(char *, int);
int u_spacelen(char const *str);
int u_strcspn(char *str, char c);
bool u_str_is_alnum(char *str);
bool u_str_is_only_alnum(char *str);
#endif /* STRING_H */

36
bonus/utils.mk Normal file
View File

@@ -0,0 +1,36 @@
##
## EPITECH PROJECT, 2024
## template
## File description:
## utils.mk
##
ifneq ($(shell command -v tput),)
ifneq ($(shell tput colors),0)
C_RESET := \033[00m
C_BOLD := \e[1m
C_RED := \e[31m
C_GREEN := \e[32m
C_YELLOW := \e[33m
C_BLUE := \e[34m
C_PURPLE := \e[35m
C_CYAN := \e[36m
C_BEGIN := \033[A
endif
endif
NOW = $(shell date +%s%3N)
STIME := $(call NOW)
TIME_NS = $(shell expr $(call NOW) - $(STIME))
TIME_MS = $(shell expr $(call TIME_NS))
BOXIFY = "[$(C_BLUE)$(1)$(C_RESET)] $(2)"
ifneq ($(shell command -v printf),)
LOG_TIME = printf $(call BOXIFY, %6s , %b\n) "$(call TIME_MS)"
else
LOG_TIME = echo -e $(call BOXIFY, $(call TIME_MS) ,)
endif