Browse Source

Basic support for variables set drop listvars

master
alistair 5 years ago
parent
commit
a167dfecc9
  1. 1
      error.h
  2. 228
      main.c
  3. 24
      main.h
  4. 14
      util.c
  5. 2
      util.h

1
error.h

@ -6,6 +6,7 @@ enum ExitCodes {
ER_SUCCESS, ER_SUCCESS,
ER_FAILURE, ER_FAILURE,
ER_FAIL_TO_FORK, ER_FAIL_TO_FORK,
ER_NOT_EXISTS,
ER_ALLOC ER_ALLOC
}; };

228
main.c

@ -3,6 +3,21 @@
#include "main.h" #include "main.h"
#include "util.h" #include "util.h"
#include <dirent.h>
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) { int get_alias(Alias *alias, State *state, char *name) {
for (int i = 0; i < state->num_aliases; i++) { for (int i = 0; i < state->num_aliases; i++) {
if (!strcmp(name, state->aliases[i].name)) { if (!strcmp(name, state->aliases[i].name)) {
@ -13,9 +28,100 @@ int get_alias(Alias *alias, State *state, char *name) {
return ER_FAILURE; 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; Alias alias;
strip_char(name, ' '); strip_char(name, ' ');
alias.name = calloc(strlen(name) + 1, sizeof(char)); 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.name, name);
strcpy(alias.substitution, substitution); 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 // add it if it doesnt exist
state->aliases[state->num_aliases] = alias; state->aliases[state->num_aliases] = alias;
@ -74,6 +180,25 @@ int list_aliases(State *state) {
return ER_SUCCESS; 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[]) { int check_builtins(State *state, int num_args, char *args[]) {
char *builtins[NUM_BUILTINS] = { char *builtins[NUM_BUILTINS] = {
"cd", "cd",
@ -82,19 +207,54 @@ int check_builtins(State *state, int num_args, char *args[]) {
}; };
if (!strcmp(args[0], "cd")) { if (!strcmp(args[0], "cd")) {
if (num_args == 1) { if (num_args == 1) {
chdir(getenv("HOME")); chdir(getenv("HOME"));
return ER_SUCCESS; return ER_SUCCESS;
} }
if (num_args != 2) { if (num_args != 2) {
return ER_FAILURE; return ER_FAILURE;
} }
chdir(args[1]); 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")) { if (!strcmp(args[0], "alias")) {
Alias alias; Alias alias;
// list aliases // 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 (num_args == 2) { if (num_args == 2) {
if (!get_alias(&alias, state, args[1])) { 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; return ER_SUCCESS;
} }
} }
if (num_args >= 2) { if (num_args >= 2) {
char *substitution; char *substitution;
char **new_split; 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) { if (err) {
return 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) { 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; return ER_FAILURE;
} }
int run_command(State *state, int argc, char *argv[]) { int run_command(State *state, int argc, char *argv[]) {
pid_t child; pid_t child;
@ -184,7 +373,7 @@ int run_command(State *state, int argc, char *argv[]) {
free(new_argv); free(new_argv);
} }
if (check_builtins(state, argc, argv)) { if (check_builtins(state, argc, argv) == ER_NOT_EXISTS) {
execute(stdin, stdout, argv, &child); execute(stdin, stdout, argv, &child);
waitpid(child, NULL, 0); waitpid(child, NULL, 0);
} }
@ -196,8 +385,8 @@ int repl(State* state, FILE *input) {
while (true) { while (true) {
char *line; char *line;
if (state->repl) { if (state->interactive) {
fprintf(state->output, "$ "); fprintf(state->output, "%s", state->ps1);
} }
if (readline(input, &line)) { if (readline(input, &line)) {
@ -223,6 +412,11 @@ int repl(State* state, FILE *input) {
int startup(State *state, int argc, char **argv) { int startup(State *state, int argc, char **argv) {
state->output = stdout; 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_home;
char *config = calloc(500, sizeof(char)); char *config = calloc(500, sizeof(char));
if ((config_home = getenv("XDG_CONFIG_HOME"))) { if ((config_home = getenv("XDG_CONFIG_HOME"))) {
@ -240,13 +434,14 @@ int startup(State *state, int argc, char **argv) {
int err; int err;
FILE* rc = fopen(config, "r"); FILE* rc = fopen(config, "r");
if (rc) { if (rc) {
state->repl = false; state->interactive = false;
state->input = rc; state->input = rc;
if ((err = repl(state, rc))) { if ((err = repl(state, rc))) {
perror("Config file error"); perror("Config file error");
return err; return err;
} }
} }
fclose(rc);
if (argc == 2) { if (argc == 2) {
FILE *script_text = fopen(argv[1], "r"); 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) { int main(int argc, char** argv) {
State *state = calloc(1, sizeof(State)); State *state = calloc(1, sizeof(State));
state->aliases = calloc(INITIAL_NUM_ALIASES, sizeof(struct Alias)); state->aliases = calloc(INITIAL_NUM_ALIASES, sizeof(struct Alias));
state->num_aliases = 0; state->num_aliases = 0;
@ -273,10 +467,10 @@ int main(int argc, char** argv) {
} }
if (state->code) { if (state->code) {
state->repl = false; state->interactive = false;
repl(state, state->code); repl(state, state->code);
} else { } else {
state->repl = true; state->interactive = true;
print_chicken(state); print_chicken(state);
repl(state, stdin); repl(state, stdin);
} }

24
main.h

@ -13,6 +13,11 @@
#define INITIAL_LINE_BUFFER 80 #define INITIAL_LINE_BUFFER 80
#define INITIAL_WORD_SIZE 80 #define INITIAL_WORD_SIZE 80
#define INITIAL_NUM_ALIASES 50 #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 #define NUM_BUILTINS 3
@ -21,13 +26,30 @@ struct Alias {
char *substitution; 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 State {
struct Alias* aliases; struct Alias* aliases;
struct GrowingArray variables;
int num_aliases; int num_aliases;
FILE* code; FILE* code;
FILE *input; FILE *input;
FILE *output; FILE *output;
bool repl; bool interactive;
char *ps1;
}; };
typedef struct State State; typedef struct State State;

14
util.c

@ -1,5 +1,15 @@
#include "util.h" #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 readline(FILE* in, char **out) {
int size_of_buffer = INITIAL_LINE_BUFFER; int size_of_buffer = INITIAL_LINE_BUFFER;
char *buffer = calloc(size_of_buffer, sizeof(char)); 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++) { for (int i = 0; i < arr_len; i++) {
if (length == stringsize - 2) { 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]); 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; return ER_FAILURE;
} }
/* Remove all instances of char del from the given string (in place). */
int strip_char(char *string, char del) { int strip_char(char *string, char del) {
int len = strlen(string); int len = strlen(string);
bool move = false; bool move = false;

2
util.h

@ -4,6 +4,8 @@
#ifndef UTILH #ifndef UTILH
#define UTILH #define UTILH
void *dualloc(void *thing, size_t size);
int readline(FILE* in, char **out); int readline(FILE* in, char **out);
int split_string(char **sep_string[], int *num, char *string, char delim); int split_string(char **sep_string[], int *num, char *string, char delim);

Loading…
Cancel
Save