diff options
| author | Douglas B. Rumbaugh <doug@douglasrumbaugh.com> | 2025-11-01 14:53:14 -0400 |
|---|---|---|
| committer | Douglas B. Rumbaugh <doug@douglasrumbaugh.com> | 2025-11-01 14:53:14 -0400 |
| commit | ddcf611815c145b1fadca042e65648a7a81cc497 (patch) | |
| tree | 9e11e5a372f2df528d162d17050eada50ad1db56 | |
| parent | 406889ed5c780f0e28703b143c72bbf035280b25 (diff) | |
| download | hush-ddcf611815c145b1fadca042e65648a7a81cc497.tar.gz | |
Added variable support
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | Makefile | 12 | ||||
| -rw-r--r-- | compile_flags.txt | 1 | ||||
| m--------- | external/libmap | 0 | ||||
| -rw-r--r-- | include/command.h | 8 | ||||
| -rw-r--r-- | include/variables.h | 29 | ||||
| -rw-r--r-- | src/command.c | 10 | ||||
| -rw-r--r-- | src/hush.c | 38 | ||||
| -rw-r--r-- | src/variables.c | 57 |
9 files changed, 148 insertions, 10 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..785aa2b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/libmap"] + path = external/libmap + url = git@hecate.lan:libmap.git @@ -1,8 +1,12 @@ all: bin/hush -bin/hush: build/lexer.o build/command.o src/hush.c build - gcc -Iinclude build/lexer.o build/command.o src/hush.c -ggdb -o bin/hush +LIBMAP_DIR := external/libmap +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 build/lexer.o: include/lexer.h src/lexer.c build gcc -Iinclude -c src/lexer.c -ggdb -o build/lexer.o @@ -10,6 +14,9 @@ build/lexer.o: include/lexer.h src/lexer.c build build/command.o: include/lexer.h include/command.h src/command.c gcc -Iinclude -c src/command.c -ggdb -o build/command.o +build/variables.o: include/variables.h + gcc -Iinclude -I$(LIBMAP_DIR)/include -c src/variables.c -ggdb -o build/variables.o + .PHONY: build clean build: -mkdir build @@ -18,5 +25,6 @@ build: clean: -rm -r build -rm -r bin + make -C $(LIBMAP_DIR) clean diff --git a/compile_flags.txt b/compile_flags.txt index 30679be..16adf22 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1 +1,2 @@ -Iinclude +-Iexternal/libmap/include diff --git a/external/libmap b/external/libmap new file mode 160000 +Subproject f16156b328c87630e0c7da036353b9992b9dbf0 diff --git a/include/command.h b/include/command.h index f44c103..2948aca 100644 --- a/include/command.h +++ b/include/command.h @@ -11,16 +11,16 @@ #include "config.h" typedef struct command { - char *command; - char *infile; - char *outfile; + const char *command; + const char *infile; + const char *outfile; struct command *next; struct command *prev; pid_t pid; int pipe[2]; - char *args[MAX_ARGUMENT_CNT + 2]; + const char *args[MAX_ARGUMENT_CNT + 2]; } command; diff --git a/include/variables.h b/include/variables.h new file mode 100644 index 0000000..7511690 --- /dev/null +++ b/include/variables.h @@ -0,0 +1,29 @@ +/* + * + */ +#ifndef H_HUSH_VARIABLES +#define H_HUSH_VARIABLES + +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> + +#include "strmap.h" +#include "hashfuncs.h" + +static inline bool is_variable(const char *token) { + return (token) ? token[0] == '$' : false; +} + +bool init_variable_store(void); + +bool add_variable(const char *key, const char *val); + +const char *get_variable(const char *key); + +bool promote_variable_to_env(const char *key); + +void destroy_variable_store(); + + +#endif diff --git a/src/command.c b/src/command.c index 20b00b1..3d63121 100644 --- a/src/command.c +++ b/src/command.c @@ -119,7 +119,15 @@ pid_t execute_command(command *cmd) { close(cmd->pipe[1]); } - execvp(cmd->command, cmd->args); + /* + * NOTE: discarding the const qualifier here is okay because either + * 1) exec fails, in which case the process is aborted immediately + * 2) exec succeeds, in which case the memory is released immediately + * + * In either case, the args won't be accessed again. + */ + execvp(cmd->command, (char**)cmd->args); + perror("Could not run command"); exit(EXIT_FAILURE); } else if (res < 0) { @@ -14,6 +14,7 @@ #include "config.h" #include "lexer.h" #include "command.h" +#include "variables.h" FILE *open_input(int argc, char **argv) { FILE *input_file = (argc > 1) ? fopen(argv[1], "r") : stdin; @@ -34,10 +35,38 @@ static size_t get_command_len(char *cmdstr) { return len; } +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]); + } + } + + if (is_variable(cmd->outfile)) { + cmd->outfile = get_variable(cmd->outfile); + } + + if (is_variable(cmd->infile)) { + cmd->infile = get_variable(cmd->infile); + } + + fprintf(stderr, "After substitution\n"); + print_commands(stderr, cmd); + } +} + int main(int argc, char **argv) { FILE *input_file = open_input(argc, argv); char buffer[MAX_LINE_LEN]; + if (!init_variable_store()) { + fprintf(stderr, "ERROR: Failed to initialize variable store\n"); + exit(EXIT_FAILURE); + } + fprintf(stdout, "$ "); while (fgets(buffer, MAX_LINE_LEN, input_file)) { char *cmdstr = trim(buffer); @@ -68,7 +97,9 @@ int main(int argc, char **argv) { // print_parsed_command(stdout, parsed_cmd); if (parsed_cmd->type == TKN_VARKEY) { - /* handle variable creation */ + if (!add_variable(parsed_cmd->text, parsed_cmd->next->text)) { + fprintf(stderr, "ERROR: Failed to create variable\n"); + } goto free_tokens; } @@ -79,6 +110,7 @@ int main(int argc, char **argv) { goto free_tokens; } + variable_substitution(cmds); for (command *cmd = cmds; cmd; cmd = cmd->next) { pid_t result = execute_command(cmd); @@ -91,9 +123,7 @@ int main(int argc, char **argv) { for (command *cmd = cmds; cmd; cmd = cmd->next) { if (cmd->pid > 0) { - fprintf(stderr, "Waiting for %d\n", cmd->pid); waitpid(cmd->pid, NULL, 0); - fprintf(stderr, "%d completed\n", cmd->pid); } } @@ -107,4 +137,6 @@ int main(int argc, char **argv) { draw_prompt: fprintf(stdout, "$ "); } + + destroy_variable_store(); } diff --git a/src/variables.c b/src/variables.c new file mode 100644 index 0000000..c7cc4da --- /dev/null +++ b/src/variables.c @@ -0,0 +1,57 @@ +/* + * + */ + +#include "variables.h" +#include "strmap.h" + +static strmap *map; + +bool init_variable_store(void) { + map = strmap_create(hash_key); + return map; +} + +bool add_variable(const char *key, const char *val) { + if (strmap_put(map, key, val) != STRMAP_OK) { + return false; + } + + return true; +} + +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); + switch (stat) { + case STRMAP_OK: + break; + case STRMAP_NOTFOUND: + val = getenv(key); + break; + default: + val = NULL; + break; + } + + val = (val) ? val : ""; + fprintf(stderr, "Value is: %s\n", val); + + return val; +} + +bool promote_variable_to_env(const char *key) { + const char *val = get_variable(key); + if (!val) { + val = ""; + } + + return !setenv(key, val, 1); +} + +void destroy_variable_store() { + strmap_destroy(map); +} |