From b9d4d1552cc5745b262a33298ccc2e945c0538f8 Mon Sep 17 00:00:00 2001 From: Dario48 Date: Sat, 6 Dec 2025 12:10:51 +0100 Subject: [PATCH] working setup --- .clangd | 2 + .gitignore | 1 + .gitmodules | 3 + Makefile | 19 +++ README.md | 1 + src/linked-list | 1 + src/main.c | 318 ++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 345 insertions(+) create mode 100644 .clangd create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Makefile create mode 100644 README.md create mode 160000 src/linked-list create mode 100644 src/main.c diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..26a762a --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Add: ["-xc"] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e660fd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5884ce3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/linked-list"] + path = src/linked-list + url = ssh://forgejo@git.dario48.site/Dario48/linked-list.git diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..920eb61 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +CC=/bin/clang +BINDIR=bin + +main=$(BINDIR)/main + +all: setup $(main) libs + +setup: + mkdir -p $(BINDIR) + git submodule update + +$(main): src/main.c src/linked-list/linked_list.c + $(CC) $(CXXFLAGS) $(CFLAGS) src/main.c -o $(main) + +libs: + +.PHONY: clean all setup +clean: + rm -fr bin/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..7cd5704 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Posix C SHell, a posix shell impementation in C diff --git a/src/linked-list b/src/linked-list new file mode 160000 index 0000000..7343039 --- /dev/null +++ b/src/linked-list @@ -0,0 +1 @@ +Subproject commit 7343039dc975ebbd3c6660527da0f3780ff432bc diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..780b89a --- /dev/null +++ b/src/main.c @@ -0,0 +1,318 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linked-list/linked_list.c" +#if DEBUG +#define LOG(...) printf(__VA_ARGS__) +#define LOG_WRAP(x, ...) x(__VA_ARGS__) +#else +#define LOG(...) +#define LOG_WRAP(x, ...) +#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; \ + } +// 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 on +struct variable { + char* name; + char* value; +}; +// clang-format off +#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__) +#endif +// clang-format on +variable_list variables = {.head = NULL}; + +const char* getorsetenv(const char* name, const char* val) { + char* get = getenv(name); + if (get) return get; + setenv(name, val, 1); + return val; +} + +int _find_variable(variable_list_node* node, void* args) { + struct variable* arg = (struct variable*)args; + 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; + 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; + if (!name) return NULL; + return getenv(name); +} + +_Bool is_subshell = 0; + +#define throw(ret, ...) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + return ret; \ + } + +#define CHECK(var, val) var& val + +#define ESCAPE 0x1 +#define SET_ESCAPE situation ^= ESCAPE +#define IS_ESCAPED CHECK(situation, ESCAPE) + +#define QUOTED 0x2 +#define SET_QUOTED situation ^= QUOTED +#define IS_QUOTED CHECK(situation, QUOTED) + +#define DOUBLE_QUOTED 0x4 +#define SET_DOUBLE_QUOTED situation ^= DOUBLE_QUOTED +#define IS_DOUBLE_QUOTED CHECK(situation, DOUBLE_QUOTED) + +#define VAR 0x8 +#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; \ + } +char* resolve(const char* str) { + char situation = 0; + + string buf = {.head = NULL}; + + string var_buffer = {.head = NULL}; + for (const char* current = str; *current; current++) { + LOG("situation_pre: %i, current: %p = %c", situation, current, + *current); + switch (*current) { + case '\\': + if (IS_QUOTED) { + append_string(&buf, '\\'); + break; + } + if (IS_VAR) + SET_VAR; + 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" + ); + SET_QUOTED; + break; + + case '"': + if (IS_VAR) SET_VAR; + if (IS_ESCAPED || IS_QUOTED) append_string(&buf, '"'); + SET_DOUBLE_QUOTED; + break; + + case '$': + if (IS_ESCAPED || IS_QUOTED) + append_string(&buf, '$'); + else if (IS_VAR) { + if (*(current - 1) == '$') { + for (pid_t id = (!is_subshell) ? getpid() : getppid(); + id > 0; id = id / 10) + append_string(&buf, (id % 10) + 48); + } else { + RESOLVE_VAR; + SET_VAR; + } + } else { + SET_VAR; + } + 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); + else + 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; + append_string(&buf, 0); + LOG("string: { "); + LOG_WRAP(print_string, &buf, "'%c', "); + LOG(" }\n"); + char* parsed = string_to_array(&buf); + LOG("parsed_internal: \"%s\"\n", parsed); + return parsed; +} + +int prompt() { + return fprintf(stderr, "%s", resolve(getorsetenv("PS1", "\\$ "))); +} + +char* input() { + char* line = NULL; + size_t n = 0; + if (getline(&line, &n, stdin) < 0 && ferror(stdin)) { + free(line); + return NULL; + }; + return line; +} + +int exec(char* line) { + LOG("line: %s\n", line); + _Bool todo = 1; + string_array args = {.head = NULL}; + string arg = {.head = NULL}; + char* orig = line; + for (; *line != '\n'; line++) { + LOG("line: %c, \n", *line); + if (*line == ' ') { + if (todo) { + orig[line - orig] = 0; + todo = 0; + } else { + append_string(&arg, 0); + append_string_array(&args, string_to_array(&arg)); + } + } else if (!todo) { + append_string(&arg, *line); + } + } + LOG("line: %c, \n", *line); + if (todo) { + orig[line - orig] = 0; + todo = 0; + } else { + append_string(&arg, 0); + append_string_array(&args, string_to_array(&arg)); + } + push_string_array(&args, orig); + append_string_array(&args, NULL); + LOG("args: { "); + LOG_WRAP(print_string_array, &args, "%s, "); + LOG(" }"); + char** strargs = string_array_to_array(&args); + for (int i = 0; strargs[i]; i++) { + LOG("strargs[%i] %s", 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; + } +}