From: Jon Feldman Date: Wed, 26 Jul 2017 13:45:25 +0000 (-0400) Subject: misc: implement builtin cd, begin docs, fixups X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=26a7c55cc779f85e20ba36d3c9fbfb5673ee82f5;p=misc%2Fysh.git misc: implement builtin cd, begin docs, fixups --- diff --git a/DOC/DEFICIENCES.md b/DOC/DEFICIENCES.md new file mode 100644 index 0000000..e69de29 diff --git a/DOC/EXAMPLES.md b/DOC/EXAMPLES.md new file mode 100644 index 0000000..e69de29 diff --git a/DOC/PATH_RESOLUTION.md b/DOC/PATH_RESOLUTION.md new file mode 100644 index 0000000..e69de29 diff --git a/DOC/PITFALLS.md b/DOC/PITFALLS.md new file mode 100644 index 0000000..f619edf --- /dev/null +++ b/DOC/PITFALLS.md @@ -0,0 +1,51 @@ +Pitfalls and things not to assume +----------------------------------- + +Posix +------ + +This is not POSIX compliant. It is not intended to be, since this +contorts the shell into working in a certain manner, and in practice, +/bin/sh usually means /bin/bash. + +Subcommands +------------ + +Subcommands may very well look like the subshell "$()" / "`" operator +in bash. They are not. + +Commands are resolved in dependency order until no more replacements are +needed. This is contrary to how bash, zsh, etc work; they literally +spawn another shell to handle anything within. To explain with graphs: + +bash: echo $(echo hello $(echo world) ho) + +echo $ + echo hello $ ho + echo world + +xsh: echo {echo hello {echo world} ho} + +echo {echo hello $ ho} + echo world +echo $ + echo hello world ho + +This behavior has a few importan6 things to note about it. + 1) Subcommands inherit the environment of the shell, not + a "parent" subcommand. + 2) Subcommands do not spawn another shell. + +Variables +---------- + +Variables (starting with the $ character) are resolved after subcommands +and double-quoted strings. +Consider the following: + += NAME 42 +echo "${echo NAME}" + +So first, echo NAME is evaluated. The contents of the double-quoted string +are then evaluated, leaving a string named "$NAME". This is then interpreted to +be a variable, resulting in the output 42. diff --git a/builtin/cd.c b/builtin/cd.c index e69de29..da58cb4 100644 --- a/builtin/cd.c +++ b/builtin/cd.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int builtin_chdir(char* nam, char** argv, char** stdout) { + assert(nam); + assert(argv[0]); + + int ret = 0; + + if (argv[1] == NULL) { + // No path was provided in cd, so just go $HOME + } else if (argv[1]) { + ret = chdir(argv[1]); + } + + if (ret == -1) + perror("cd"); + + return ret; +} diff --git a/builtin/math.c b/builtin/math.c new file mode 100644 index 0000000..e69de29 diff --git a/gsh_main.c b/gsh_main.c index 0e77e3b..58e0fe6 100644 --- a/gsh_main.c +++ b/gsh_main.c @@ -348,6 +348,29 @@ pid_t fork_and_execvp(const char *file, char *const argv[], char** stdout) { return pid; } +typedef int (*builtin_fn_t)(char*, char**, char**); + +int builtin_chdir(char* nam, char** argv, char** stdout); + +typedef struct { + char name[64]; + builtin_fn_t func; +} builtin_info_t; + +builtin_info_t builtin_info[] = { + { "cd", builtin_chdir }, + { "", NULL }, +}; + +int check_builtin(char* name) { + for (int i = 0; builtin_info[i].func != NULL; i++) { + if (!strcmp(name, builtin_info[i].name)) { + return i; + } + } + return -1; +} + void execute(ast_t* tree, char** stdout) { // Important note; this function is only for fully resolved trees of commands. // If any unresolved subshells or groups exist, this function is undefined. @@ -369,9 +392,14 @@ void execute(ast_t* tree, char** stdout) { argv[tree->size] = NULL; prog = argv[0]; - pid_t pid = fork_and_execvp(prog, argv, stdout); - int wstatus; - pid = waitpid(pid, &wstatus, 0); + int builtin_chk = check_builtin(prog); + if (builtin_chk != -1) { + builtin_info[builtin_chk].func(prog, argv, stdout); + } else { + pid_t pid = fork_and_execvp(prog, argv, stdout); + int wstatus; + pid = waitpid(pid, &wstatus, 0); + } } void ast_resolve_subs(ast_t* ast, int master) {