From a167dfecc903488a93e425d245cc8536207d2259 Mon Sep 17 00:00:00 2001 From: alistair Date: Tue, 26 Nov 2019 13:50:14 +1000 Subject: [PATCH] Basic support for variables set drop listvars --- error.h | 1 + main.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++----- main.h | 24 +++++- util.c | 14 +++- util.h | 2 + 5 files changed, 250 insertions(+), 19 deletions(-) diff --git a/error.h b/error.h index adf6b09..dae2bf3 100644 --- a/error.h +++ b/error.h @@ -6,6 +6,7 @@ enum ExitCodes { ER_SUCCESS, ER_FAILURE, ER_FAIL_TO_FORK, + ER_NOT_EXISTS, ER_ALLOC }; diff --git a/main.c b/main.c index fdc572e..a2e75fa 100644 --- a/main.c +++ b/main.c @@ -3,6 +3,21 @@ #include "main.h" #include "util.h" +#include + +int get_alias(Alias *alias, State *state, char *name); +int add_alias(State* state, char *name, char *substitution); +int del_alias(State *state, char *name); +int repl(State* state, FILE *input); + +GrowingArray get_growing_array(size_t num_elements, size_t size_elem) { + GrowingArray arr; + arr.inner = calloc(num_elements, size_elem); + arr.space = num_elements; + arr.elements = 0; + return arr; +} + int get_alias(Alias *alias, State *state, char *name) { for (int i = 0; i < state->num_aliases; i++) { if (!strcmp(name, state->aliases[i].name)) { @@ -13,9 +28,100 @@ int get_alias(Alias *alias, State *state, char *name) { return ER_FAILURE; } -int del_alias(State *state, char *name); +int get_array_element(ArrayElement **ret, GrowingArray* array, char* key) { + for (int i = 0; i < array->elements; i++) { + if (!strcmp(key, array->inner[i].key)) { + *ret = array->inner + i; + return ER_SUCCESS; + } + } + return ER_NOT_EXISTS; +} + +int check_array_space(GrowingArray* array) { + int resize = 0; + if (array->elements > MIN_ARRAY_SIZE) { + if (array->elements >= array->space - 2) { + resize = 2 * array->space; + } else if (array->elements < (array->space / 3)) { + resize = array->space / 2; + } + } + + if (resize) { + void *new = reallocarray(array->inner, resize, + sizeof(ArrayElement)); + if (new) { + array->space = resize; + array->inner = new; + return ER_SUCCESS; + } else { + return ER_FAILURE; + } + } else { + return ER_SUCCESS; + } +} -int add_alias(State* state, char *name, char *substitution) { +int set_array_element(GrowingArray* array, char* key, void* value, + size_t valsize) { + ArrayElement *arr; + if (!get_array_element(&arr, array, key)) { + free(arr->value); + arr->value = dualloc(value, valsize); + return ER_SUCCESS; + } else { + check_array_space(array); + void *val = dualloc(value, valsize); + void *nkey = dualloc(key, (strlen(key) + 1) * sizeof(char)); + if (value && key) { + array->inner[array->elements].value = val; + array->inner[array->elements].key = nkey; + array->elements++; + return ER_SUCCESS; + } + } + return ER_FAILURE; +} + +int del_array_element(GrowingArray* array, char* key) { + ArrayElement *elem; + int err = get_array_element(&elem, array, key); + if (err) { + return err; + } else { + bool move = false; + for (int i = 0; i < array->elements; i++) { + if (move) { + if (i == array->elements - 1) { + memset(&array->inner[i], 0, sizeof(ArrayElement)); + } else { + array->inner[i] = array->inner[i+1]; + } + } + if (!strcmp(array->inner[i].key, key)) { + if (!move) { + free(array->inner[i].key); + free(array->inner[i].value); + move = true; + // move + if (i == array->elements - 1) { + memset(&array->inner[i], 0, sizeof(ArrayElement)); + } else { + array->inner[i] = array->inner[i+1]; + } + + } + } + } + + array->elements--; + return ER_SUCCESS; + } + return ER_FAILURE; +} + +int add_alias(State* state, char* name, char* substitution) { Alias alias; strip_char(name, ' '); alias.name = calloc(strlen(name) + 1, sizeof(char)); @@ -23,9 +129,9 @@ int add_alias(State* state, char *name, char *substitution) { strcpy(alias.name, name); strcpy(alias.substitution, substitution); - Alias throw; + Alias existing; - if (get_alias(&throw, state, name)) { + if (get_alias(&existing, state, name)) { // add it if it doesnt exist state->aliases[state->num_aliases] = alias; @@ -74,6 +180,25 @@ int list_aliases(State *state) { return ER_SUCCESS; } +int list_variables(State *state) { + for (int i = 0; i < state->variables.elements; i++) { + char *key = state->variables.inner[i].key; + char *value = state->variables.inner[i].value; + fprintf(state->output, "%s=%s\n", key, value); + } + return ER_SUCCESS; +} + +void shutdown(State *state) { + for (int i = 0; i < state->num_aliases; i++) { + free(state->aliases[i].name); + free(state->aliases[i].substitution); + } + free(state->ps1); + free(state); + exit(0); +} + int check_builtins(State *state, int num_args, char *args[]) { char *builtins[NUM_BUILTINS] = { "cd", @@ -82,19 +207,54 @@ int check_builtins(State *state, int num_args, char *args[]) { }; if (!strcmp(args[0], "cd")) { - if (num_args == 1) { chdir(getenv("HOME")); return ER_SUCCESS; } - if (num_args != 2) { return ER_FAILURE; } - chdir(args[1]); } + if (!strcmp(args[0], "set")) { + if (num_args >= 2) { + char *joined; + int err = join_string(&joined, num_args -1, args + 1, " "); + char **split; + int num; + err = split_string(&split, &num, joined, '='); + if (num == 2) { + char * key = split[0]; + char * value = split[1]; + set_array_element(&state->variables, key, value, + (strlen(value) + 1) * sizeof(char)); + return ER_SUCCESS; + } else { + return ER_FAILURE; + } + } + } + + if (!strcmp(args[0], "listvars")) { + list_variables(state); + return ER_SUCCESS; + } + + if (!strcmp(args[0], "drop")) { + if (num_args == 2) { + char *key = args[1]; + int err = del_array_element(&state->variables, key); + if (err) { + return ER_FAILURE; + } else { + return ER_SUCCESS; + } + } + return ER_FAILURE; + + } + if (!strcmp(args[0], "alias")) { Alias alias; // list aliases @@ -106,14 +266,16 @@ int check_builtins(State *state, int num_args, char *args[]) { if (num_args >= 2) { if (num_args == 2) { if (!get_alias(&alias, state, args[1])) { - fprintf(state->output, "alias %s=%s\n", alias.name, alias.substitution); + fprintf(state->output, "alias %s=%s\n", alias.name, + alias.substitution); return ER_SUCCESS; } } if (num_args >= 2) { char *substitution; char **new_split; - int err = join_string(&substitution, num_args - 1, args + 1, " "); + int err = join_string(&substitution, num_args - 1, + args + 1, " "); if (err) { return err; } @@ -141,7 +303,33 @@ int check_builtins(State *state, int num_args, char *args[]) { } } - return ER_FAILURE; + if (!strcmp(args[0], "run")) { + if (num_args == 2) { + FILE *file = fopen(args[1], "r"); + if (!file) { + return ER_FAILURE; + } + bool temp_repl_state = state->interactive; + state->interactive = false; + int err; + if ((err = repl(state, file))) { + perror("Config file error"); + return err; + } + state->interactive = temp_repl_state; + fclose(file); + + return ER_SUCCESS; + } + } + + if (!strcmp(args[0], "exit")) { + if (num_args == 1) { + shutdown(state); + return ER_FAILURE; + } + } + return ER_NOT_EXISTS; } int check_aliases(State *state, char **substitution, char *name) { @@ -155,6 +343,7 @@ int check_aliases(State *state, char **substitution, char *name) { return ER_FAILURE; } + int run_command(State *state, int argc, char *argv[]) { pid_t child; @@ -184,7 +373,7 @@ int run_command(State *state, int argc, char *argv[]) { free(new_argv); } - if (check_builtins(state, argc, argv)) { + if (check_builtins(state, argc, argv) == ER_NOT_EXISTS) { execute(stdin, stdout, argv, &child); waitpid(child, NULL, 0); } @@ -196,8 +385,8 @@ int repl(State* state, FILE *input) { while (true) { char *line; - if (state->repl) { - fprintf(state->output, "$ "); + if (state->interactive) { + fprintf(state->output, "%s", state->ps1); } if (readline(input, &line)) { @@ -223,6 +412,11 @@ int repl(State* state, FILE *input) { int startup(State *state, int argc, char **argv) { state->output = stdout; + state->ps1 = calloc(3, sizeof(char)); + strcpy(state->ps1, "$ "); + + state->variables = get_growing_array(INITIAL_NUM_VARIABLES, sizeof(char*)); + char *config_home; char *config = calloc(500, sizeof(char)); if ((config_home = getenv("XDG_CONFIG_HOME"))) { @@ -240,13 +434,14 @@ int startup(State *state, int argc, char **argv) { int err; FILE* rc = fopen(config, "r"); if (rc) { - state->repl = false; + state->interactive = false; state->input = rc; if ((err = repl(state, rc))) { perror("Config file error"); return err; } } + fclose(rc); if (argc == 2) { FILE *script_text = fopen(argv[1], "r"); @@ -262,7 +457,6 @@ int startup(State *state, int argc, char **argv) { } int main(int argc, char** argv) { - State *state = calloc(1, sizeof(State)); state->aliases = calloc(INITIAL_NUM_ALIASES, sizeof(struct Alias)); state->num_aliases = 0; @@ -273,10 +467,10 @@ int main(int argc, char** argv) { } if (state->code) { - state->repl = false; + state->interactive = false; repl(state, state->code); } else { - state->repl = true; + state->interactive = true; print_chicken(state); repl(state, stdin); } diff --git a/main.h b/main.h index 5a78bcf..3d63bdc 100644 --- a/main.h +++ b/main.h @@ -13,6 +13,11 @@ #define INITIAL_LINE_BUFFER 80 #define INITIAL_WORD_SIZE 80 #define INITIAL_NUM_ALIASES 50 +#define INITIAL_NUM_VARIABLES 200 + +// the minimum size of an array, the automaic array allocator will not make +// arrays smaller than this +#define MIN_ARRAY_SIZE 50 #define NUM_BUILTINS 3 @@ -21,13 +26,30 @@ struct Alias { char *substitution; }; +struct ArrayElement { + void *value; + char *key; +}; + +typedef struct ArrayElement ArrayElement; + +struct GrowingArray { + struct ArrayElement *inner; + int elements; + int space; +}; + +typedef struct GrowingArray GrowingArray; + struct State { struct Alias* aliases; + struct GrowingArray variables; int num_aliases; FILE* code; FILE *input; FILE *output; - bool repl; + bool interactive; + char *ps1; }; typedef struct State State; diff --git a/util.c b/util.c index b1183b3..36e63c8 100644 --- a/util.c +++ b/util.c @@ -1,5 +1,15 @@ #include "util.h" +void *dualloc(void *thing, size_t size) { + + void *dupl = malloc(size); + memset(dupl, 0, size); + memcpy(dupl, thing, size); + + return dupl; +} + +/* Read a line into a newly created buffer */ int readline(FILE* in, char **out) { int size_of_buffer = INITIAL_LINE_BUFFER; char *buffer = calloc(size_of_buffer, sizeof(char)); @@ -44,7 +54,8 @@ int join_string(char **joined, int arr_len, char *sep_stirng[], char *delim) { for (int i = 0; i < arr_len; i++) { if (length == stringsize - 2) { - new_string = reallocarray(new_string, stringsize *= 2, sizeof(char)); + new_string = reallocarray(new_string, stringsize *= 2, + sizeof(char)); } int len = strlen(sep_stirng[i]); @@ -68,6 +79,7 @@ int join_string(char **joined, int arr_len, char *sep_stirng[], char *delim) { return ER_FAILURE; } +/* Remove all instances of char del from the given string (in place). */ int strip_char(char *string, char del) { int len = strlen(string); bool move = false; diff --git a/util.h b/util.h index 430d118..71bba55 100644 --- a/util.h +++ b/util.h @@ -4,6 +4,8 @@ #ifndef UTILH #define UTILH +void *dualloc(void *thing, size_t size); + int readline(FILE* in, char **out); int split_string(char **sep_string[], int *num, char *string, char delim);