aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Lance Borden 2024-09-23 09:51:17 -0400
committerGravatar GitHub 2024-09-23 09:51:17 -0400
commitb578aef7bf03fad539969aa671829e1a8643248b (patch)
tree0d1ac4d5d39de29c1cf7d4d682c09c50446b9821
parentUpdate README.md (diff)
parentimplemented piping into new chaining method (diff)
Merge pull request #2 from BanceDev/chaining-operators
Chaining operators
-rw-r--r--src/lua_api.c2
-rw-r--r--src/lush.c222
-rw-r--r--src/lush.h5
3 files changed, 190 insertions, 39 deletions
diff --git a/src/lua_api.c b/src/lua_api.c
index 99892c7..d40489c 100644
--- a/src/lua_api.c
+++ b/src/lua_api.c
@@ -99,7 +99,7 @@ static int execute_command(lua_State *L, const char *line) {
int status = 0;
lush_push_history(line);
char *expanded_line = lush_resolve_aliases((char *)line);
- char **commands = lush_split_pipes(expanded_line);
+ char **commands = lush_split_commands(expanded_line);
char ***args = lush_split_args(commands, &status);
if (status == -1) {
diff --git a/src/lush.c b/src/lush.c
index 0be4d4d..1cdb50d 100644
--- a/src/lush.c
+++ b/src/lush.c
@@ -25,6 +25,7 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#include "lualib.h"
#include <asm-generic/ioctls.h>
#include <bits/time.h>
+#include <ctype.h>
#include <dirent.h>
#include <linux/limits.h>
#include <locale.h>
@@ -43,6 +44,18 @@ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#define BUFFER_SIZE 1024
+typedef enum {
+ OP_PIPE = 1, // |
+ OP_AND, // &&
+ OP_OR, // ||
+ OP_SEMICOLON, // ;
+ OP_BACKGROUND, // &
+ OP_REDIRECT_OUT, // >
+ OP_APPEND_OUT, // >>
+ OP_REDIRECT_IN, // <
+ OP_OTHER // All other operators like parentheses, braces, etc.
+} OperatorType;
+
// initialize prompt format
char *prompt_format = NULL;
@@ -126,7 +139,7 @@ int lush_help(lua_State *L, char ***args) {
return 1;
}
-int lush_exit(lua_State *L, char ***args) { return 0; }
+int lush_exit(lua_State *L, char ***args) { exit(0); }
int lush_time(lua_State *L, char ***args) {
// advance past time command
@@ -935,34 +948,104 @@ char *lush_resolve_aliases(char *line) {
return result;
}
-char **lush_split_pipes(char *line) {
+static int is_operator(const char *str) {
+ const char *operators[] = {"||", "&&", "&", ";", ">>", ">", "<",
+ "\\", "(", ")", "{", "}", "!", "|"};
+ int num_operators = sizeof(operators) / sizeof(operators[0]);
+ for (int i = 0; i < num_operators; i++) {
+ if (strncmp(str, operators[i], strlen(operators[i])) == 0) {
+ switch (i) {
+ case 0:
+ return OP_OR;
+ case 1:
+ return OP_AND;
+ case 2:
+ return OP_BACKGROUND;
+ case 3:
+ return OP_SEMICOLON;
+ case 4:
+ return OP_APPEND_OUT;
+ case 5:
+ return OP_REDIRECT_OUT;
+ case 6:
+ return OP_REDIRECT_IN;
+ case 13:
+ return OP_PIPE;
+ default:
+ return OP_OTHER; // Parentheses, braces, etc.
+ }
+ }
+ }
+ return 0; // Not an operator
+}
+
+static char *trim_whitespace(char *str) {
+ char *end;
+
+ // Trim leading space
+ while (isspace((unsigned char)*str))
+ str++;
+
+ if (*str == 0)
+ return str; // If all spaces, return empty string
+
+ // Trim trailing space
+ end = str + strlen(str) - 1;
+ while (end > str && isspace((unsigned char)*end))
+ end--;
+
+ *(end + 1) = '\0';
+
+ return str;
+}
+
+// Split the command based on various chaining operations
+char **lush_split_commands(char *line) {
char **commands = calloc(16, sizeof(char *));
if (!commands) {
perror("calloc failed");
exit(1);
}
- char *command;
int pos = 0;
+ char *start = line;
+ while (*start) {
+ // Skip leading spaces
+ while (isspace((unsigned char)*start))
+ start++;
+
+ // Check for operators
+ int op_len = is_operator(start);
+ if (op_len > 0) {
+ // Allocate memory for operator command
+ char *operator_cmd = calloc(op_len + 1, sizeof(char));
+ strncpy(operator_cmd, start, op_len);
+ commands[pos++] = operator_cmd;
+ start += op_len;
+ } else {
+ // Collect regular commands until the next operator or end of string
+ char *next = start;
+ while (*next && !is_operator(next)) {
+ next++;
+ }
- command = strtok(line, "|");
- while (command) {
- commands[pos++] = command;
- command = strtok(NULL, "|");
- }
-
- // trim off whitespace
- for (int i = 0; i < pos; i++) {
- while (*commands[i] == ' ' || *commands[i] == '\n') {
- commands[i]++;
+ // Copy the command between start and next
+ char *command = strndup(start, next - start);
+ commands[pos++] = trim_whitespace(command);
+ start = next;
}
- char *end_of_str = strrchr(commands[i], '\0');
- --end_of_str;
- while (*end_of_str == ' ' || *end_of_str == '\n') {
- *end_of_str = '\0';
- --end_of_str;
+
+ if (pos >= 16) {
+ // Resize if necessary
+ commands = realloc(commands, (pos + 16) * sizeof(char *));
+ if (!commands) {
+ perror("realloc failed");
+ exit(1);
+ }
}
}
+
+ commands[pos] = NULL;
return commands;
}
@@ -1044,6 +1127,80 @@ char ***lush_split_args(char **commands, int *status) {
return command_args;
}
+static int run_command(lua_State *L, char ***commands) {
+ // check if the command is a lua script
+ char *ext = strrchr(commands[0][0], '.');
+ if (ext) {
+ ext++;
+ if (strcmp(ext, "lua") == 0) {
+ return ((*builtin_func[4])(L, commands));
+ }
+ }
+
+ // check shell builtins
+ for (int j = 0; j < lush_num_builtins(); j++) {
+ if (strcmp(commands[0][0], builtin_strs[j]) == 0) {
+ return ((*builtin_func[j])(L, commands));
+ }
+ }
+
+ return lush_execute_command(commands[0], STDIN_FILENO, STDOUT_FILENO);
+}
+
+int lush_execute_chain(lua_State *L, char ***commands, int num_commands) {
+ if (commands[0][0][0] == '\0') {
+ return 1;
+ }
+
+ int num_actions = (num_commands + 1) / 2;
+ int last_result = 0;
+
+ for (int i = 0; i < num_actions; i++) {
+ // Determine the operator type between commands
+ if (i < num_actions - 1) {
+ int op_type = is_operator(commands[1][0]);
+
+ // Handle '&&' operator
+ if (op_type == OP_AND && last_result != 0) {
+ commands += 2;
+ continue;
+ }
+
+ // Handle '|', build pipe array
+ if (op_type == OP_PIPE) {
+ char ***pipe_commands =
+ malloc(sizeof(char **) * (num_actions - i));
+ int pipe_count = 0;
+
+ while (i < num_actions - 1 && op_type == OP_PIPE) {
+ pipe_commands[pipe_count++] = commands[0];
+ commands += 2;
+ i++;
+ if (i < num_actions - 1) {
+ op_type = is_operator(commands[1][0]);
+ } else {
+ break;
+ }
+ }
+
+ pipe_commands[pipe_count++] = commands[0];
+ last_result = lush_execute_pipeline(pipe_commands, pipe_count);
+
+ free(pipe_commands);
+ commands += 2;
+ continue;
+ }
+ }
+
+ if (!is_operator(commands[0][0])) {
+ last_result = run_command(L, commands);
+ commands += 2;
+ }
+ }
+
+ return last_result;
+}
+
int lush_execute_pipeline(char ***commands, int num_commands) {
// no command given
if (commands[0][0][0] == '\0') {
@@ -1086,7 +1243,7 @@ int lush_execute_pipeline(char ***commands, int num_commands) {
return 1;
}
-void lush_execute_command(char **args, int input_fd, int output_fd) {
+int lush_execute_command(char **args, int input_fd, int output_fd) {
// create child
pid_t pid;
int status;
@@ -1098,6 +1255,8 @@ void lush_execute_command(char **args, int input_fd, int output_fd) {
// restore default sigint for child
sa.sa_handler = SIG_DFL;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
sigaction(SIGINT, &sa, NULL);
// redirect in and out fd's if needed
@@ -1126,6 +1285,12 @@ void lush_execute_command(char **args, int input_fd, int output_fd) {
waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
+
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ } else {
+ return -1;
+ }
}
int lush_run(lua_State *L, char ***commands, int num_commands) {
@@ -1134,22 +1299,7 @@ int lush_run(lua_State *L, char ***commands, int num_commands) {
return 1;
}
- // check if the command is a lua script
- char *ext = strrchr(commands[0][0], '.');
- if (ext) {
- ext++;
- if (strcmp(ext, "lua") == 0) {
- return ((*builtin_func[4])(L, commands));
- }
- }
-
- // check shell builtins
- for (int i = 0; i < lush_num_builtins(); i++) {
- if (strcmp(commands[0][0], builtin_strs[i]) == 0) {
- return ((*builtin_func[i])(L, commands));
- }
- }
- return lush_execute_pipeline(commands, num_commands);
+ return lush_execute_chain(L, commands, num_commands);
}
int main(int argc, char *argv[]) {
@@ -1221,7 +1371,7 @@ int main(int argc, char *argv[]) {
continue;
}
char *expanded_line = lush_resolve_aliases(line);
- char **commands = lush_split_pipes(expanded_line);
+ char **commands = lush_split_commands(expanded_line);
char ***args = lush_split_args(commands, &status);
if (status == -1) {
fprintf(stderr, "lush: Expected end of quoted string\n");
diff --git a/src/lush.h b/src/lush.h
index 15d4d71..291a8dd 100644
--- a/src/lush.h
+++ b/src/lush.h
@@ -35,11 +35,12 @@ int lush_num_builtins();
int lush_run(lua_State *L, char ***commands, int num_commands);
char *lush_read_line();
-char **lush_split_pipes(char *line);
+char **lush_split_commands(char *line);
char ***lush_split_args(char **commands, int *status);
-void lush_execute_command(char **args, int input_fd, int output_fd);
+int lush_execute_command(char **args, int input_fd, int output_fd);
int lush_execute_pipeline(char ***commands, int num_commands);
+int lush_execute_chain(lua_State *L, char ***commands, int num_commands);
void lush_format_prompt(const char *prompt_format);