|
|
|
@ -3,6 +3,21 @@
@@ -3,6 +3,21 @@
|
|
|
|
|
#include "main.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) { |
|
|
|
|
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) {
@@ -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) {
@@ -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) {
@@ -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[]) {
@@ -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[]) {
@@ -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[]) {
@@ -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) {
@@ -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[]) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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); |
|
|
|
|
} |
|
|
|
|