From a2a51b77a5534978f30f2788f7ed9cbe4fda3089 Mon Sep 17 00:00:00 2001 From: Charles Cabergs Date: Mon, 14 Sep 2020 20:48:50 +0200 Subject: Removing path hash table, replacing it by brute force search --- Makefile | 2 +- README.md | 64 ++++++++++++---------------------- include/eval.h | 14 ++++---- include/minishell.h | 5 ++- minishell_test | 2 +- src/builtin/pwd.c | 16 ++++----- src/eval/cmd.c | 14 ++++---- src/eval/eval.c | 10 +++--- src/eval/exec.c | 39 ++++++++++----------- src/eval/operation.c | 12 +++---- src/eval/parenthesis.c | 7 ++-- src/main.c | 39 +++++++++------------ src/path.c | 93 +++++++++++++++++++++++--------------------------- 13 files changed, 137 insertions(+), 180 deletions(-) diff --git a/Makefile b/Makefile index ccf5433..1ea268f 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ # By: cacharle +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/02/03 04:14:24 by cacharle #+# #+# # -# Updated: 2020/09/13 16:02:22 by charles ### ########.fr # +# Updated: 2020/09/14 19:10:10 by charles ### ########.fr # # # # **************************************************************************** # diff --git a/README.md b/README.md index d9f52cd..9df33be 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,30 @@ # minishell -minishell project of school 42 +minishell project of school 42. -## Testing +## Authors + +* [nahaddac](https://github.com/nass1pro) +* [cacharle](https://github.com/cacharle) +## Usage + +```sh +$ make +$ ./minishell ``` ->make test + +## Testing + +Done with [minishell\_test](https://github.com/cacharle/minishell_test). + +```sh +$ git submodule update minishell_test +$ cd minishell_test +$ ./run ``` ## Documentation -Generate with `make doc` (clean with `make doc_clean`). -You can then read the man pages in ./doc/man or open ./doc/html/index.html in your browser. - -## TODO - -### Mandatory - -- [x] Show a prompt when waiting for a new command -- [x] Search and launch the right executable (based on the *PATH* variable or by using relative or absolute path) like in bash -- [ ] It must implement the builtins like in bash: - - [x] `echo` with option `-n` - - [ ] `cd` without `-` option - - [ ] `pwd` without any options - - [x] `export` without any options - - [x] `unset` without any options - - [ ] `env` without any options and any arguments - - [x] `exit` without any options -- [x] `;` in the command should separate commands like in bash -- [x] `'` and `"` should work like in bash except for multiline commands -- [ ] Redirections `<` `>` `>>` should work like in bash except for file descriptor aggregation -- [ ] Pipes | should work like in bash -- [x] Environment variables (`$` followed by characters) should work like in bash -- [ ] `$?` should work like in bash -- [ ] `ctrl-C`, `ctrl-D` and `ctrl-\` should have the same result as in bash - -### Bonus - -- [ ] Redirection `<<` like in bash -- [ ] History and line editing with Termcaps (`man tgetent` for examples) - - [ ] Edit the line where the cursor is located. - - [ ] Move the cursor left and right to be able to edit the line at a specific location. - Obviously new characters have to be inserted between the existing ones similarly to a classic shell. - - [ ] Use up and down arrows to navigate through the command history which we will then be able to edit if we feel like it (the line, not the history). - - [ ] Cut, copy, and/or paste all or part of a line using the key sequence you prefer. - - [ ] Move directly by word towards the left or the right using ctrl+LEFT and ctrl+RIGHT. - - [ ] Go directly to the beginning or the end of a line by pressing `home` and `end`. - - [ ] Write AND edit a command over a few lines. In that case, we would love that ctrl+UP and ctrl+DOWN allow - to go from one line to another in the command while remaining in the same column or otherwise the most appropriate column. -- [ ] &&, || with parenthesis for priorities, like in bash -- [x] wilcard * like in bash +Generate with `make doc` (clean with `make doc_clean`). +You can then read the man pages in `./doc/man` or open `./doc/html/index.html` in your browser. diff --git a/include/eval.h b/include/eval.h index 6aaefd9..02d0624 100644 --- a/include/eval.h +++ b/include/eval.h @@ -6,7 +6,7 @@ /* By: charles +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/04/01 17:05:30 by charles #+# #+# */ -/* Updated: 2020/09/14 17:20:14 by charles ### ########.fr */ +/* Updated: 2020/09/14 19:49:18 by charles ### ########.fr */ /* */ /* ************************************************************************** */ @@ -24,7 +24,6 @@ typedef struct { - t_path path; t_env env; t_ast *ast; int fds[2]; @@ -32,7 +31,7 @@ typedef struct typedef struct { - char *exec_path; + char exec_path[PATH_MAX + 1]; char **argv; t_env env; t_builtin_entry *builtin; @@ -49,25 +48,25 @@ extern pid_t g_child_pid; */ int fork_wrap(int fds[2], void *passed, int (*wrapped)(void *param), pid_t *child_pid); -int eval(int fds[2], t_env env, t_path path, t_ast *ast, pid_t *child_pid); +int eval(int fds[2], t_env env, t_ast *ast, pid_t *child_pid); /* ** cmd.c */ -int eval_cmd(int fds[2], t_env env, t_path path, t_ast *ast, pid_t *child_pid); +int eval_cmd(int fds[2], t_env env, t_ast *ast, pid_t *child_pid); /* ** operation.c */ -int eval_operation(int fds[2], t_env env, t_path path, t_ast *ast); +int eval_operation(int fds[2], t_env env, t_ast *ast); /* ** parenthesis.c */ -int eval_parenthesis(int fds[2], t_env env, t_path path, t_ast *ast); +int eval_parenthesis(int fds[2], t_env env, t_ast *ast); /* ** redir.c @@ -80,6 +79,5 @@ int redir_extract(t_tok_lst **redirs, t_env env, int fds[2]); */ int exec_path_check(char *exec_path); -int exec_search_path(t_path path, char *path_var, char *exec_name, char **exec_path); #endif diff --git a/include/minishell.h b/include/minishell.h index 95f299b..0dd0522 100644 --- a/include/minishell.h +++ b/include/minishell.h @@ -6,7 +6,7 @@ /* By: cacharle +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/02/26 15:33:51 by cacharle #+# #+# */ -/* Updated: 2020/09/14 15:36:04 by charles ### ########.fr */ +/* Updated: 2020/09/14 19:50:06 by charles ### ########.fr */ /* */ /* ************************************************************************** */ @@ -48,7 +48,6 @@ # define BUILTIN_NOT_FOUND -2 -typedef t_ftht* t_path; typedef t_ftvec* t_env; extern int g_last_status; @@ -58,7 +57,7 @@ extern char *g_basename; ** path.c */ -t_path path_update(t_path path, char *path_var); +bool path_search(t_env env, char *exec_name, char exec_path[PATH_MAX + 1]); /* ** env.c diff --git a/minishell_test b/minishell_test index 55fab32..fec33d1 160000 --- a/minishell_test +++ b/minishell_test @@ -1 +1 @@ -Subproject commit 55fab322485f67112c789a4a529765b5e6635238 +Subproject commit fec33d1621e01e12a7dc64630477318213218ae7 diff --git a/src/builtin/pwd.c b/src/builtin/pwd.c index 0d8a7f1..ba4544a 100644 --- a/src/builtin/pwd.c +++ b/src/builtin/pwd.c @@ -6,7 +6,7 @@ /* By: charles +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/04/01 17:10:40 by charles #+# #+# */ -/* Updated: 2020/09/13 20:23:15 by charles ### ########.fr */ +/* Updated: 2020/09/14 21:27:54 by charles ### ########.fr */ /* */ /* ************************************************************************** */ @@ -30,14 +30,10 @@ int builtin_pwd(char **argv, t_env env) char *working_directory; (void)argv; - if ((working_directory = env_search(env, "PWD")) == NULL) - { - ft_bzero(buf, PATH_MAX); - if (getcwd(buf, PATH_MAX) == NULL) - return (1); - ft_putendl(buf); - } - else - ft_putendl(working_directory); + (void)env; + ft_bzero(buf, PATH_MAX); + if (getcwd(buf, PATH_MAX) == NULL) + return (1); + ft_putendl(buf); return (0); } diff --git a/src/eval/cmd.c b/src/eval/cmd.c index 455ff77..8e6e72a 100644 --- a/src/eval/cmd.c +++ b/src/eval/cmd.c @@ -6,7 +6,7 @@ /* By: charles +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/06/14 10:41:31 by charles #+# #+# */ -/* Updated: 2020/09/14 17:18:05 by charles ### ########.fr */ +/* Updated: 2020/09/14 21:32:19 by charles ### ########.fr */ /* */ /* ************************************************************************** */ @@ -36,7 +36,7 @@ int wrapped_cmd(void *void_param) } } -int eval_cmd(int fds[2], t_env env, t_path path, t_ast *ast, pid_t *child_pid) +int eval_cmd(int fds[2], t_env env, t_ast *ast, pid_t *child_pid) { t_fork_param_cmd param; char **argv; @@ -54,13 +54,13 @@ int eval_cmd(int fds[2], t_env env, t_path path, t_ast *ast, pid_t *child_pid) if (param.builtin == NULL) { - status = exec_search_path(path, env_search(env, "PATH"), argv[0], ¶m.exec_path); - if (status != 0) + + if (!path_search(env, argv[0], param.exec_path)) { - if (status == 127) - errorf("%s: command not found\n", argv[0]); + /* printf("--------%s---\n", env_search(env, "PATH")); */ + errorf("%s: command not found\n", argv[0]); ft_split_destroy(argv); - return (status); + return (127); } if ((status = exec_path_check(param.exec_path)) != 0) return (status); diff --git a/src/eval/eval.c b/src/eval/eval.c index 351c870..ee5c009 100644 --- a/src/eval/eval.c +++ b/src/eval/eval.c @@ -6,7 +6,7 @@ /* By: charles +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/09/13 20:38:06 by charles #+# #+# */ -/* Updated: 2020/09/14 16:49:31 by charles ### ########.fr */ +/* Updated: 2020/09/14 19:39:33 by charles ### ########.fr */ /* */ /* ************************************************************************** */ @@ -62,13 +62,13 @@ int fork_wrap( ** \return The last command status or EVAL_FATAL on error */ -int eval(int fds[2], t_env env, t_path path, t_ast *ast, pid_t *child_pid) +int eval(int fds[2], t_env env, t_ast *ast, pid_t *child_pid) { if (ast->tag == AST_PARENT) - return (eval_parenthesis(fds, env, path, ast)); + return (eval_parenthesis(fds, env, ast)); if (ast->tag == AST_OP) - return (eval_operation(fds, env, path, ast)); + return (eval_operation(fds, env, ast)); if (ast->tag == AST_CMD) - return (eval_cmd(fds, env, path, ast, child_pid)); + return (eval_cmd(fds, env, ast, child_pid)); return (EVAL_FATAL); } diff --git a/src/eval/exec.c b/src/eval/exec.c index e8e13e1..f733c34 100644 --- a/src/eval/exec.c +++ b/src/eval/exec.c @@ -6,7 +6,7 @@ /* By: charles +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/04/01 17:06:11 by charles #+# #+# */ -/* Updated: 2020/09/14 17:20:50 by charles ### ########.fr */ +/* Updated: 2020/09/14 19:48:49 by charles ### ########.fr */ /* */ /* ************************************************************************** */ @@ -31,7 +31,6 @@ int exec_path_check(char *exec_path) return (errorf_ret(127, "%s: %s\n", exec_path, strerror(errno))); if (S_ISDIR(statbuf.st_mode)) return (errorf_ret(126, "%s: Is a directory\n", exec_path)); - // if (!(statbuf.st_mode & 0444)) return (errorf_ret(126, "%s: %s\n", exec_path, strerror(EACCES))); return (0); @@ -45,20 +44,22 @@ int exec_path_check(char *exec_path) ** \return Executable path or NULL if not found or path update error */ -int exec_search_path(t_path path, char *path_var, char *exec_name, char **exec_path) -{ - if (ft_strchr(exec_name, '/') != NULL) // TODO test recursive link - { - *exec_path = exec_name; - return (0); - } - // TODO if PATH contain empty path, consider current directory files as cmd - if ((*exec_path = ft_htget(path, exec_name)) == NULL) - { - if (path_update(path, path_var) == NULL) // optimise by not updating not changed path in ht - return (EVAL_FATAL); // FIXME need to distiguish between malloc error and cmd not found error - if ((*exec_path = ft_htget(path, exec_name)) == NULL) - return (127); - } - return (0); -} +/* int exec_search_path(t_path path, char *path_var, char *exec_name, char **exec_path) */ +/* { */ +/* if (ft_strchr(exec_name, '/') != NULL) // TODO test recursive link */ +/* { */ +/* *exec_path = exec_name; */ +/* return (0); */ +/* } */ +/* if (path_var == NULL) */ +/* return (127); */ +/* // TODO if PATH contain empty path, consider current directory files as cmd */ +/* if ((*exec_path = ft_htget(path, exec_name)) == NULL) */ +/* { */ +/* if (path_update(path, path_var) == NULL) */ +/* return (EVAL_FATAL); */ +/* if ((*exec_path = ft_htget(path, exec_name)) == NULL) */ +/* return (127); */ +/* } */ +/* return (0); */ +/* } */ diff --git a/src/eval/operation.c b/src/eval/operation.c index eaafcf8..8c80033 100644 --- a/src/eval/operation.c +++ b/src/eval/operation.c @@ -6,13 +6,13 @@ /* By: charles +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/06/17 15:27:22 by charles #+# #+# */ -/* Updated: 2020/09/13 20:38:26 by charles ### ########.fr */ +/* Updated: 2020/09/14 19:39:16 by charles ### ########.fr */ /* */ /* ************************************************************************** */ #include "eval.h" -int eval_operation(int fds[2], t_env env, t_path path, t_ast *ast) +int eval_operation(int fds[2], t_env env, t_ast *ast) { int status; int left_fds[2]; @@ -31,9 +31,9 @@ int eval_operation(int fds[2], t_env env, t_path path, t_ast *ast) pid_t left_pid; pid_t right_pid; - eval(left_fds, env, path, ast->op.left, &left_pid); + eval(left_fds, env, ast->op.left, &left_pid); close(p[FD_WRITE]); - eval(right_fds, env, path, ast->op.right, &right_pid); + eval(right_fds, env, ast->op.right, &right_pid); close(p[FD_READ]); pid_t finished; @@ -49,12 +49,12 @@ int eval_operation(int fds[2], t_env env, t_path path, t_ast *ast) } return (0); } - if ((status = eval(left_fds, env, path, ast->op.left, NULL)) == EVAL_FATAL) + if ((status = eval(left_fds, env, ast->op.left, NULL)) == EVAL_FATAL) return (EVAL_FATAL); g_last_status = status; if ((ast->op.sep == TAG_AND && status != 0) || (ast->op.sep == TAG_PIPE && status != 0) || (ast->op.sep == TAG_OR && status == 0)) return (status); - return (eval(right_fds, env, path, ast->op.right, NULL)); + return (eval(right_fds, env, ast->op.right, NULL)); } diff --git a/src/eval/parenthesis.c b/src/eval/parenthesis.c index 8983378..610218b 100644 --- a/src/eval/parenthesis.c +++ b/src/eval/parenthesis.c @@ -6,7 +6,7 @@ /* By: charles +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/09/13 20:38:29 by charles #+# #+# */ -/* Updated: 2020/09/13 20:40:19 by charles ### ########.fr */ +/* Updated: 2020/09/14 19:40:12 by charles ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,10 +17,10 @@ int wrapped_eval(void *void_param) t_fork_param_args *param; param = void_param; - return (eval(param->fds, param->env, param->path, param->ast, NULL)); + return (eval(param->fds, param->env, param->ast, NULL)); } -int eval_parenthesis(int fds[2], t_env env, t_path path, t_ast *ast) +int eval_parenthesis(int fds[2], t_env env, t_ast *ast) { int status; t_fork_param_args param; @@ -31,7 +31,6 @@ int eval_parenthesis(int fds[2], t_env env, t_path path, t_ast *ast) param.fds[0] = fds[0]; param.fds[1] = fds[1]; param.env = env; - param.path = path; param.ast = ast->parent_ast; return (fork_wrap(fds, ¶m, wrapped_eval, NULL)); } diff --git a/src/main.c b/src/main.c index 2e44b0e..5173a5d 100644 --- a/src/main.c +++ b/src/main.c @@ -6,7 +6,7 @@ /* By: cacharle +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/02/28 11:45:44 by cacharle #+# #+# */ -/* Updated: 2020/09/14 16:24:30 by charles ### ########.fr */ +/* Updated: 2020/09/14 21:32:07 by charles ### ########.fr */ /* */ /* ************************************************************************** */ @@ -28,10 +28,9 @@ void tok_lst_debug(t_tok_lst *tokens); /* ** TODO -** $? -** pipe make 2 new children -** concurrent pipeline -** signal on whole line instead of single command +** signal whole line +** path optimisation on command not found +** path tricks */ bool env_set_default(t_env env, char *key, char *value) @@ -45,7 +44,6 @@ char *g_basename = "minishell"; int main(int argc, char **argv, char **envp) { - t_path path; t_env env; env = env_from_array(envp); @@ -67,22 +65,18 @@ int main(int argc, char **argv, char **envp) !env_set_default(env, "PATH", "/sbin:")) return (1); -#ifndef MINISHELL_TEST - char *path_str = env_search(env, "PATH"); - if (ft_strstr(path_str, "/sbin") == NULL) - { - char *value = ft_strjoin("/sbin:", path_str); - env_export(env, "PATH", value); - free(value); - } -#endif - - path = path_update(NULL, env_search(env, "PATH")); + /* char *path_str = env_search(env, "PATH"); */ + /* if (ft_strstr(path_str, "/sbin") == NULL) */ + /* { */ + /* char *value = ft_strjoin("/sbin:", path_str); */ + /* env_export(env, "PATH", value); */ + /* free(value); */ + /* } */ - char *env_exec_path; - if ((env_exec_path = ft_htget(path, "env")) == NULL) + char env_exec_path[PATH_MAX + 1]; + if (!path_search(env, "env", env_exec_path)) { - env_exec_path = "/sbin/env"; + ft_strcpy(env_exec_path, "/sbin/env"); /* errorf("env: command not found\n"); */ /* return (127); */ } @@ -126,7 +120,7 @@ int main(int argc, char **argv, char **envp) /* printf("===redirs===\n"); */ /* ft_lstiter(parser_out->ast->redirs, token_debug); */ int fds[2] = {FD_NONE, FD_NONE}; - status = eval(fds, env, path, parser_out->ast, NULL); + status = eval(fds, env, parser_out->ast, NULL); if (status == EVAL_FATAL) exit(1); g_last_status = status; @@ -162,7 +156,7 @@ int main(int argc, char **argv, char **envp) } int fds[2] = {FD_NONE, FD_NONE}; - int status = eval(fds, env, path, parser_out->ast, NULL); + int status = eval(fds, env, parser_out->ast, NULL); if (status == EVAL_FATAL) exit(1); g_last_status = status; @@ -172,7 +166,6 @@ int main(int argc, char **argv, char **envp) return (1); } - ft_htdestroy(path, free); ft_vecdestroy(env, free); return (g_last_status); } diff --git a/src/path.c b/src/path.c index 0de0bad..442389b 100644 --- a/src/path.c +++ b/src/path.c @@ -6,77 +6,70 @@ /* By: cacharle +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/02/27 15:51:01 by cacharle #+# #+# */ -/* Updated: 2020/09/09 15:49:50 by charles ### ########.fr */ +/* Updated: 2020/09/14 20:44:39 by charles ### ########.fr */ /* */ /* ************************************************************************** */ /* ** \file path.c -** \brief Path hash table manipulation +** \brief Path search */ #include "minishell.h" -/* -** \brief Number of buckets of a path hash table -*/ - -#define MS_PATH_HT_SIZE 8192 - -/* -** \brief Update `path` with all files -** in the directory named `dirname`. -** \param path Path hash table -** \param dirname directory name -** \return -1 on error, 0 or -2 otherwise -*/ - -static int st_add_directory(t_path path, char *dirname) +static bool st_dir_search(char *dirname, char *exec_name, char exec_path[PATH_MAX + 1]) { DIR *dir; struct dirent *entry; if ((dir = opendir(dirname)) == NULL) - return (-2); + return (false); while ((entry = readdir(dir)) != NULL) { - if (ft_htset_safe(path, entry->d_name, - ft_strjoin3(dirname, "/", entry->d_name), free) == NULL) + if (ft_strcmp(entry->d_name, exec_name) == 0) { - closedir(dir); - return (-1); + ft_strcpy(exec_path, dirname); + ft_strcat(exec_path, "/"); + ft_strcat(exec_path, exec_name); + return (true); } } - if (closedir(dir) == -1) - return (-1); - return (0); + closedir(dir); + return (false); } -/* -** \brief Update the path -** \param path Path hash table or NULL to create a new one -** \param path_var PATH environment variable where -** each directory is separated by a ':' -** \return The updated/created path hash table or NULL on error -*/ - -// TODO check nullstring path == current directory -// i.e ./ not needed before executable -t_path path_update(t_path path, char *path_var) +bool path_search(t_env env, char *exec_name, char exec_path[PATH_MAX + 1]) { - int i; - char **dirs; + char *current_dir; + char *collon; + char cwd[PATH_MAX + 1]; + + if (ft_strchr(exec_name, '/') != NULL) + { + ft_strcpy(exec_path, exec_name); + return (true); + } + /* printf("==========\n"); */ + if ((current_dir = env_search(env, "PATH")) == NULL) + return (st_dir_search(getcwd(cwd, PATH_MAX + 1), exec_name, exec_path)); + /* printf("%s\n", current_dir); */ + while ((collon = ft_strchr(current_dir, ':')) != NULL) + { + *collon = '\0'; + /* printf("%s\n", current_dir); */ + if (*current_dir == '\0') + current_dir = getcwd(cwd, PATH_MAX + 1); + if (st_dir_search(current_dir, exec_name, exec_path)) + return (true); + *collon = ':'; + current_dir = collon + 1; + } + /* printf("> %s\n", current_dir); */ - if (path_var == NULL) - return (NULL); - if (path == NULL && (path = ft_htnew(MS_PATH_HT_SIZE)) == NULL) - return (NULL); - if ((dirs = ft_split(path_var, ':')) == NULL) - return (NULL); - i = -1; - while (dirs[++i] != NULL) - if (st_add_directory(path, dirs[i]) == -1) - return (ft_split_destroy(dirs)); - ft_split_destroy(dirs); - return (path); + if (*current_dir == '\0') + current_dir = getcwd(cwd, PATH_MAX + 1); + if (st_dir_search(current_dir, exec_name, exec_path)) + return (true); + /* printf("yo\n"); */ + return (false); } -- cgit