From db4653a2d21acf394d255a26be0b6eb102b835d0 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 26 Jan 2026 11:03:09 -0700 Subject: [PATCH] allow chaining commands with '&&' --- src/lexer/lexer.c | 120 +++++++++++++++++++++++++++++--------------- src/system/system.h | 11 ++++ 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index 89f2513..2fcdce1 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -41,9 +41,7 @@ void msh_lexer_parse(msh_lexer *lexer, char *buf, SIZE_TYPE sz) { int i = 0, n = 0, j = 0; char cur_word_buf[1024]; - /*case '#': - do_clear = 1; - break; + /* case '|': if (i + 1 < sz) { if (buf[i + 1] == '|') { @@ -56,18 +54,6 @@ void msh_lexer_parse(msh_lexer *lexer, char *buf, SIZE_TYPE sz) { } do_clear = 1; break; - case '&': - if (i + 1 < sz) { - if (buf[i + 1] == '&') { - msh_lexer_push_item(lexer, MSH_LEXER_ITEM_TYPE_OP_AND, buf, 2); - last = i + 2; - } else { - msh_lexer_push_item(lexer, MSH_LEXER_ITEM_TYPE_OP_CONTROL, buf, 1); - last = i + 1; - } - } - do_clear = 1; - break; case ';': msh_lexer_push_item(lexer, MSH_LEXER_ITEM_TYPE_OP_SEMICOLON, buf, 1); do_clear = 1; @@ -94,11 +80,22 @@ void msh_lexer_parse(msh_lexer *lexer, char *buf, SIZE_TYPE sz) { quote_mode = !quote_mode; } break; + case '&': + if (i + 1 < sz) { + if (buf[i + 1] == '&') { + msh_lexer_push_item(lexer, MSH_LEXER_ITEM_TYPE_OP_AND, buf, 2); + i++; + } else { + msh_lexer_push_item(lexer, MSH_LEXER_ITEM_TYPE_OP_CONTROL, buf, 1); + } + } + break; case ' ': if (quote_mode == 1) { goto do_add; break; } + /* fallthrough */ case '\n': case '\0': cur_word_buf[n++] = '\0'; @@ -122,25 +119,13 @@ lexer_cancel: return; } -int msh_lexer_execute(msh_lexer *lexer) { - msh_lexer_item_list *list = lexer->item_list_head; - char *cmd = list->item->str; - SIZE_TYPE cmd_size = list->item->strlen; - - SIZE_TYPE args_size = 0; - char is_first_arg = 0, exec_success = 0, exec_status = 0; - unsigned short i = 0, n = 0, j = 0, counter = 0; +static int do_exec(msh_lexer *lexer, char *cmd, char **args, int *n, + int *exec_status) { char full_path[PATH_MAX]; - char *args[512]; + char is_first_arg = 0, exec_success = 0; + unsigned short i = 0, j = 0, counter = 0; - while (list != 0) { - if (!list->item) { - break; - } - args[n++] = list->item->str; - list = list->next; - } - args[n++] = 0; + args[*n] = 0; /* Do nothing on blank commands */ if (*cmd == '\0') { @@ -162,19 +147,20 @@ int msh_lexer_execute(msh_lexer *lexer) { } else { /* loop through all the path entries and check if the file exists in them. */ - i = 0, n = 0, j = 0; + i = 0, *n = 0, j = 0; while (1) { - full_path[n++] = lexer->path[j]; + full_path[*n] = lexer->path[j]; + *n += 1; if (lexer->path[j] == '\0') { - full_path[n - 1] = msh_path_seperator; + full_path[*n - 1] = msh_path_seperator; for (i = 0; cmd[i] != 0; i++) { - full_path[i + n] = cmd[i]; + full_path[i + *n] = cmd[i]; } - n += i; - full_path[n++] = '\0'; + *n += i; + full_path[*n++] = '\0'; if (msh_path_exists(full_path)) { - exec_status = msh_execute(full_path, args); + msh_execute(full_path, args); exec_success = 1; break; } @@ -183,7 +169,7 @@ int msh_lexer_execute(msh_lexer *lexer) { if (counter > 2) { break; } - n = 0; + *n = 0; } else { counter = 0; } @@ -193,10 +179,62 @@ int msh_lexer_execute(msh_lexer *lexer) { if (!exec_success) { msh_print_strings("msh: ", cmd, ": command not found\n\r", 0); } + /* flush out args */ + for (i = 0; i < 512; i++) { + if (args[i] == 0) { + break; + } + args[i] = 0; + } + + return 0; +} + +int msh_lexer_execute(msh_lexer *lexer) { + msh_lexer_item_list *list = lexer->item_list_head; + char *cmd = list->item->str; + SIZE_TYPE cmd_size; + int i = 0, n = 0, exec_status = 0; + SIZE_TYPE args_size = 0; + char *args[512]; + + while (list != 0) { + if (!list->item) { + break; + } + switch (list->item->type) { + case MSH_LEXER_ITEM_TYPE_UNKNOWN: + break; + case MSH_LEXER_ITEM_TYPE_WORD: + if (cmd == 0 && *list->item->str != '\0') { + cmd = list->item->str; + } else { + args[n++] = list->item->str; + } + break; + case MSH_LEXER_ITEM_TYPE_COMMENT: + break; + case MSH_LEXER_ITEM_TYPE_OP_OR: + break; + case MSH_LEXER_ITEM_TYPE_OP_AND: + do_exec(lexer, cmd, args, &n, &exec_status); + n = 0; + cmd = 0; + break; + case MSH_LEXER_ITEM_TYPE_OP_PIPE: + break; + case MSH_LEXER_ITEM_TYPE_OP_CONTROL: + break; + case MSH_LEXER_ITEM_TYPE_OP_SEMICOLON: + break; + } + list = list->next; + } + do_exec(lexer, cmd, args, &n, &exec_status); msh_lexer_flush(lexer); - return exec_status == 0 ? exec_status : exec_success; + return 0; }; void msh_lexer_flush(msh_lexer *lexer) { diff --git a/src/system/system.h b/src/system/system.h index 9961016..55f4b8d 100644 --- a/src/system/system.h +++ b/src/system/system.h @@ -95,12 +95,23 @@ const char *msh_working_directory(); */ void msh_set_working_directory(const char *); +/* + * Type representing an OS's process. + * !! Do NOT use the fields directly, use the appropriate macros instead. + */ +typedef struct msh_process_t { +#ifdef __linux__ + SIZE_TYPE __pid; +#endif +} msh_process; + /* * Execute given command with args. * * cmd is self explanatory, args is a null terminated array of strings based on * the arguments the user provided. * + * Returns the process to be waited on. * * Non-zero return values are the exit status. -1 implies the command was not * found.