From 6ec1cc78f72d438403e4ec3ed82898a707afc5e5 Mon Sep 17 00:00:00 2001 From: Dario48 Date: Tue, 6 Jan 2026 18:04:24 +0100 Subject: [PATCH] biiiig update folks --- .clangd | 2 +- Makefile | 2 +- src/linked-list | 2 +- src/main.c | 811 ++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 682 insertions(+), 135 deletions(-) diff --git a/.clangd b/.clangd index 26a762a..329e434 100644 --- a/.clangd +++ b/.clangd @@ -1,2 +1,2 @@ CompileFlags: - Add: ["-xc"] + Add: ["-xc", "-std=gnu23"] diff --git a/Makefile b/Makefile index 83be941..5865276 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC=$(shell which clang) -CFLAGS:=$(CFLAGS) +CFLAGS:=$(CFLAGS) --std=gnu23 BINDIR=bin main=$(BINDIR)/main diff --git a/src/linked-list b/src/linked-list index 7343039..83210aa 160000 --- a/src/linked-list +++ b/src/linked-list @@ -1 +1 @@ -Subproject commit 7343039dc975ebbd3c6660527da0f3780ff432bc +Subproject commit 83210aa292843c67e768f03ba3390efe388505bd diff --git a/src/main.c b/src/main.c index 780b89a..dea5705 100644 --- a/src/main.c +++ b/src/main.c @@ -1,76 +1,221 @@ -#include -#include +// vim:fileencoding=utf-8:foldmethod=marker #include +#include #include #include #include #include -#include +#include #include #include #include "linked-list/linked_list.c" + +// Options {{{ +// 90% non implementate, qui per usi futuri +struct options { + _Bool a; + _Bool C; + _Bool e; + _Bool f; + _Bool h; + _Bool n; + _Bool u; + _Bool v; + _Bool x; +}; + +struct options optStatus = {0}; +// }}} + +// Logging {{{ + +// semplice funzione di logging, niente di speciale #if DEBUG -#define LOG(...) printf(__VA_ARGS__) +#define LOG(...) \ + do { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } while (0) +// funzione che esegue lo snippet di codice solo qualora il logging sia +// abilitato #define LOG_WRAP(x, ...) x(__VA_ARGS__) +// opposto di LOG_WRAP +#define LOG_WRAP_REVERSE(x, ...) #else #define LOG(...) #define LOG_WRAP(x, ...) +#define LOG_WRAP_REVERSE(x, ...) x(__VA_ARGS__) +#endif +// }}} + +// List extensions {{{ + +// estensione alla lista che va a creare una funzione toarray e lo struct +// associato +#define CREATE_TOARRAY(name, type, format) \ + struct name##_array_args { \ + _Bool backwards; \ + int len; \ + type* array; \ + }; \ + int _##name##_to_array /*a commment is needed to make the syntax highliter \ + work after this*/ \ + (name##_node * node, void* vargs) { \ + struct name##_array_args* args = (struct name##_array_args*)vargs; \ + LOG("len: %i, backwards: %b, val: " #format \ + ", node: %p, node_next: %p\n", \ + args->len, args->backwards, node->val, node, node->next); \ + \ + if (!args->backwards) { \ + args->len++; \ + if (!node->next) { \ + args->backwards = 1; \ + args->array = malloc(args->len * sizeof(type)); \ + if (!args->array) return -1; \ + } \ + } else { \ + args->len--; \ + args->array[args->len - 1] = node->val; \ + free(node); \ + } \ + return 0; \ + } \ + \ + type* name##_to_array(name* str) { \ + struct name##_array_args args = {.backwards = 0, .len = 1}; \ + if (foreach_twopass_##name(str, _##name##_to_array, &args)) \ + return NULL; \ + str->head = NULL; \ + return args.array; \ + } +// }}} + +// Strings {{{ +// clang-format off +// clang-format va a dare problemi con il % +CREATE_LIST(string_array, char*); +CREATE_TOARRAY(string_array, char*, %s); +CREATE_LIST(string, char); +CREATE_TOARRAY(string, char, %c); +// clang-format on + +//}}} + +// Alias type {{{ + +// clang-format off +// uno struct per gli alias, contiene il nome e +// o una funzione che va a eseguire (per esempio exit, che va a eseguire __exit()) +// o un comando e argomenti da aggiungere (per esempio `alias ll="ls -l" +// clang-format on + +struct alias { + char* name; + char* command; + char** args; + int (*fn)(char**); +}; + +// tipo non stampabile facilmente, rimossa temporanemante la funzione di log +#undef LOG +#define LOG(...) +CREATE_LIST(alias_list, struct alias) +CREATE_TOARRAY(alias_list, struct alias, '\0') +#if DEBUG +#undef LOG +#define LOG(...) \ + do { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } while (0) #endif -#define CREATE_TOARRAY(name, type, format) \ - struct name##_array_args { \ - _Bool backwards; \ - int len; \ - type* array; \ - }; \ - int _##name##_to_array(name##_node* node, void* vargs) { \ - struct name##_array_args* args = (struct name##_array_args*)vargs; \ - LOG("len: %i, backwards: %b, val: " #format \ - ", node: %p, node_next: %p\n", \ - args->len, args->backwards, node->val, node, node->next); \ - \ - if (!args->backwards) { \ - args->len++; \ - if (!node->next) { \ - args->backwards = 1; \ - args->array = malloc(args->len * sizeof(type)); \ - if (!args->array) return -1; \ - } \ - } else { \ - args->len--; \ - args->array[args->len - 1] = node->val; \ - free(node); \ - } \ - return 0; \ - } \ - \ - type* name##_to_array(name* str) { \ - struct name##_array_args args = {.backwards = 0, .len = 1}; \ - if (foreach_twopass_##name(str, _##name##_to_array, &args)) \ - return NULL; \ - return args.array; \ - } +alias_list aliases = {.head = NULL}; + // clang-format off -CREATE_LIST(string_array, char*) -CREATE_TOARRAY(string_array, char*, %s) -CREATE_LIST(string, char) -CREATE_TOARRAY(string, char, %c) +int _findalias(alias_list_node* node, void* vargs) { + alias_list_node** args = (alias_list_node**)vargs; // va a fare il casting del pointer + char *n, *a; // va a creare delle variabili temporanee + for (n = node->val.name, a = (*args)->val.name; *n && *a; n++, a++) { + if (*n != *a) return 0; // e a confrontarle + } + + if (*n ^ *a) return 0; // in case siamo arrivati alla fine dell'array invece di avere trovato il nome giusto + + *args = node; // impostiamo gli argomenti al nodo con nome giusto + return 1; // ritorniamo 1 così da interrompere l'esecuzione del ciclo foreach +} + +// funzione che va a trovare un alias +alias_list_node* findalias(char* name) { + struct alias val = {.name = name}; // va a creare un alias con nome come passato + alias_list_node node = {.val = val}; // va a creare un node + alias_list_node* ptr = &node; // e un pointer per contenerlo + if (foreach_alias_list(&aliases, *_findalias, &ptr)) return ptr; // se trovato viene ritornato + return NULL; // senno ritorna null +} // clang-format on +int last_exit = 0; +//}}} + +// Builtin aliases {{{ + +// funzione exit come definita da POSIX +int __exit(char** args) { + if (args[1]) exit(atoi(args[1])); + exit(last_exit); +} +struct alias exit_alias = { + .name = "exit", + .fn = __exit, +}; + +// ancora non implementata, out of scope +int set(char** args) { + if (args[1]) { + } else { + return printf( + "a: %b,\n" + "C: %b,\n" + "e: %b,\n" + "f: %b,\n" + "h: %b,\n" + "n: %b,\n" + "u: %b,\n" + "v: %b,\n" + "x: %b,\n", + optStatus.a, optStatus.C, optStatus.e, optStatus.f, optStatus.h, + optStatus.n, optStatus.u, optStatus.v, optStatus.x + ); + } +} +struct alias set_alias = { + .name = "set", + .fn = set, +}; + +//}}} + +// Variable type {{{ struct variable { char* name; char* value; }; -// clang-format off + +// tipo non stampabile facilmente, rimossa temporanemante la funzione di log #undef LOG #define LOG(...) CREATE_LIST(variable_list, struct variable) CREATE_TOARRAY(variable_list, struct variable, '\0') #if DEBUG #undef LOG -#define LOG(...) printf(__VA_ARGS__) +#define LOG(...) \ + do { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } while (0) #endif -// clang-format on variable_list variables = {.head = NULL}; const char* getorsetenv(const char* name, const char* val) { @@ -80,130 +225,263 @@ const char* getorsetenv(const char* name, const char* val) { return val; } +// implementazione equivalente alla ricerca di alias int _find_variable(variable_list_node* node, void* args) { - struct variable* arg = (struct variable*)args; + struct variable* arg = *((struct variable**)args); + LOG("checking %s against %s\n", node->val.name, arg->name); if (strlen(node->val.name) == strlen(arg->name)) { for (int i = 0; node->val.name[i] && arg->name[i]; i++) { if (node->val.name[i] != arg->name[i]) return 0; } - arg->value = node->val.value; + *arg = node->val; return 1; } return 0; } char* find_variable(char* name) { - struct variable ret = {.name = name}; - if (foreach_variable_list(&variables, _find_variable, &ret)) - return ret.value; + LOG("searching for %s\n", name); if (!name) return NULL; + struct variable tmp = {.name = name}; + struct variable* ret = &tmp; + if (foreach_variable_list(&variables, _find_variable, &ret)) { + LOG("found %s", ret->value); + return ret->value; + } + LOG("falling back to getenv\n"); return getenv(name); } +// come il find_variable ma senza fallback +char* find_local_variable(char* name) { + LOG("searching for local %s\n", name); + if (!name) return NULL; + struct variable tmp = {.name = name}; + struct variable* ret = &tmp; + if (foreach_variable_list(&variables, _find_variable, &ret)) + return ret->value; + LOG("not found\n"); + return NULL; +} + +// trova e rimpiazza una variabile +int find_and_replace_local_variable(char* name, char* replacement) { + LOG("searching for local %s\n", name); + if (!name) return 1; + struct variable tmp = {.name = name}; + struct variable* ret = &tmp; + if (foreach_variable_list(&variables, _find_variable, &ret)) { + free(ret->value); + ret->value = replacement; + return 0; + } + LOG("not found\n"); + return 1; +} +//}}} + _Bool is_subshell = 0; +// Text processing {{{ #define throw(ret, ...) \ - { \ + do { \ fprintf(stderr, __VA_ARGS__); \ return ret; \ - } + } while (0) #define CHECK(var, val) var& val -#define ESCAPE 0x1 +#define ESCAPE 1 #define SET_ESCAPE situation ^= ESCAPE #define IS_ESCAPED CHECK(situation, ESCAPE) -#define QUOTED 0x2 +#define QUOTED 2 #define SET_QUOTED situation ^= QUOTED #define IS_QUOTED CHECK(situation, QUOTED) -#define DOUBLE_QUOTED 0x4 +#define DOUBLE_QUOTED 4 #define SET_DOUBLE_QUOTED situation ^= DOUBLE_QUOTED #define IS_DOUBLE_QUOTED CHECK(situation, DOUBLE_QUOTED) -#define VAR 0x8 +#define VAR 8 #define SET_VAR situation ^= VAR #define IS_VAR CHECK(situation, VAR) -#define RESOLVE_VAR \ - { \ - char* varname = string_to_array(&var_buffer); \ - char* content = find_variable(varname); \ - if (content) { \ - for (; *content; content++) { \ - append_string(&buf, *content); \ - } \ - } \ - free(varname); \ - SET_VAR; \ - } + +#define RESOLVE_VAR() \ + do { \ + append_string(&var_buffer, 0); /* si aggiunge un terminator */ \ + char* varname = string_to_array(&var_buffer); \ + char* content = find_variable(varname); /* cerchiamo la variabile */ \ + if (content) { /* se la troviamo */ \ + for (; *content; content++) { \ + append_string( \ + &buf, *content \ + ); /* aggiungiamo il suo valore al buffer */ \ + } \ + } \ + free(varname); \ + SET_VAR; \ + } while (0) + +#define DUMP_UNINTERRUPTED() \ + do { \ + append_string(&uninterrupted, 0); /* aggiungiamo un terminatore */ \ + char* dump_tofree = string_to_array(&uninterrupted); \ + LOG("dump_tofree: %s", dump_tofree); \ + if (dump_tofree) { \ + if (dump) { /* se siamo dopo un '=' */ \ + LOG(", dump: %s\n", dump); \ + struct variable tmpvar = {.name = dump, .value = dump_tofree}; \ + append_variable_list( \ + &variables, tmpvar \ + ); /* aggiungiamo la variabile */ \ + dump = NULL; \ + } else { \ + LOG("\n"); \ + for (char* tmp = dump_tofree; *dump; \ + dump++) /* aggiungiamo al buffer normale */ \ + append_string(&buf, *tmp); \ + free(dump_tofree); \ + } \ + } \ + } while (0) + char* resolve(const char* str) { char situation = 0; string buf = {.head = NULL}; + char* dump = NULL; string var_buffer = {.head = NULL}; + string uninterrupted = {.head = NULL}; + + // switch case di ogni carattere speciale definito da posix supportato for (const char* current = str; *current; current++) { LOG("situation_pre: %i, current: %p = %c", situation, current, *current); switch (*current) { + case '#': + if (IS_VAR) + RESOLVE_VAR(); + else + DUMP_UNINTERRUPTED(); + if (IS_QUOTED) { + append_string(&buf, '#'); + break; + } + if (IS_DOUBLE_QUOTED) { + append_string(&buf, '#'); + break; + } + if (IS_ESCAPED) { + append_string(&buf, '#'); + break; + } + goto FIN; case '\\': + if (IS_VAR) + RESOLVE_VAR(); + else + DUMP_UNINTERRUPTED(); if (IS_QUOTED) { append_string(&buf, '\\'); break; } - if (IS_VAR) - SET_VAR; - else if (IS_ESCAPED) + if (IS_DOUBLE_QUOTED) { + switch (*(++current)) { + case '$': + case '`': + case '"': + case '\\': + append_string(&buf, *current); + default: + append_string(&buf, '\\'); + current--; + } + break; + } else if (IS_ESCAPED) append_string(&buf, '\\'); SET_ESCAPE; goto END; case '\'': - if (IS_VAR) SET_VAR; if (IS_QUOTED && IS_ESCAPED) throw( NULL, "attempt to escape a \"'\" while inside quotes, this " "goes against posix standard" ); + if (IS_VAR) + RESOLVE_VAR(); + else + DUMP_UNINTERRUPTED(); SET_QUOTED; break; case '"': - if (IS_VAR) SET_VAR; + if (IS_VAR) + RESOLVE_VAR(); + else + DUMP_UNINTERRUPTED(); if (IS_ESCAPED || IS_QUOTED) append_string(&buf, '"'); SET_DOUBLE_QUOTED; break; case '$': + DUMP_UNINTERRUPTED(); if (IS_ESCAPED || IS_QUOTED) append_string(&buf, '$'); else if (IS_VAR) { if (*(current - 1) == '$') { - for (pid_t id = (!is_subshell) ? getpid() : getppid(); + for (pid_t id = (!is_subshell) + ? getpid() + : getppid(); // non ancora in uso id > 0; id = id / 10) append_string(&buf, (id % 10) + 48); } else { - RESOLVE_VAR; + RESOLVE_VAR(); SET_VAR; } } else { SET_VAR; } break; + + case '=': + if (IS_QUOTED || IS_DOUBLE_QUOTED || IS_ESCAPED) { + if (IS_VAR) RESOLVE_VAR(); + append_string(&buf, *current); + } else { + dump = string_to_array(&uninterrupted); + } + break; case '\n': if (IS_ESCAPED) break; - case ' ': case ';': case ',': case '.': - if (IS_VAR) RESOLVE_VAR; - default: if (IS_VAR) - append_string(&var_buffer, *current); + RESOLVE_VAR(); else + DUMP_UNINTERRUPTED(); + append_string(&buf, *current); + break; + default: + if ((*current >= 'A' && *current <= 'Z') || + (*current >= 'a' && *current <= 'z') || + (*current >= '0' && *current <= '9')) + + if (IS_VAR) + append_string(&var_buffer, *current); + else + append_string(&uninterrupted, *current); + else { + if (IS_VAR) + SET_VAR; + else + DUMP_UNINTERRUPTED(); append_string(&buf, *current); + } } if (IS_ESCAPED) SET_ESCAPE; END: @@ -211,7 +489,9 @@ char* resolve(const char* str) { LOG_WRAP(print_string, &buf, "'%c', "); LOG(" }, situation: %i\n", situation); } - if (IS_VAR) RESOLVE_VAR; + if (IS_VAR) RESOLVE_VAR(); +FIN: + DUMP_UNINTERRUPTED(); append_string(&buf, 0); LOG("string: { "); LOG_WRAP(print_string, &buf, "'%c', "); @@ -220,42 +500,150 @@ char* resolve(const char* str) { LOG("parsed_internal: \"%s\"\n", parsed); return parsed; } +//}}} -int prompt() { - return fprintf(stderr, "%s", resolve(getorsetenv("PS1", "\\$ "))); -} +// Io {{{ +// print della prompt inpostand anche la variabile se non ancora impostata +int prompt() { return fprintf(stderr, "%s", getorsetenv("PS1", "$ ")); } +// semplice funzione di imput +FILE* inputFile; char* input() { char* line = NULL; size_t n = 0; - if (getline(&line, &n, stdin) < 0 && ferror(stdin)) { + if (getline(&line, &n, inputFile) <= 0) { free(line); return NULL; }; return line; } -int exec(char* line) { - LOG("line: %s\n", line); +// clear dell'imput quando  viene premuto in interactive mod +void clearInput(int sig) { + signal(sig, SIG_IGN); + LOG_WRAP(char c; do {} while, 0); + fseek(stdin, 0, SEEK_END); + fprintf(stderr, "\033[2K"); + fprintf(stderr, "\r"); + prompt(); + signal(sig, clearInput); +} + +//}}} + +// Execute {{{ + +// whitespace checker +_Bool isjustwhite(char* str) { + for (; *str; str++) + if (*str != ' ' && *str != '\n') return false; + return true; +} + +int _exec(char* line); +int __exec(char** argv, char* command, char* fromalias); +// exec() = __exec in un caso e _exec nell'altro +#define FIRST(X, ...) X +#define exec(...) \ + _Generic(FIRST(__VA_ARGS__), char**: __exec, default: _exec)(__VA_ARGS__) + +int __exec(char** argv, char* command, char* fromalias) { + if (fromalias) { + for (char *c = command, *f = fromalias; *c && *f; c++, f++) { + if (*c != *f) { + goto ALIAS; + } + } + goto SKIP; + } + // se dobbiamo trovare l'alias +ALIAS: + alias_list_node* node = findalias(command); + if (!node) goto SKIP; + + if (node->val.fn) { + return (*node->val.fn)(argv); // se troviamo un builtin lo eseguiamo + } + + // troviamo lunghezza degli argomenti + int argc; + for (argc = 0; (node->val.args)[argc++];); + char** new_argv = malloc(argc); + // li spostiamo tutti nella nuova argv + memcpy(new_argv, argv, argc); + + // rifacciamo lo stesso con gli argomenti passati nella cli + int old_argc; + for (old_argc = -1; argv[++old_argc];); + new_argv = realloc(new_argv, argc + old_argc); + memcpy(new_argv + argc, argv + 1, old_argc); + return exec(new_argv, node->val.command, command); + +SKIP: + LOG("\n"); + if (isjustwhite(command)) return 0; // in caso sia solo \n e ' ' + if (optStatus.x) { + // print dei commandi + printf("%s ", command); + for (char** tmp = argv; *tmp; tmp++) { + printf("%s ", *tmp); + }; + printf("\n"); + } + + // vfork del processo + pid_t proc = vfork(); + + // se non ѐ andato a buon fine ritorna errore + if (proc == -1) return -1; + + if (proc) { + // se siamo il parent + siginfo_t infop; + int ret = waitid( + P_PID, proc, &infop, WEXITED | WSTOPPED + ); /* "aspettiamo" il processo (solo per ottenere il return, in realtà + vfork aspetta di default) */ + if (ret) return -1; // se non ci riusciamo, errore + last_exit = infop.si_status; + if (infop.si_status) + fprintf( + stderr, "Process returned with error code %i\n", infop.si_status + ); + LOG("\n\n"); + return 0; + } else { + // se siamo il child process + int ret = execvp(command, argv); // execvp + if (ret == -1) + fprintf(stderr, "errno: %i\n", errno); // se non ha funzionato + _exit(ret); + } +} + +// separazione di argouments e command +void split(char* line, char*** strargs_ret, char** orig_ret) { _Bool todo = 1; string_array args = {.head = NULL}; string arg = {.head = NULL}; char* orig = line; - for (; *line != '\n'; line++) { - LOG("line: %c, \n", *line); + for (; *line != '\n' && *line; line++) { + LOG("main.split.for: line: %c, ", *line); if (*line == ' ') { if (todo) { orig[line - orig] = 0; todo = 0; } else { + LOG_WRAP(print_string, &arg, "main.split.for.arg: %c\n"); append_string(&arg, 0); append_string_array(&args, string_to_array(&arg)); } } else if (!todo) { + LOG("appending; \n"); append_string(&arg, *line); } } - LOG("line: %c, \n", *line); + LOG("main.split: line: %c, ", *line); if (todo) { orig[line - orig] = 0; todo = 0; @@ -267,52 +655,211 @@ int exec(char* line) { append_string_array(&args, NULL); LOG("args: { "); LOG_WRAP(print_string_array, &args, "%s, "); - LOG(" }"); + LOG(" }\n"); char** strargs = string_array_to_array(&args); for (int i = 0; strargs[i]; i++) { - LOG("strargs[%i] %s", i, strargs[i]); + LOG("strargs[%i] %s\n", i, strargs[i]); } - pid_t proc = vfork(); - if (proc == -1) return -1; - if (proc) { - siginfo_t infop; - int ret = waitid(P_PID, proc, &infop, WEXITED | WSTOPPED); - if (ret) return -1; - if (infop.si_status) - fprintf( - stderr, "Process returned with error code %i\n", infop.si_status - ); - return 0; - } else { - int ret = execvp(orig, strargs); - if (ret == -1) fprintf(stderr, "errno: %i\n", errno); - _exit(ret); - } -} -int main(int argc, char** argv) { - LOG("sizeof(string_node): %i, sizeof(string): %i, " - "sizeof(string_array_args): %i\n", - sizeof(string_node), sizeof(string), sizeof(struct string_array_args)); - LOG("sizeof(string_array_node): %i, sizeof(string_array): %i, " - "sizeof(string_array_array_args): %i\n", - sizeof(string_array_node), sizeof(string_array), - sizeof(struct string_array_array_args)); - LOG("sizeof(variable): %i, sizeof(variable_list): %i, " - "sizeof(variable_list_node): %i, sizeof(variable_list_array_args): " - "%i\n", - sizeof(struct variable), sizeof(variable_list), - sizeof(variable_list_node), sizeof(struct variable_list_array_args)); - LOG("test, resolve \"\\$\", \"%s\"\n", resolve("\\$ ")); - for (;;) { - prompt(); - char* line = input(); - LOG("input: %s", line); - if (!line) return errno; - char* parsed = resolve(line); - LOG("parsed: %s", parsed); - if (!parsed) return -1; - int ret = exec(parsed); - if (ret) return ret; - } + *strargs_ret = strargs; + *orig_ret = orig; +} +int _exec(char* line) { + LOG("line: %s\n", line); + char **strargs, *orig; + split(line, &strargs, &orig); + return exec(strargs, orig, NULL); +} +//}}} + +// Enums {{{ + +typedef enum { + File, + FakeFile, + Stdin, +} Mode; + +typedef enum { + Normal, + ScriptArgs, +} ParseMode; + +// }}} + +// Convarsions {{{ +char* itoa(int integer) { + if (!integer) return "0"; + string tmp; + for (; integer; integer /= 10) append_string(&tmp, integer % 10 + '0'); + return string_to_array(&tmp); +} +// }}} + +_Bool interactive = false; +int main(int argc, char** argv) { + LOG("set arg0 to %s\n", argv[0]); + struct variable arg0 = {.name = "0", .value = argv[0]}; + append_variable_list(&variables, arg0); + inputFile = stdin; + Mode mode = Stdin; + ParseMode parsemode = Normal; + + _Bool c = false; + _Bool s = false; + + // Initialize builtins {{{ + + append_alias_list(&aliases, exit_alias); + append_alias_list(&aliases, set_alias); + + // }}} + + // Handle argouments {{{ + if (argc - 1) { + int i; + for (i = 1; i < argc && parsemode == Normal; i++) { + LOG("i: %i, argv[i]: %s\n", i, argv[i]); + switch (*(argv[i])) { + case '-': + char c; + if ((c = argv[i][1])) { + switch (c) { + case 'c': + if (s) + throw( + 1, + "only specify either -s or -c, not both" + ); + c = true; + ++i; + LOG("i: %i, argv[i](command): %s\n", i, + argv[i]); + inputFile = + fmemopen(argv[i], strlen(argv[i]), "r"); + if (!inputFile) + throw( + errno, + "failed to execute commands provided " + "by -c" + ); + mode = FakeFile; + parsemode = ScriptArgs; + + break; + case 's': + if (c) + throw( + 1, + "only specify either -s or -c, not both" + ); + s = true; + break; + case 'i': + interactive = true; + break; + case 'a': + optStatus.a = true; + break; + case 'n': + optStatus.n = true; + break; + } + } else { + parsemode = ScriptArgs; + } + break; + default: + struct stat info = {0}; + if (stat(argv[i], &info)) return errno; + if ((info.st_mode & S_IXUSR /*owner has execution*/ && + info.st_uid == getuid()) || + (info.st_mode & S_IXGRP /*group has execution*/ && + info.st_gid == getgid()) || + (info.st_mode & S_IXOTH /*other has execution*/)) { + inputFile = fopen(argv[i], "r"); + if (!inputFile) + throw(errno, "failed to open file provided"); + } else + throw(1, "file specified is not executable"); + mode = File; + parsemode = ScriptArgs; + find_and_replace_local_variable("0", argv[i]); + } + } + if (i < argc && mode == Stdin) { + struct stat info = {0}; + if (stat(argv[i], &info)) return errno; + if ((info.st_mode & S_IXUSR /*owner has execution*/ && + info.st_uid == getuid()) || + (info.st_mode & S_IXGRP /*group has execution*/ && + info.st_gid == getgid()) || + (info.st_mode & S_IXOTH /*other has execution*/)) { + inputFile = fopen(argv[i], "r"); + if (!inputFile) throw(errno, "failed to open file provided"); + } + mode = File; + find_and_replace_local_variable("0", argv[i]); + i++; + } + for (int j = 1; i < argc; i++, j++) { + struct variable argn = {.name = itoa(j), .value = argv[i]}; + append_variable_list(&variables, argn); + } + } + + if (getgid() != getegid() || getuid() != geteuid()) + interactive = false; // come definito da posix + if (interactive) { + do { + char* filename = getenv("ENV"); + if (!filename) break; + FILE* backupfile = inputFile; + + char* line = input(); + LOG("input: %s\n", line); + if (!line) { + if (feof(inputFile)) + __exit(NULL); + else + return errno; + } + char* parsed = resolve(line); + LOG("parsed: %s\n", parsed); + if (!parsed) return -1; + int ret = exec(parsed); + if (ret) return ret; + inputFile = backupfile; + } while (0); + } + // }}} + if (interactive) { + signal(SIGINT, clearInput); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + }; + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + + // Main loop {{{ + for (;;) { + if (mode == Stdin) prompt(); + char* line = input(); + LOG("input: %s\n", line); + if (!line) { + if (feof(inputFile)) + __exit(NULL); + else + return errno; + } + char* parsed = resolve(line); + LOG("parsed: %s\n", parsed); + if (!parsed) return -1; + if (interactive || !optStatus.n) { + int ret = exec(parsed); + if (ret) return ret; + } + } + // }}} }