Semester's final Project assignment for "Operating Systems" course at AUTH University
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

225 lines
5.4 KiB

7 years ago
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/wait.h>
#include "apostolofShellFunctions.h"
const char semicolonDelimeter[2] = ";";
const char ampersandDelimeter[2] = "&";
void interactiveMode(){
char input[BUFFER_SIZE];
int quit_called = 0;
while (1){
printf(GRN "\x1B[1mfanakis_8261> \x1B[0m" RESET);
//Gets user input and checks for errors
if (!fgets(input, BUFFER_SIZE, stdin) || feof(stdin) || ferror(stdin)){
continue;
}
//Checks for input buffer overflow
if ((strlen(input) == BUFFER_SIZE - 1) && input[BUFFER_SIZE - 2] != '\n'){
printf("Input too long! Please confine input to 512 characters.\n");
//Clears garbage from stdin
char discarded;
while ((discarded = fgetc(stdin)) != '\n' && discarded != EOF);
continue;
}
//Trims possible leading and trailing whitespace
strcpy(input, trimWhitespaces(input));
if (strcmp(input, "\n") == 0 || input == 0){
continue;
}
//Parses semicolon-separated chunks first
unconditionalRun(input, &quit_called);
if (quit_called == QUIT_CALLED){
exit(EXIT_SUCCESS);
}
}
}
void batchFileMode(char *filename){
char line[BUFFER_SIZE];
int quit_called = 0;
//Opens file
FILE* file = fopen(filename, "r");
if (!file){
printf("Couldn't open file.\n");
exit(EXIT_FAILURE);
}
//Reads file one line at a time
while (fgets(line, sizeof(line), file)) {
strcpy(line, trimWhitespaces(line));
if (strcmp(line, "\n") == 0 || line == 0){
continue;
}
unconditionalRun(line, &quit_called);
if (quit_called == QUIT_CALLED){
fclose(file);
exit(EXIT_SUCCESS);
}
}
fclose(file);
return;
}
void unconditionalRun(char *input, int *quit_called){
char *rest, *token;
//Parses chunks of input split by semicolons (";")
//Gets first token
token = strtok_r(input, semicolonDelimeter, &rest);
while (token != NULL){
//Further parses and conditionally runs chunks
conditionalRun(token, quit_called);
//Parses ampersand-separated chunks and runs them successively
if (*quit_called == QUIT_CALLED){
return;
} /*else if ((*rest == 0)){
return 1;
}*/
token = strtok_r(NULL, semicolonDelimeter, &rest);
}
}
void conditionalRun(char *input, int *quit_called){
char *rest, *token;
//Parses ampersand-separated chunks
//Gets first token
token = strtok_r(input, ampersandDelimeter, &rest);
while (token != NULL){
char *command, **argv;
int argc = 0;
//Parses the command
parseCommand(trimWhitespaces(token), &command, &argv, &argc);
if (strcmp(command, "quit") == 0){
*quit_called = QUIT_CALLED;
return;
}
//Executes the command
if (execute(command, argv)){
//Exits on failure because this is a conditional run
return;
}
//Cleans up space allocated
free(command);
for (int i=0; i<argc; ++i){
free(argv[i]);
}
free(argv);
//Checks if chunk isn't split by a double ampersand
if (strlen(rest) != 0){
if (!(rest[0] == '&' && isspace(rest[1]))){
printf("Not supported\n");
return;
}
}
//Gets next token
token = strtok_r(NULL, ampersandDelimeter, &rest);
}
}
int execute(char *command, char **argv){
pid_t pid;
int status = 0;
if ((pid = fork()) < 0) {
//Failed to create child process
perror("Can't fork");
exit(EXIT_FAILURE);
} else if (pid == 0) {
//Child process
if (execvp(command, argv)) {
perror("Error executing command");
_exit(EXIT_FAILURE);
}
} else {
//Parent process
while (wait(&status) != pid)
;
return status;
}
return status;
}
void parseCommand(char *input, char **command, char ***argv, int *argc){
char *token = strtok(input, " ");
*argc = 1;
//Allocates memory and copies command
*command = (char*)(malloc((strlen(token) + 1) * sizeof(char)));
strcpy(*command, trimWhitespaces(token));
(*command)[strlen(*command)] = '\0';
//Allocates memory and copies first argument (command)
*argv = (char**)(malloc((*argc) * sizeof(char*)));
(*argv)[(*argc) - 1] = (char*)(malloc((strlen(*command) + 1) * sizeof(char)));
strcpy((*argv)[(*argc) - 1], *command);
(*argv)[(*argc) - 1][strlen((*argv)[(*argc) - 1])] = '\0';
//Parses the rest of the arguments
7 years ago
token = strtok(NULL, " ");
while (token != NULL){
++(*argc);
*argv = (char**)(realloc(*argv, (*argc) * sizeof(char*)));
//Checks if argument is wrapped inside " or ' characters
if ( (token[0] == '"' && token[strlen(token) - 1] == '"' ) ||
(token[0] == '\'' && token[strlen(token) - 1] == '\'' ) ){
//Deletes wrapper characters
token++;
token[strlen(token) - 1] = '\0';
(*argv)[(*argc) - 1] = (char*)(malloc((strlen(token)) * sizeof(char)));
strcpy((*argv)[(*argc) - 1], trimWhitespaces(token));
} else {
(*argv)[(*argc) - 1] = (char*)(malloc((strlen(token) + 1) * sizeof(char)));
strcpy((*argv)[(*argc) - 1], trimWhitespaces(token));
(*argv)[(*argc) - 1][strlen((*argv)[(*argc) - 1])] = '\0';
}
7 years ago
token = strtok(NULL, " ");
}
//NULL-terminates arguments array
++(*argc);
*argv = (char**)(realloc(*argv, (*argc) * sizeof(char*)));
(*argv)[(*argc) - 1] = NULL;
}
char *trimWhitespaces(char *string){
char *end;
//Trims leading spaces
while (isspace( (unsigned char) *string )){
string++;
}
if(*string == 0){ //String was all spaces
return string;
}
//Trims trailing spaces
end = string + strlen(string) - 1;
while (end > string && isspace( (unsigned char) *end )){
end--;
}
//Writes new null terminator
*(end+1) = 0;
return string;
}