diff --git a/Makefile b/Makefile index ed958b4..6d352fe 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,30 @@ INC := -I include -all: main exec +all: compile link -main: +compile: gcc $(INC) -c -o build/main.o src/main.c + gcc $(INC) -c -o build/Common.o src/Common.c gcc $(INC) -c -o build/Integrated.o src/Integrated.c gcc $(INC) -c -o build/Pish.o src/Pish.c -exec: +link: gcc -o bin/pish.out build/*.o +exec: compile link + ./bin/pish.out + +debug: clean debugCompile debugLink + +debugCompile: + gcc $(INC) -g -c -o build/main.o src/main.c + gcc $(INC) -g -c -o build/Integrated.o src/Integrated.c + gcc $(INC) -g -c -o build/Common.o src/Common.c + gcc $(INC) -g -c -o build/Pish.o src/Pish.c + +debugLink: + gcc -g -o bin/pish.out build/*.o + clean: - rm build/* + rm build/*.o + rm bin/*.out diff --git a/include/Common.h b/include/Common.h new file mode 100755 index 0000000..25ac07a --- /dev/null +++ b/include/Common.h @@ -0,0 +1,11 @@ +#ifndef COMMON_H +#define COMMON_H + +typedef struct CommandStruct { + char* argv[100]; // Max 100 commands + int argc; +} CommandStruct; + +void ResetCommandStruct(CommandStruct* command); + +#endif \ No newline at end of file diff --git a/include/Integrated.h b/include/Integrated.h index fe2509b..ecfd85f 100755 --- a/include/Integrated.h +++ b/include/Integrated.h @@ -1,6 +1,17 @@ #ifndef INTEGRATED_H #define INTEGRATED_H -void IntegratedCheck(char* command); +#include "Common.h" + +const char* GetHomeDir(void); +void ioRedirection(CommandStruct *command); +int IntegratedCheck(CommandStruct* command); +void GetInput(char* inputString); +void append(char *input, char *file); +void input(char *command); +void ExecPipe(); +void output(char *command); +void ParseInput(char* inputString, CommandStruct* command); +void ReadPishrc(CommandStruct* command, char* inputString); #endif \ No newline at end of file diff --git a/include/Pish.h b/include/Pish.h index fd60acd..9b54a1a 100644 --- a/include/Pish.h +++ b/include/Pish.h @@ -1,8 +1,8 @@ #ifndef PISH_H #define PISH_H -char* getcmd(void); -void exec(char* command); +#include "Common.h" + void Pish(void); #endif diff --git a/src/Common.c b/src/Common.c new file mode 100644 index 0000000..1f230a8 --- /dev/null +++ b/src/Common.c @@ -0,0 +1,11 @@ +#include "Common.h" +#include +#include + +void ResetCommandStruct(CommandStruct* command) +{ + for (int i = 0; i < command->argc; i++) + command->argv[i] = NULL; + command->argc = 0; + return; +} diff --git a/src/Integrated.c b/src/Integrated.c index 00103c8..3722651 100755 --- a/src/Integrated.c +++ b/src/Integrated.c @@ -1,14 +1,218 @@ +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include "Integrated.h" -// Checks for commands that are built into Pish -void IntegratedCheck(char* command) +// Gets home directory location of user +const char *GetHomeDir(void) { - if (command == "exit") - exit(0); - // If there is an argument, change to argument location - // Else, change to home directory - if (command[0] == 'c' && command[1] == 'd') - ; - return; -} \ No newline at end of file + char *homeDir = (getpwuid(getuid()))->pw_dir; + return homeDir; +} + +// Checks for commands that are built into Pish +int IntegratedCheck(CommandStruct *command) +{ + if (strcmp(command->argv[0], "exit") == 0) + exit(0); + // If there is an argument, change to argument location + // Else, change to home directory + if (command->argv[0][0] == 'c' && command->argv[0][1] == 'd') + { + if (command->argv[1] != NULL) + chdir(command->argv[1]); + if (command->argv[1] == NULL) + chdir(GetHomeDir()); + return 1; + } + return 0; +} + +// Prints a prompt and then reads a command from the terminal +void GetInput(char *inputString) +{ + char c; + char *prompt = "pish%>"; + printf("%s ", prompt); + // assert(scanf("%[^\n]s", inputString) == 1); + scanf("%1000[^\n]s", inputString); + while ((c = getchar()) != '\n' && c != EOF) + /* discard */; + return; +} + +// Splits a string separated by spaces into an array of strings +void ParseInput(char *inputString, CommandStruct *command) +{ + // Parse command + int *argc = &(command->argc); + char *token = strtok(inputString, " "); + command->argv[*argc] = token; + (*argc)++; + while (token != NULL) + { + // This only holds 1 command at a time then it overrides + // Will need modified + token = strtok(NULL, " "); + command->argv[*argc] = token; + (*argc)++; + } +} + +// Reads ~/.pishrc and runs each command in the file +void ReadPishrc(CommandStruct *command, char *inputString) +{ + char buffer[1]; + int forkID; + int *argc = &(command->argc); + char* pishLocation = GetHomeDir(); + strcat(pishLocation, "/.pishrc"); + int fd = open(pishLocation, O_RDONLY | O_CREAT); + assert(fd > -1); + while (read(fd, buffer, 1) > 0) + { + if (buffer[0] == '\n') + { + ParseInput(inputString, command); + forkID = fork(); + if (forkID == 0) + execvp(command->argv[0], command->argv); + else + wait(&forkID); + strcpy(inputString, ""); + ResetCommandStruct(command); + continue; + } + strcat(inputString, buffer); + } + assert(close(fd) >= 0); +} + +// i/o redirection +// TODO: Work on one symbol at a time +// inputString may not be useful here, only *command +// Try to add a layer of abstraction where possible +// I.E. think about using function instead for checking +void ioRedirection(CommandStruct *command) +{ + int newfd; + // check command standard output + // TODO: Check command->argv[] for symbol instead + for(int i = 0; i < sizeof(command); i++) + { + if (strchr(command->argv[i], '>') != NULL) + { + output(command->argv[i+1]); + // Check if targeting a specific string in command->argv works + } + if (strchr(command->argv[i], '<') != NULL) + { + input(command->argv[i+1]); + } + if (strchr(command->argv[i], '|')!= NULL) + { + // not sure if i + 1 correct + // pipe(command->argv[i+1]); + } + if (strpbrk(command->argv[i], ">>")!= NULL) + { + append(command->argv[i-1], command->argv[i+1]); + } + } +} + +void output(char *command){ + int newfd; + if (newfd = open(command, O_CREAT | O_TRUNC | O_WRONLY, 0644) < 0) + { + perror(command); + exit(1); + } + dup2(newfd,1); +} + +void input(char *command) +{ + int newfd; + if (newfd = open(command, O_RDONLY) < 0) + { + perror(command); + exit(1); + } + dup2(newfd,0); +} + +void ExecPipe() +{ + ; +} + +void append(char *input, char *file) +{ + FILE *fp; + fp = fopen(file, "a+"); + fputs(input, fp); + fclose(fp); +} + +// check command standard input +// if (strchr(inputString, '<') != NULL) +// { +// newfd = open((command, O_CREAT |O_TRUNC | O_WRONLY, 0644)) < 0); +// // No if statement for fail checking, brackets just exist here +// { +// // failed +// perror(command); +// exit(1); +// } +// dup2(newfd, 0); +// } + +// check pipe +// TODO: Check for pipe symbol +// Check in command->argv[] instead +// if (strchr(command, '|') != NULL) +// { +// ; +// } +// check append +// TODO: Implement append +// if (strpbrk(command, ">>") != NULL) +// { +// newfd = open((command, O_CREAT |O_TRUNC | O_WRONLY, 0644)) < 0); +// // No if statement for fail checking, brackets just exist here +// { +// // failed +// perror(command); +// exit(1); +// } +// dup2(newfd, 0); +// } +// check pipe +// TODO: Check pipe already exists above, maybe loop? +// if (strchr(command, '|') != NULL) +// { +// ; +// } +// check append +// TODO: Check append already exists above, maybe loop? +// if (strpbrk(command, ">>") != NULL) +// { +// ; +// } + +// Environment varibles +// TODO: Add this function to CommandStruct +// Environment Variables can just be a part of the struct +// void varibles(char str, int count) +// { +// char var[1000]; +// var[count] = str; +// } diff --git a/src/Pish.c b/src/Pish.c index cac9605..a4d370d 100644 --- a/src/Pish.c +++ b/src/Pish.c @@ -1,51 +1,43 @@ +#include #include #include #include #include +#include #include "Integrated.h" #include "Pish.h" -// Prints a prompt and then reads a command from the terminal -char* getInput(void) -{ - return "echo hello world"; -} - -// Executes a command to the system -void exec(char* command) -{ - system(command); -} - // Main function for Pish program void Pish(void) { - char* command; - int retval; + CommandStruct commandObject = {"", 0}; + CommandStruct* command = &commandObject; + char inputString[1000]; // Max 1000 characters + int forkPID; + ReadPishrc(command, inputString); while (1) { - command = getInput(); - IntegratedCheck(command); - retval = fork(); + ResetCommandStruct(command); // Clean command + strcpy(inputString, ""); // Clean inputString + GetInput(inputString); + ParseInput(inputString, command); + if (IntegratedCheck(command)) + continue; + forkPID = fork(); // Child - if (retval == 0) + if (forkPID == 0) { // This is the child process // Setup the child's process environment here // E.g., where is standard I/O, how to handle signals? - exec(command); + // execve() is recommended, execvpe() may be better + execvp(command->argv[0], command->argv); // exec does not return if it succeeds - printf("ERROR: Could not execute %s\n", command); + printf("ERROR: Could not execute %s\n", inputString); exit(1); } // Parent - else - { - // This is the parent process; Wait for the child to finish - int pid = retval; - wait(pid); - } - // TODO: Remove break when while loop doesn't break program - break; + // This is the parent process; Wait for the child to finish + wait(&forkPID); } }