biiiig update folks

This commit is contained in:
Dario48 2026-01-06 18:04:24 +01:00
commit 6ec1cc78f7
4 changed files with 682 additions and 135 deletions

View file

@ -1,2 +1,2 @@
CompileFlags:
Add: ["-xc"]
Add: ["-xc", "-std=gnu23"]

View file

@ -1,5 +1,5 @@
CC=$(shell which clang)
CFLAGS:=$(CFLAGS)
CFLAGS:=$(CFLAGS) --std=gnu23
BINDIR=bin
main=$(BINDIR)/main

@ -1 +1 @@
Subproject commit 7343039dc975ebbd3c6660527da0f3780ff432bc
Subproject commit 83210aa292843c67e768f03ba3390efe388505bd

View file

@ -1,30 +1,67 @@
#include <bits/types/idtype_t.h>
#include <bits/types/siginfo_t.h>
// vim:fileencoding=utf-8:foldmethod=marker
#include <errno.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wait.h>
#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(name##_node* node, void* vargs) { \
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", \
@ -49,28 +86,136 @@
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
CREATE_LIST(string_array, char*)
CREATE_TOARRAY(string_array, char*, %s)
CREATE_LIST(string, char)
CREATE_TOARRAY(string, char, %c)
// 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
alias_list aliases = {.head = NULL};
// clang-format off
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,138 +225,273 @@ 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 \
{ \
#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); \
if (content) { \
char* content = find_variable(varname); /* cerchiamo la variabile */ \
if (content) { /* se la troviamo */ \
for (; *content; content++) { \
append_string(&buf, *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;
if (IS_VAR)
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:
LOG(", string: { ");
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);
}
}
*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("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();
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", line);
if (!line) return errno;
LOG("input: %s\n", line);
if (!line) {
if (feof(inputFile))
__exit(NULL);
else
return errno;
}
char* parsed = resolve(line);
LOG("parsed: %s", parsed);
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;
}
}
// }}}
}