From f84e64b593c6e6fda9e2a907d25ed99d8742d619 Mon Sep 17 00:00:00 2001 From: "Douglas B. Rumbaugh" Date: Sat, 1 Nov 2025 15:18:03 -0400 Subject: Added support for required builtins --- Makefile | 8 ++++-- include/builtin.h | 20 +++++++++++++++ src/builtin.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/hush.c | 18 +++++-------- src/variables.c | 7 +----- 5 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 include/builtin.h create mode 100644 src/builtin.c diff --git a/Makefile b/Makefile index fbe4e9d..c860407 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,8 @@ LIBMAP_LIB := $(LIBMAP_DIR)/lib/libmap.a $(LIBMAP_LIB): $(LIBMAP_DIR)/Makefile make -C $(LIBMAP_DIR) lib/libmap.a -bin/hush: build/lexer.o build/command.o src/hush.c build build/variables.o $(LIBMAP_LIB) - gcc -Iinclude -I$(LIBMAP_DIR)/include build/lexer.o build/command.o build/variables.o src/hush.c $(LIBMAP_LIB) -ggdb -o bin/hush +bin/hush: build/lexer.o build/command.o src/hush.c build build/variables.o build/builtin.o $(LIBMAP_LIB) + gcc -Iinclude -I$(LIBMAP_DIR)/include build/lexer.o build/command.o build/variables.o build/builtin.o src/hush.c $(LIBMAP_LIB) -ggdb -o bin/hush build/lexer.o: include/lexer.h src/lexer.c build gcc -Iinclude -c src/lexer.c -ggdb -o build/lexer.o @@ -17,6 +17,10 @@ build/command.o: include/lexer.h include/command.h src/command.c build/variables.o: include/variables.h gcc -Iinclude -I$(LIBMAP_DIR)/include -c src/variables.c -ggdb -o build/variables.o +build/builtin.o: include/builtin.h include/variables.h + gcc -Iinclude -I$(LIBMAP_DIR)/include -c src/builtin.c -ggdb -o build/builtin.o + + .PHONY: build clean build: -mkdir build diff --git a/include/builtin.h b/include/builtin.h new file mode 100644 index 0000000..1c99ef5 --- /dev/null +++ b/include/builtin.h @@ -0,0 +1,20 @@ +/* + * + */ +#ifndef H_HUSH_BUILTIN +#define H_HUSH_BUILTIN + +#include +#include + +#include "command.h" +#include "variables.h" + +/* + * Check if the provided command corresponds with a known built-in + * function. If so, run the builtin and return true. If not, return + * false. + */ +bool run_builtin(command *cmd); + +#endif diff --git a/src/builtin.c b/src/builtin.c new file mode 100644 index 0000000..f22ce33 --- /dev/null +++ b/src/builtin.c @@ -0,0 +1,75 @@ +/* + * + */ +#include "builtin.h" +#include "variables.h" +#include + +struct builtin { + char *name; + int (*builtin_func)(const char **); +}; + +static int builtin_cd(const char *args[]) { + const char *dir = (args[1]) ? args[1] : get_variable("$HOME"); + int res = chdir(dir); + + if (res != 0) { + perror("cd:"); + return 0; + } + + return 1; +} + +static int builtin_export(const char *args[]) { + const char *key = args[1]; + + if (!key) { + fprintf(stderr, "export: no variable name specified\n"); + return 0; + } + + if (!promote_variable_to_env(key)) { + perror("export:"); + return 0; + } + + return 1; +} + +static int builtin_pwd(const char *args[]) { + char buffer[PATH_MAX]; + char *path = getcwd(buffer, PATH_MAX); + if (path) { + fprintf(stdout, "%s\n", path); + return 1; + } + + perror("pwd:"); + return 0; +} + +static int builtin_exit(const char *args[]) { exit(EXIT_SUCCESS); } + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +static struct builtin builtin_lookup[] = { + {.name = "cd", .builtin_func = builtin_cd}, + {.name = "export", .builtin_func = builtin_export}, + {.name = "pwd", .builtin_func = builtin_pwd}, + {.name = "exit", .builtin_func = builtin_exit}}; + +static const size_t BUILTIN_CNT = ARRAY_SIZE(builtin_lookup); + +bool run_builtin(command *cmd) { + + for (size_t i = 0; i < BUILTIN_CNT; i++) { + if (!strcmp(cmd->command, builtin_lookup[i].name)) { + builtin_lookup[i].builtin_func(cmd->args); + return true; + } + } + + return false; +} diff --git a/src/hush.c b/src/hush.c index 0d25244..2d40aa7 100644 --- a/src/hush.c +++ b/src/hush.c @@ -15,6 +15,7 @@ #include "lexer.h" #include "command.h" #include "variables.h" +#include "builtin.h" FILE *open_input(int argc, char **argv) { FILE *input_file = (argc > 1) ? fopen(argv[1], "r") : stdin; @@ -37,8 +38,6 @@ static size_t get_command_len(char *cmdstr) { void variable_substitution(command *cmds) { for (command *cmd = cmds; cmd; cmd = cmd->next) { - fprintf(stderr, "Before substitution\n"); - print_commands(stderr, cmd); for (size_t i=0; i < MAX_ARGUMENT_CNT + 1; i++) { if (is_variable(cmd->args[i])) { cmd->args[i] = get_variable(cmd->args[i]); @@ -52,9 +51,6 @@ void variable_substitution(command *cmds) { if (is_variable(cmd->infile)) { cmd->infile = get_variable(cmd->infile); } - - fprintf(stderr, "After substitution\n"); - print_commands(stderr, cmd); } } @@ -94,8 +90,6 @@ int main(int argc, char **argv) { } } - // print_parsed_command(stdout, parsed_cmd); - if (parsed_cmd->type == TKN_VARKEY) { if (!add_variable(parsed_cmd->text, parsed_cmd->next->text)) { fprintf(stderr, "ERROR: Failed to create variable\n"); @@ -113,14 +107,14 @@ int main(int argc, char **argv) { variable_substitution(cmds); for (command *cmd = cmds; cmd; cmd = cmd->next) { - pid_t result = execute_command(cmd); - if (result < 0) { - break; + if (!run_builtin(cmd)) { + pid_t result = execute_command(cmd); + if (result < 0) { + break; + } } } - // print_commands(stdout, cmds); - for (command *cmd = cmds; cmd; cmd = cmd->next) { if (cmd->pid > 0) { waitpid(cmd->pid, NULL, 0); diff --git a/src/variables.c b/src/variables.c index c7cc4da..c478d9d 100644 --- a/src/variables.c +++ b/src/variables.c @@ -21,8 +21,6 @@ bool add_variable(const char *key, const char *val) { } const char *get_variable(const char *key) { - fprintf(stderr, "Key is: %s\n", key); - key += (key[0] == '$'); const char *val; strmap_status stat = strmap_get(map, key, &val); @@ -37,10 +35,7 @@ const char *get_variable(const char *key) { break; } - val = (val) ? val : ""; - fprintf(stderr, "Value is: %s\n", val); - - return val; + return (val) ? val : ""; } bool promote_variable_to_env(const char *key) { -- cgit v1.2.3