-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
417 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// Stephen Terrio B00755443 | ||
|
||
// Base taken from Assignement 2 PDF - | ||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
#include <sys/wait.h> | ||
#include "linked_list.h" | ||
|
||
// CITED RESOURCES: LinkedList.c with its respective header has been taken from previous work done in the class: Systems Programming | ||
// It is only used for the history command. | ||
|
||
#define MAX_LINE 80 /* max command length */ | ||
|
||
// MAIN - | ||
int main (void){ | ||
/* flag for program execution vs termination */ | ||
int should_run = 1; | ||
LinkedList* history = llist_initialize(sizeof(char*),"string"); | ||
LinkedList* ids = llist_initialize(sizeof(int*),"integer"); | ||
|
||
while(should_run == 1) { | ||
printf("CSCI3120>"); | ||
fflush(stdout); | ||
|
||
/* Reading user input, refrencing back to my solution of A1... */ | ||
char input[250]; | ||
// getting input until new line & discarding, adding to history list & checking special commands | ||
scanf("%[^\n]%*c", input); | ||
|
||
if(!strcmp("!!",input)){ | ||
if(history->size == 0){printf("No command in history!\n");continue;} | ||
strcpy(input,llist_get(history, 0)); | ||
printf("CSCI3120>%s\n", input); | ||
|
||
}else if(input[0] == '!'){ | ||
int index = input[1] - '0'; | ||
if(index > history->size){printf("Such a command is NOT in history!\n"); continue;} | ||
strcpy(input,llist_get(history,index - 1)); | ||
printf("CSCI3120>%s\n", input); | ||
} | ||
if(strcmp("history",input)){llist_add_first(history, input);} | ||
char *split = strtok(input, " "); | ||
// 41 tokens at most, 39 buffer tokens | ||
char *arrayofchars[80]; | ||
int counter = 0; | ||
// looping till there can be no more splits | ||
while(split != NULL){ | ||
arrayofchars[counter] = split; | ||
split = strtok(NULL, " "); | ||
counter = counter + 1; | ||
} | ||
|
||
// checking for exit command | ||
if(!strcmp("exit",arrayofchars[0])){should_run = 0;} | ||
|
||
// handling for history command | ||
if(!strcmp("history",arrayofchars[0])){ | ||
if(history->size == 0){printf("No command in history!\n"); continue;} | ||
printf("ID PID Command\n"); | ||
for(int i = 0; i < history->size && i < 10; i++){ | ||
int tempID = (*(int *)llist_get(ids,i)); | ||
printf("%d %d %s\n", i+1, tempID, llist_get(history,i)); | ||
} | ||
continue; | ||
} | ||
// Keeping track of function stats in case of error | ||
int execpStatus; | ||
int waitStatus; | ||
/* Fork to a child process */ | ||
pid_t child; | ||
child = fork(); | ||
// saving to be used later in history | ||
void *id = &child; | ||
llist_add_first(ids, id); | ||
|
||
// should not be non-negative unless an error occured, referencing class notes pdf | ||
if(child < 0){ | ||
printf("An error occured Forking"); | ||
return 1; | ||
} | ||
/*Child Process Running Correctly*/ | ||
else if(child == 0 && should_run != 0){ | ||
execpStatus = execvp(arrayofchars[0], arrayofchars); | ||
if(execpStatus == -1){ | ||
// an error has occured | ||
printf("Invalid command!"); | ||
exit(1); | ||
} | ||
} | ||
/* Parent Process */ | ||
else { | ||
wait(&waitStatus); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
TO COMPILE: | ||
open terminal and find folder containing .c and .h files | ||
cd into it and execute this command in terminal once reaching directory | ||
|
||
gcc A2.c linked_list.c -o a2 | ||
|
||
once compiled, run command ./a2 to execute program |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,278 @@ | ||
#include "linked_list.h" | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
LinkedList* llist_initialize(int typeSize, char* typeName) | ||
{ | ||
// Create a linked list struct. | ||
LinkedList* llist = malloc(sizeof(*llist)); | ||
|
||
// If the linked list can't have memory allocated, return NULL. | ||
if(llist == NULL) | ||
return NULL; | ||
|
||
// Initialize all of the linked list fields. | ||
llist->first = NULL; | ||
llist->last = NULL; | ||
llist->size = 0; | ||
llist->itemSize = typeSize; | ||
llist->type = malloc(strlen(typeName)); | ||
strcpy(llist->type, typeName); | ||
|
||
// Return the empty linked list. | ||
return llist; | ||
} | ||
|
||
bool llist_add_at(LinkedList* llist, int index, void* element) | ||
{ | ||
// If the list or element are null, return false. | ||
if(llist == NULL || element == NULL) | ||
return false; | ||
|
||
// If the index doesn't fit in the bounds of the | ||
// list, we can return false. | ||
if(index < 0 || index > llist->size) | ||
return false; | ||
|
||
// Create a new node and populate its data. | ||
Node *node = malloc(sizeof(*node)); | ||
node->data = malloc(llist->itemSize); | ||
memcpy(node->data, element, llist->itemSize); | ||
|
||
// If we haven't added any nodes yet, we need to | ||
// ensure both the first and last are updated. | ||
if(llist->size == 0) | ||
{ | ||
llist->first = node; | ||
llist->last = node; | ||
node->next = NULL; | ||
node->prev = NULL; | ||
} | ||
// If we are adding on the front of the list, | ||
// we only need to deal with the first pointer. | ||
else if(index == 0) | ||
{ | ||
node->next = llist->first; | ||
node->prev = NULL; | ||
llist->first->prev = node; | ||
llist->first = node; | ||
} | ||
// If we are adding on the end of the list, | ||
// we only need to deal with the last pointer. | ||
else if(index == llist->size) | ||
{ | ||
node->next = NULL; | ||
node->prev = llist->last; | ||
llist->last->next = node; | ||
llist->last = node; | ||
} | ||
// If we get here, we are inserting somewhere | ||
// in the middle of the list. | ||
else | ||
{ | ||
// Create a temporary traversal node. | ||
Node *temp = llist->first; | ||
|
||
// Iterate until we get to the node to be removed. | ||
for(int i=0; i < index; i++) | ||
temp = temp->next; | ||
|
||
// Set the new node's previous to the current node's previous. | ||
node->prev = temp->prev; | ||
|
||
// Set the new node's next to the current node. | ||
node->next = temp; | ||
|
||
// Set the previous node to point to the new one. | ||
temp->prev->next = node; | ||
|
||
// Set the current node to point to the new one. | ||
temp->prev = node; | ||
} | ||
|
||
// Increase the size of the linked list by 1. | ||
llist->size++; | ||
return true; | ||
} | ||
|
||
bool llist_add_first(LinkedList* llist, void* element) | ||
{ | ||
// We can simply call/return "add_at". It will check for NULL. | ||
return llist_add_at(llist, 0, element); | ||
} | ||
|
||
bool llist_add_last(LinkedList* llist, void* element) | ||
{ | ||
// We need to check if llist is null before we | ||
// use llist->size, otherwise we'll seg fault. | ||
if(llist == NULL) | ||
return false; | ||
|
||
// Return the value of "add_at" on the list size. | ||
return llist_add_at(llist, llist->size, element); | ||
} | ||
|
||
void* llist_get(LinkedList* llist, int index) | ||
{ | ||
// If the list is null, we return null. | ||
if(llist == NULL) | ||
return NULL; | ||
|
||
// If the index isn't in the list right now, return null. | ||
if(index < 0 || index >= llist->size) | ||
return NULL; | ||
|
||
// Create a temporary node variable and store the first node. | ||
Node *temp = llist->first; | ||
|
||
// Iterate through the list until we find the element. | ||
for(int i=0; i < index; i++) | ||
temp = temp->next; | ||
|
||
// Return a pointer to the element. | ||
return temp->data; | ||
} | ||
|
||
int llist_index_of(LinkedList* llist, void* element) | ||
{ | ||
// If the list is null or the element is null, we return -1. | ||
if(llist == NULL || element == NULL) | ||
return -1; | ||
|
||
// Create a temporary node variable and store the first node. | ||
Node *temp = llist->first; | ||
|
||
// Iterate through the list until we find the element. | ||
for(int i=0; i < llist->size; i++) | ||
{ | ||
// Compare the element to the stored data of this node. | ||
// If the data matches the element, return the index. | ||
if(memcmp(temp->data, element, llist->itemSize) == 0) | ||
return i; | ||
|
||
// Move to the next list node. | ||
temp = temp->next; | ||
} | ||
|
||
// If we get here, the list didn't have the element. Return -1. | ||
return -1; | ||
} | ||
|
||
void* llist_remove(LinkedList* llist, int index) | ||
{ | ||
// If the list is null, return null. | ||
if(llist == NULL) | ||
return NULL; | ||
|
||
// If the index is out of bounds, return null. | ||
if(index < 0 || index >= llist->size) | ||
return NULL; | ||
|
||
// Create a temporary node. | ||
Node *temp = llist->first; | ||
|
||
// Iterate until we get to the node to be removed. | ||
for(int i=0; i < index; i++) | ||
temp = temp->next; | ||
|
||
// Adjust the pointers of adjacent nodes and linked list: | ||
// 1) If the list only has one node, we simply set the | ||
// linked list's first and last pointers to NULL. | ||
// 2) If we are removing the first node, we only have to | ||
// adjust the next node's pointers and update the | ||
// linked list's first node pointer. | ||
// 3) If we are removing the last node, we only have to | ||
// adjust the previous node's pointers and update the | ||
// linked list's last node pointer. | ||
// 4) Otherwise we adjust the next and prev nodes to make | ||
// sure they point to each other. | ||
if(llist->size == 1) | ||
{ | ||
llist->first = NULL; | ||
llist->last = NULL; | ||
} | ||
else if(index == 0) | ||
{ | ||
llist->first = temp->next; | ||
llist->first->prev = NULL; | ||
} | ||
else if(index == llist->size-1) | ||
{ | ||
llist->last = temp->prev; | ||
llist->last->next = NULL; | ||
} | ||
else | ||
{ | ||
temp->prev->next = temp->next; | ||
temp->next->prev = temp->prev; | ||
} | ||
|
||
// Reduce the size of the linked list by 1. | ||
llist->size--; | ||
|
||
// Save the data from the node. | ||
void* data = temp->data; | ||
|
||
// Free the node. | ||
free(temp); | ||
|
||
// Return the removed node. It is up to the owner to free it. | ||
return data; | ||
} | ||
|
||
void* llist_remove_first(LinkedList* llist) | ||
{ | ||
// We can call "remove" on the first index. | ||
return llist_remove(llist, 0); | ||
} | ||
|
||
void* llist_remove_last(LinkedList* llist) | ||
{ | ||
// If llist is null, we can't use the the | ||
// llist->size member without a seg fault. | ||
if(llist == NULL) | ||
return false; | ||
|
||
// We can call "remove" on the last index. | ||
return llist_remove(llist, llist->size-1); | ||
} | ||
|
||
bool llist_destroy(LinkedList* llist) | ||
{ | ||
// If the list is null, we can't destroy it. Return false. | ||
if(llist == NULL) | ||
return false; | ||
|
||
// If there are nodes available in the list, free them. | ||
if(llist->size > 0) | ||
{ | ||
// Create a temporary node for holding nodes. | ||
Node *current = llist->first; | ||
Node *next = NULL; | ||
|
||
// Iterate through all of the nodes. | ||
for(int i=0; i < llist->size; i++) | ||
{ | ||
// Store a pointer to the next node. | ||
next = current->next; | ||
|
||
// Free this node's data. | ||
free(current->data); | ||
|
||
// Free this node. | ||
free(current); | ||
|
||
// We move to the next node. | ||
current = next; | ||
} | ||
} | ||
|
||
// Free the necessary linked list fields. | ||
free(llist->type); | ||
|
||
// Free the linked list. | ||
free(llist); | ||
|
||
// We destroyed the list. Return true. | ||
return true; | ||
} |
Oops, something went wrong.