|
|
|
#include "error.h"
|
|
|
|
#include "run.h"
|
|
|
|
#include "main.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include <err.h>
|
|
|
|
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <readline/readline.h>
|
|
|
|
#include <readline/history.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);
|
|
|
|
int run_command(State *state, int argc, char *argv[]);
|
|
|
|
int get_array_element(ArrayElement **ret, GrowingArray* array, char* key);
|
|
|
|
int del_array_element(GrowingArray* array, char* key);
|
|
|
|
int expand_command(State *state, int *argc, char** ret_argv[]);
|
|
|
|
|
|
|
|
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)) {
|
|
|
|
*alias = state->aliases[i];
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ER_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 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));
|
|
|
|
alias.substitution = calloc(strlen(substitution) + 1, sizeof(char));
|
|
|
|
|
|
|
|
strcpy(alias.name, name);
|
|
|
|
strcpy(alias.substitution, substitution);
|
|
|
|
Alias existing;
|
|
|
|
|
|
|
|
if (get_alias(&existing, state, name)) {
|
|
|
|
// add it if it doesnt exist
|
|
|
|
|
|
|
|
state->aliases[state->num_aliases] = alias;
|
|
|
|
state->num_aliases++;
|
|
|
|
} else {
|
|
|
|
del_alias(state, name);
|
|
|
|
free(alias.name);
|
|
|
|
free(alias.substitution);
|
|
|
|
add_alias(state, name, substitution);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int del_alias(State *state, char *name) {
|
|
|
|
// read the list until the alias is found, then
|
|
|
|
// shuffle all the alias definitions down by one
|
|
|
|
bool move = false;
|
|
|
|
for (int i = 0; i < state->num_aliases; i++) {
|
|
|
|
if (move) {
|
|
|
|
if (i < state->num_aliases -1) {
|
|
|
|
state->aliases[i] = state->aliases[i + 1];
|
|
|
|
} else {
|
|
|
|
memset(&state->aliases[i], 0, sizeof(Alias));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!strcmp(name, state->aliases[i].name)) {
|
|
|
|
move = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (move) {
|
|
|
|
state->num_aliases--;
|
|
|
|
return ER_SUCCESS;
|
|
|
|
} else {
|
|
|
|
return ER_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int list_aliases(State *state) {
|
|
|
|
for (int i = 0; i < state->num_aliases; i++) {
|
|
|
|
Alias alias = state->aliases[i];
|
|
|
|
fprintf(state->output, "alias %s=%s\n", alias.name, alias.substitution);
|
|
|
|
}
|
|
|
|
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 run_pipes(State *state, int num_args, char *args []) {
|
|
|
|
char *joined = 0;
|
|
|
|
int err = join_string(&joined, num_args, args, " ");
|
|
|
|
if (err) {
|
|
|
|
errx(1, "no");
|
|
|
|
}
|
|
|
|
char * separated_by_pipe;
|
|
|
|
|
|
|
|
int pipe_count = 0;
|
|
|
|
for (int i = 0; i < strlen(joined); i++) {
|
|
|
|
if (joined[i] == '|') {
|
|
|
|
pipe_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int num_commands = pipe_count + 1;
|
|
|
|
|
|
|
|
char **sep_commands = calloc(pipe_count + 1, sizeof(char *));
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
char *piece = strtok(joined, "|");
|
|
|
|
do {
|
|
|
|
sep_commands[i] = calloc(strlen(piece) + 1, sizeof(char));
|
|
|
|
strcpy(sep_commands[i], piece);
|
|
|
|
i++;
|
|
|
|
} while ((piece = (char *)strtok(NULL, "|")) != 0);
|
|
|
|
|
|
|
|
if (num_commands == 1) {
|
|
|
|
for (int i = 0; i < num_commands; i++) {
|
|
|
|
free(sep_commands[i]);
|
|
|
|
}
|
|
|
|
free(sep_commands);
|
|
|
|
free(joined);
|
|
|
|
// free everything
|
|
|
|
return ER_NOT_EXISTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int *pipes = calloc(pipe_count * 2, sizeof(int));
|
|
|
|
|
|
|
|
for (int i = 0; i < pipe_count; i++) {
|
|
|
|
pipe(pipes + (2 * i));
|
|
|
|
}
|
|
|
|
|
|
|
|
pid_t child;
|
|
|
|
|
|
|
|
int in;
|
|
|
|
int out;
|
|
|
|
|
|
|
|
for (int i = 0; i < num_commands; i++) {
|
|
|
|
char **command;
|
|
|
|
int words;
|
|
|
|
|
|
|
|
int err = split_string(&command, &words, sep_commands[i], ' ');
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
in = 0;
|
|
|
|
out = pipes[2*i + 1];
|
|
|
|
} else if (i == num_commands - 1) {
|
|
|
|
in = pipes[2*(i-1)];
|
|
|
|
out = 1;
|
|
|
|
} else {
|
|
|
|
in = pipes[2*(i-1)];
|
|
|
|
out = pipes[2*i + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
int command_len = 0;
|
|
|
|
for (int i = 0; command[i] != 0; i++) {
|
|
|
|
command_len++;
|
|
|
|
}
|
|
|
|
//free(command[i]); // free the null pointer on the end
|
|
|
|
expand_command(state, &command_len, &command);
|
|
|
|
for (int i = 0; i < command_len; i++) {
|
|
|
|
printf("%s ", command[i]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
command = reallocarray(command, command_len+1, sizeof(char*));
|
|
|
|
command[command_len] = 0;
|
|
|
|
|
|
|
|
execute(in, out, command, &child);
|
|
|
|
|
|
|
|
for (int i = 0; i < command_len; i++) {
|
|
|
|
free(command[i]);
|
|
|
|
}
|
|
|
|
free(command);
|
|
|
|
}
|
|
|
|
|
|
|
|
int status;
|
|
|
|
while (!wait(&status));
|
|
|
|
|
|
|
|
free(pipes);
|
|
|
|
for (int i = 0; i < num_commands; i++) {
|
|
|
|
free(sep_commands[i]);
|
|
|
|
}
|
|
|
|
free(sep_commands);
|
|
|
|
free(joined);
|
|
|
|
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int check_builtins(State *state, int num_args, char *args[]) {
|
|
|
|
char *builtins[NUM_BUILTINS] = {
|
|
|
|
"cd",
|
|
|
|
"alias",
|
|
|
|
"unalias"
|
|
|
|
};
|
|
|
|
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, '=');
|
|
|
|
printf("%s\n", 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
|
|
|
|
if (args[1] == 0) {
|
|
|
|
list_aliases(state);
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
// add new alias
|
|
|
|
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);
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (num_args >= 2) {
|
|
|
|
char *substitution;
|
|
|
|
char **new_split;
|
|
|
|
int err = join_string(&substitution, num_args - 1,
|
|
|
|
args + 1, " ");
|
|
|
|
if (err) {
|
|
|
|
free(substitution);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
int eqcount = 0;
|
|
|
|
int num_parts;
|
|
|
|
err = split_string(&new_split, &num_parts, substitution, '=');
|
|
|
|
|
|
|
|
// exit if alias contains an =
|
|
|
|
if (num_parts != 2 || err) {
|
|
|
|
free(substitution);
|
|
|
|
for (int i =0; i < num_parts; i++) {
|
|
|
|
free(new_split[i]);
|
|
|
|
}
|
|
|
|
free(new_split);
|
|
|
|
return ER_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = add_alias(state, new_split[0], new_split[1]);
|
|
|
|
|
|
|
|
free(substitution);
|
|
|
|
for (int i =0; i < num_parts; i++) {
|
|
|
|
free(new_split[i]);
|
|
|
|
}
|
|
|
|
free(new_split);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(args[0], "unalias")) {
|
|
|
|
Alias alias;
|
|
|
|
if (num_args == 2) {
|
|
|
|
if (!del_alias(state, args[1])) {
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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_aliase(State *state, char **substitution, char *name) {
|
|
|
|
Alias alias;
|
|
|
|
for (int i = 0; i < state->num_aliases; i++) {
|
|
|
|
if (!get_alias(&alias, state, name)) {
|
|
|
|
*substitution = alias.substitution;
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ER_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int expand_command(State *state, int* argc, char** ret_argv[]) {
|
|
|
|
if (*argc == 0) {
|
|
|
|
return ER_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
char **argv = *ret_argv;
|
|
|
|
|
|
|
|
char *substitution;
|
|
|
|
for (int i = 0; i < *argc; i++) {
|
|
|
|
if (!check_aliase(state, &substitution, argv[i])) {
|
|
|
|
|
|
|
|
strip_char(argv[i], ' ');
|
|
|
|
|
|
|
|
// copy substitution into argv array
|
|
|
|
*ret_argv[i] = reallocarray(*ret_argv[i], strlen(substitution) + 1, sizeof(char));
|
|
|
|
strcpy(*ret_argv[0], substitution);
|
|
|
|
|
|
|
|
// expand substituted piece into the erray splitting over spaces
|
|
|
|
char *joined;
|
|
|
|
char **new_argv;
|
|
|
|
join_string(&joined, *argc, *ret_argv, " ");
|
|
|
|
split_string(&new_argv, argc, joined, ' ');
|
|
|
|
|
|
|
|
for (int j = 0 ; j < *argc;j ++) {
|
|
|
|
free(*ret_argv[j]);
|
|
|
|
}
|
|
|
|
free(*ret_argv);
|
|
|
|
|
|
|
|
*ret_argv = new_argv;
|
|
|
|
/***************************************/
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
int run_command(State *state, int argc, char *argv[]) {
|
|
|
|
pid_t child;
|
|
|
|
if (check_builtins(state, argc, argv) == ER_NOT_EXISTS) {
|
|
|
|
if (!execute(0,1, argv, &child))
|
|
|
|
waitpid(child, NULL, 0);
|
|
|
|
}
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read eval print loop until SIGTERM or end of non-interact file*/
|
|
|
|
int repl(State* state, FILE *input) {
|
|
|
|
while (true) {
|
|
|
|
char *line;
|
|
|
|
|
|
|
|
if (state->interactive) {
|
|
|
|
|
|
|
|
char ** ps1_sep;
|
|
|
|
int num;
|
|
|
|
split_string(&ps1_sep, &num, state->ps1, ' ');
|
|
|
|
run_command(state, num, ps1_sep);
|
|
|
|
for (int i = 0; i < num; i ++) {
|
|
|
|
free(ps1_sep[i]);
|
|
|
|
}
|
|
|
|
free(ps1_sep);
|
|
|
|
|
|
|
|
line = readline("$ ");
|
|
|
|
if (!line) {
|
|
|
|
printf("EOF\n");
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_history(line);
|
|
|
|
} else {
|
|
|
|
if (get_line(input, &line)) {
|
|
|
|
if (line)
|
|
|
|
free(line);
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char **sep_string;
|
|
|
|
int num_words;
|
|
|
|
|
|
|
|
split_string(&sep_string, &num_words, line, ' ');
|
|
|
|
free(line);
|
|
|
|
|
|
|
|
if (num_words == 0 // line is empty
|
|
|
|
|| sep_string[0][0] == '#') { // line is comment
|
|
|
|
for (int i = 0; i <= num_words; i ++)
|
|
|
|
free(sep_string[i]);
|
|
|
|
free(sep_string);
|
|
|
|
continue; // skip execution
|
|
|
|
}
|
|
|
|
|
|
|
|
int err = run_pipes(state, num_words, sep_string);
|
|
|
|
|
|
|
|
if (err == ER_NOT_EXISTS) {
|
|
|
|
expand_command(state, &num_words, &sep_string);
|
|
|
|
run_command(state, num_words, sep_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < num_words; i ++) {
|
|
|
|
free(sep_string[i]);
|
|
|
|
}
|
|
|
|
free(sep_string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int startup(State *state, int argc, char **argv) {
|
|
|
|
state->output = stdout;
|
|
|
|
|
|
|
|
state->ps1 = calloc(3, sizeof(char));
|
|
|
|
strcpy(state->ps1, "pwd");
|
|
|
|
|
|
|
|
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"))) {
|
|
|
|
strcpy(config, config_home);
|
|
|
|
int len = strlen(config_home);
|
|
|
|
strcpy(config + len, "/chicken/chickenrc");
|
|
|
|
} else {
|
|
|
|
config_home = getenv("HOME");
|
|
|
|
strcpy(config, config_home);
|
|
|
|
int len = strlen(config_home);
|
|
|
|
strcpy(config + len, "/.chickenrc");
|
|
|
|
}
|
|
|
|
|
|
|
|
int err;
|
|
|
|
FILE* rc = fopen(config, "r");
|
|
|
|
free(config);
|
|
|
|
if (rc) {
|
|
|
|
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");
|
|
|
|
if (script_text) {
|
|
|
|
state->code = script_text;
|
|
|
|
} else {
|
|
|
|
perror("Failed to load script");
|
|
|
|
return ER_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
int err = startup(state, argc, argv);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->code) {
|
|
|
|
state->interactive = false;
|
|
|
|
repl(state, state->code);
|
|
|
|
} else {
|
|
|
|
state->interactive = true;
|
|
|
|
print_chicken(state);
|
|
|
|
repl(state, stdin);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ER_SUCCESS;
|
|
|
|
}
|