diff --git a/.gitignore b/.gitignore index 8a2de8f..423b430 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,7 @@ modules.order Module.symvers Mkfile.old dkms.conf + +# CLion +.idea/ +cmake-build-debug/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..198963d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.17) +project(linkBase VERSION 0.2.0 LANGUAGES C) + +set(CMAKE_C_STANDARD 99) + +add_executable(linkBase main.c linkedList.c linkedList.h) +add_executable(test test.c linkedList.c linkedList.h) diff --git a/LICENSE b/LICENSE index 463f5ba..6676eef 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Elikem Hermon +Copyright (c) 2020 Elikem Hermon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 6c41f01..567117d 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,22 @@ # LinkBase +[![GitHub version](https://badge.fury.io/gh/eliherm%2FLinkBase.svg)](https://badge.fury.io/gh/eliherm%2FLinkBase) + In memory database for storing collections of integers. Collections are stored using linked lists. ## Usage - -### Create -Create a new collection - -``` -> create [collection name] -``` - -### Prepend -Add a value to the start of a collection - -``` -> prepend [collection name] [value] -``` - -### Append -Add a value to the end of a collection - -``` -> append [collection name] [value] -``` - -### View -View all collections - -``` -> view [--all / -a] -``` - -View a single collection - -``` -> view [--one / -o] [collection name] -``` - -### Delete -Delete a specified collection - -``` -> delete [collection name] +The following operations can be performed on a collection. +``` +view prints the contents of the list +count counts the contents of the list +append [value] appends a value to the list +prepend [value] prepends a value to the list +insert [index] [value] inserts a value into the list at a specified index +del_first deletes the first value of the list +del_last deletes the last value of the list +del_idx [index] deletes a value at a specified index +exit Ends the current session +quit Ends the current session ``` ## License diff --git a/linkBase.c b/linkBase.c deleted file mode 100644 index 18ad970..0000000 --- a/linkBase.c +++ /dev/null @@ -1,259 +0,0 @@ -#include -#include -#include -#include -#include -#include "linkedList.h" - -#define ARG_LENGTH 21 // 20 chars for each argument -#define INPUT_LENGTH 61 - -indexNode *indexHead = NULL; - -void convertCase(char arg[]) { - int i = 0; - while(arg[i] != '\0') { - arg[i] = tolower(arg[i]); - i++; - } -} - -indexNode* findCollection(char name[]) { - indexNode *current = indexHead; - - while(current != NULL) { - if (strcmp(current->name, name) == 0) { - return current; - } - - if (current->next == NULL) break; - current = current->next; - } - - return NULL; -} - -void createCollection(char name[]) { - if (name[0] == '\0') { - fprintf(stderr, "Enter a collection name\n"); - return; - } - - if (findCollection(name) == NULL) { - Node *Collection = NULL; - Collection = initList(Collection); - indexHead = prependIndex(indexHead, Collection, name); - printf("Collection %s was successfully created\n", name); - } else { - fprintf(stderr, "%s cannot be created, it already exists\n", name); - } - -} - -void prependCollection(char name[], int value) { - if (name[0] == '\0') { - fprintf(stderr, "Enter a collection name\n"); - return; - } - - indexNode *collection = findCollection(name); - if (collection != NULL) { - if (collection->entries->empty == true) { - collection->entries->value = value; - collection->entries->empty = false; - } else { - collection->entries = prepend(collection->entries, value); - } - printf("Collection %s was successfully updated\n", name); - } else { - fprintf(stderr, "Collection %s was not not found\n", name); - } -} - -void appendCollection(char name[], int value) { - if (name[0] == '\0') { - printf("Enter a collection name\n"); - return; - } - - indexNode *collection = findCollection(name); - if (collection != NULL) { - if (collection->entries->empty == true) { - collection->entries->value = value; - collection->entries->empty = false; - } else { - collection->entries = append(collection->entries, value); - } - printf("Collection %s was successfully updated\n", name); - } else { - fprintf(stderr, "Collection %s was not not found\n", name); - } -} - -void viewDB() { - if (indexHead == NULL) { - fprintf(stderr, "The are no collections to be viewed\n"); - return; - } - - indexNode *collection = indexHead; - while (collection != NULL) { - printList(collection->entries, collection->name); - if (collection->next == NULL) break; - collection = collection->next; - } -} - -void viewCollection(char name[]) { - if (indexHead == NULL) { - fprintf(stderr, "The are no collections to be viewed\n"); - return; - } - - if (name[0] == '\0') { - fprintf(stderr, "Enter a collection name\n"); - return; - } - - indexNode *collection = findCollection(name); - if (collection != NULL) { - printList(collection->entries, collection->name); - } else { - fprintf(stderr, "Collection %s was not not found\n", name); - } -} - -void deleteCollection(char name[]) { - if (indexHead == NULL) { - fprintf(stderr, "The are no collections to be deleted\n"); - return; - } - - if (name[0] == '\0') { - fprintf(stderr, "Enter a collection name\n"); - return; - } - - char confirmation[10] = {}; - printf("Warning: This action cannot be reverted\nAre you sure you want to delete collection %s ?\nEnter 'y' or 'n' to confirm: ", name); - fgets(confirmation, 10, stdin); - - // Remove newline - if ((strlen(confirmation) > 0) && (confirmation[strlen(confirmation) - 1] == '\n')) { - confirmation[strlen(confirmation) - 1] = '\0'; - } - - convertCase(confirmation); - if ((strcmp(confirmation, "y") == 0) || (strcmp(confirmation, "yes") == 0)) { - bool success; - indexHead = deleteIndex(indexHead, name, &success); - if (success) { - printf("\nCollection %s was successfully deleted\n", name); - } else { - fprintf(stderr, "Collection %s was not found\n", name); - } - } else { - printf("\n"); - } -} - -void extractArgs(char input[], char argList[][ARG_LENGTH]) { - int argIndex = 0; - - char *ptr = NULL; - ptr = strtok(input, " "); - if (ptr == NULL) return; - - strcpy(argList[argIndex], ptr); - argIndex++; - while(argIndex < 3) { - ptr = strtok(NULL, " "); - if (ptr == NULL) break; - strcpy(argList[argIndex], ptr); - argIndex++; - } -} - -int commandList(char cmd[]) { - if (strcmp(cmd, "help") == 0) { - return 1; - } else if (strcmp(cmd, "create") == 0) { - return 2; - } else if (strcmp(cmd, "prepend") == 0) { - return 3; - } else if (strcmp(cmd, "append") == 0) { - return 4; - } else if (strcmp(cmd, "view") == 0) { - return 5; - } else if (strcmp(cmd, "delete") == 0) { - return 6; - } else if ((strcmp(cmd, "exit") == 0) || (strcmp(cmd, "quit") == 0)) { - return 0; - } else { - return -1; - } -} - -// TODO: Use getch() for arrow keys -void prompt() { - bool isTerminated = false; - char *endPtr = NULL; - int value = 0; - - while (!isTerminated) { - char input[INPUT_LENGTH] = {}; - printf("> "); - fgets(input, INPUT_LENGTH, stdin); - - // Remove newline - if ((strlen(input) > 0) && (input[strlen(input) - 1] == '\n')) { - input[strlen(input) - 1] = '\0'; - } - - char argList[3][ARG_LENGTH] = {}; - extractArgs(input, argList); - - convertCase(argList[0]); // Convert command to lowercase - switch(commandList(argList[0])) { - case 1: // Help - printf("Display help\n"); - break; - case 2: // Create collection - createCollection(argList[1]); - break; - case 3: // Prepend to collection - value = (int) strtol(argList[2], &endPtr, 10); - prependCollection(argList[1], value); - break; - case 4: // Append to collection - value = (int) strtol(argList[2], &endPtr, 10); - appendCollection(argList[1], value); - break; - case 5: // Display collection(s) - convertCase(argList[1]); // Convert flag to lowercase - - if ((strcmp(argList[1], "--all") == 0) || (strcmp(argList[1], "-a") == 0)) { - viewDB(); - } else if ((strcmp(argList[1], "--one") == 0) || (strcmp(argList[1], "-o") == 0)) { - viewCollection(argList[2]); - } else { - printf("Incorrect syntax.\nView all collections: view [--all / -a]\nView one collection: view [--one / -o] [collection name]\n"); - } - break; - case 6: // Delete a collection - deleteCollection(argList[1]); - break; - case 0: - // Exit - isTerminated = true; - break; - default: - printf("Invalid command. Type 'help' for a list of commands.\n"); - } - } -} - -int main() { - printf("Welcome to LinkBase.\nCopyright (c) 2019 Elikem Hermon. All rights reserved.\n\nType 'help' for help.\n\n"); - prompt(); -} diff --git a/linkedList.c b/linkedList.c new file mode 100644 index 0000000..3a4769a --- /dev/null +++ b/linkedList.c @@ -0,0 +1,327 @@ +#include +#include +#include +#include "linkedList.h" + +void initList(LinkedList *list, char *name) { + // Check for initialization issues + if (list->head != NULL || list->tail != NULL || list->initialized != 0) { + exceptionHandler(ERR_INIT_LIST); + } + + list->name = name; + list->initialized = 1; +} + +int isEmpty(LinkedList *list) { + if (list->head == NULL && list->tail == NULL) { + return 1; + } else if (list->head == NULL || list->tail == NULL) { + exceptionHandler(ERR_CORRUPTED_LIST); + } + + return 0; +} + +void append(LinkedList *list, int val) { + if (list->initialized != 1) { + exceptionHandler(ERR_NO_INIT_LIST); + } + + Node *new = (Node *) malloc(sizeof(Node)); + if (new == NULL) { + exceptionHandler(ERR_MEM); + } + + new->next = NULL; + new->value = val; + + if (isEmpty(list)) { + list->head = new; + list->tail = new; + } else { + list->tail->next = new; + list->tail = new; + } +} + +void prepend(LinkedList *list, int val) { + if (list->initialized != 1) { + exceptionHandler(ERR_NO_INIT_LIST); + } + + Node *new = (Node *) malloc(sizeof(Node)); + if (new == NULL) { + exceptionHandler(ERR_MEM); + } + + new->value = val; + new->next = list->head; + + if (isEmpty(list)) { + list->head = new; + list->tail = new; + } else { + list->head = new; + } +} + +int insertIdx(LinkedList *list, int idx, int val) { + if (list->initialized != 1) { + exceptionHandler(ERR_NO_INIT_LIST); + } + + if (idx < 0) { + printf("The specified index of %d is invalid. Only positive indexes are supported.\n", idx); + return 0; + } + + Node *new = (Node *) malloc(sizeof(Node)); + new->value = val; + + if (isEmpty(list)) { + new->next = NULL; + list->head = new; + list->tail = new; + printf("The list is empty. The new node will be inserted at index 0.\n"); + return 1; + } + + // Insertion at the beginning of the linked list + if (idx == 0) { + new->next = list->head; + list->head = new; + return 1; + } + + int listIdx = 0; + Node *itr = list->head; + while ((listIdx != idx - 1) && (itr != NULL)) { + listIdx++; + itr = itr->next; + } + + if (itr == NULL) { + printf("The specified index of %d is invalid. The linked list goes up to index %d.\n", idx, listIdx - 1); + free(new); + return 0; + } else if (itr->next == NULL) { + printf("The specified index of %d is invalid. The linked list goes up to index %d.\n", idx, listIdx); + free(new); + return 0; + } + + // Insertion in the middle and at the end of the linked list + new->next = itr->next; + itr->next = new; + if (itr == list->tail) { + list->tail = new; + } + return 1; +} + +int deleteFirst(LinkedList *list) { + if (list->initialized != 1) { + exceptionHandler(ERR_NO_INIT_LIST); + } + + if (isEmpty(list)) { + printf("The list is empty, the specified node cannot be deleted.\n"); + return 0; + } + + Node *temp = list->head; + if (list->head == list->tail) { + list->head = NULL; + list->tail = NULL; + } else { + list->head = list->head->next; + } + + free(temp); + return 1; +} + +int deleteLast(LinkedList *list) { + if (list->initialized != 1) { + exceptionHandler(ERR_NO_INIT_LIST); + } + + if (isEmpty(list)) { + printf("The list is empty, the specified node cannot be deleted.\n"); + return 0; + } + + Node *temp = list->tail; + if (list->tail == list->head) { + list->head = NULL; + list->tail = NULL; + free(temp); + } else { + Node *itr = list->head; + + // Skip to the node before the tail + while (itr->next != list->tail) { + itr = itr->next; + } + + itr->next = NULL; + list->tail = itr; + free(temp); + } + + return 1; +} + +int deleteIdx(LinkedList *list, int idx) { + if (list->initialized != 1) { + exceptionHandler(ERR_NO_INIT_LIST); + } + + if (idx < 0) { + printf("The specified index of %d is invalid. Only positive indexes are supported.\n", idx); + return 0; + } + + if (isEmpty(list)) { + printf("The list is empty. There is no node to delete.\n"); + return 0; + } + + if (idx == 0) { + deleteFirst(list); + return 1; + } + + int listIdx = 0; + Node *itr = list->head; + while ((listIdx != idx - 1) && (itr != NULL)) { + listIdx++; + itr = itr->next; + } + + if (itr == NULL) { + printf("The specified index of %d is invalid. The linked list goes up to index %d.\n", idx, listIdx - 1); + return 0; + } else if (itr->next == NULL) { + printf("The specified index of %d is invalid. The linked list goes up to index %d.\n", idx, listIdx); + return 0; + } + + // Deleting in the middle and at the end of the linked list + Node *temp = itr->next; + if (itr->next == list->tail) { + list->tail = itr; + } + + itr->next = itr->next->next; + free(temp); + return 1; +} + +int count(LinkedList *list) { + if (isEmpty(list)) { + return 0; + } + + int count = 0; + Node *itr = list->head; + while (itr != NULL) { + count++; + itr = itr->next; + } + return count; +} + +void printList(LinkedList *list, char *listName) { + if (list->initialized != 1) { + exceptionHandler(ERR_NO_INIT_LIST); + } + + if (isEmpty(list)) { + printf("%s: [ ]\n", listName); + return; + } + + printf("%s: [ ", listName); + Node *iterator = list->head; + while (iterator->next != NULL) { + printf("%d, ", iterator->value); + iterator = iterator->next; + } + + printf("%d ]\n", iterator->value); +} + +void printHeading(char *heading) { + printf("++"); + for (int i = 0; i < strlen(heading); ++i) { + printf("-"); + } + printf("++\n %s \n++", heading); + for (int i = 0; i < strlen(heading); ++i) { + printf("-"); + } + printf("++\n"); +} + +void freeList(LinkedList *list) { + if (list->initialized != 1) { + exceptionHandler(ERR_NO_INIT_LIST); + } + + char heading[100]; + snprintf(heading, 100, "Cleanup Log (%s)", list->name); + printHeading(heading); + + if (isEmpty(list)) { + list->name = NULL; + printf("Nothing to clean. The list is empty.\n\n"); + return; + } + + Node *iterator = list->head; + while (iterator != list->tail) { + Node *temp = iterator; + iterator = iterator->next; + + if (temp == list->head) { + printf("List head freed (%d)\n", temp->value); + } else { + printf("List node freed (%d)\n", temp->value); + } + + free(temp); + } + + printf("List tail freed (%d)\n\n", list->tail->value); + free(list->tail); + list->head = NULL; + list->tail = NULL; + list->name = NULL; +} + +void exceptionHandler(errors err) { + switch (err) { + case ERR_MEM: + perror("Error"); + exit(EXIT_FAILURE); + + case ERR_INIT_LIST: + fprintf(stderr, "Error: The linked list could not be initialized\n"); + exit(EXIT_FAILURE); + + case ERR_NO_INIT_LIST: + fprintf(stderr, "Error: The linked list has not been initialized\n"); + exit(EXIT_FAILURE); + + case ERR_CORRUPTED_LIST: + fprintf(stderr, "Error: The linked list has been corrupted\n"); + exit(EXIT_FAILURE); + + default: + fprintf(stderr, "Fatal: Unknown Error\n"); + perror(""); + exit(EXIT_FAILURE); + } +} diff --git a/linkedList.h b/linkedList.h index 93df981..d80a316 100644 --- a/linkedList.h +++ b/linkedList.h @@ -1,169 +1,48 @@ -#include -#include -#include +#ifndef LINKED_LIST_H +#define LINKED_LIST_H +// A node of the linked list typedef struct node { struct node *next; int value; - bool empty; } Node; -typedef struct idx_node { - struct idx_node *next; - Node *entries; - char name[21]; -} indexNode; - -typedef enum { ERR_MEM, ERR_INIT, ERR_NO_INIT } errors; -void exceptionHandler(errors err) { - switch (err) { - case ERR_MEM: - perror("Error"); - exit(EXIT_FAILURE); - case ERR_INIT: - fprintf(stderr, "Error: The linked list is already initialized\n"); - break; - case ERR_NO_INIT: - fprintf(stderr, "Error: The linked list is not initialized\n"); - break; - default: - fprintf(stderr, "Fatal: Unknown Error\n"); - exit(EXIT_FAILURE); - } -} - -Node* initList(Node *listHead) { - if (listHead != NULL) { - exceptionHandler(ERR_INIT); - return NULL; - } - - // Create a new node - Node *new = (Node *)malloc(sizeof(Node)); - if (new == NULL) { - exceptionHandler(ERR_MEM); - return NULL; - } - - new->value = 0; - new->next = NULL; - new->empty = true; - listHead = new; - return listHead; -} - -Node* append(Node *listHead, int val) { - if (listHead == NULL) { - exceptionHandler(ERR_NO_INIT); - return NULL; - } - - // Create a new node - Node *new = (Node *) malloc(sizeof(Node)); - if (new == NULL) { - exceptionHandler(ERR_MEM); - return NULL; - } - - new->value = val; - new->next = NULL; - new->empty = false; - - // Find the end of the list - Node *Tail = listHead; - while (Tail->next != NULL) Tail = Tail->next; // Iterate to the end of the linked list - Tail->next = new; - return listHead; -} - -Node* prepend(Node *listHead, int val) { - // Create a new node - Node *new = (Node *) malloc(sizeof(Node)); - if (new == NULL) { - exceptionHandler(ERR_MEM); - return NULL; - } - - new->value = val; - new->next = listHead; - new->empty = false; - listHead = new; - return listHead; -} - -indexNode* prependIndex(indexNode *listHead, Node *entries, char name[]) { - // Create a new node - indexNode *new = (indexNode *) malloc(sizeof(indexNode)); - if (new == NULL) { - exceptionHandler(ERR_MEM); - return NULL; - } - - new->entries = entries; - new->next = listHead; - strcpy(new->name, name); - listHead = new; - return listHead; -} - -indexNode* deleteIndex(indexNode *listHead, char name[], bool *success) { - bool exists = false; - - if (listHead == NULL) { - exceptionHandler(ERR_NO_INIT); - return NULL; - } - - indexNode *current = listHead; - indexNode *prev = NULL; - - while(current != NULL) { - if (strcmp(current->name, name) == 0) { - exists = true; - break; - } - - if (current->next == NULL) break; - prev = current; - current = current->next; - } - - if (exists) { - if (current == listHead) { - listHead = listHead->next; - } else { - prev->next = current->next; - } - free(current); - *success = true; - return listHead; - } else { - *success = false; - return listHead; - } -} - -void printList(Node *listHead, char title[]) { - if (listHead == NULL) { - exceptionHandler(ERR_NO_INIT); - return; - } - - Node *iterator = listHead; - printf("%s: [ ", title); - - // Check for empty collections - if (iterator->empty == true) { - printf("]\n"); - return; - } - - while(iterator != NULL) { - if (iterator->next == NULL) { - printf("%d ]\n", iterator->value); - break; - } - printf("%d, ", iterator->value); - iterator = iterator->next; - } -} +// Keeps track of a linked list instance +typedef struct { + Node *head; + Node *tail; + char *name; + int initialized; +} LinkedList; + +typedef enum { + ERR_MEM, ERR_INIT_LIST, ERR_NO_INIT_LIST, ERR_CORRUPTED_LIST +} errors; + +void initList(LinkedList *list, char *name); + +int isEmpty(LinkedList *list); + +void append(LinkedList *list, int val); + +void prepend(LinkedList *list, int val); + +int insertIdx(LinkedList *list, int idx, int val); + +int deleteFirst(LinkedList *list); + +int deleteLast(LinkedList *list); + +int deleteIdx(LinkedList *list, int idx); + +int count(LinkedList *list); + +void printList(LinkedList *list, char *listName); + +void printHeading(char *heading); + +void freeList(LinkedList *list); + +void exceptionHandler(errors err); + +#endif //LINKED_LIST_H diff --git a/main.c b/main.c new file mode 100644 index 0000000..5f478ae --- /dev/null +++ b/main.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include +#include "linkedList.h" + +#define LIST_NAME_MAX 100 +#define PROMPT_MAX 61 +#define NUM_PROMPT_ARGS 61 +#define PROMPT_ARG_LEN 21 // 20 chars for each argument + +typedef enum { + HELP, PRINT_LIST, COUNT, APPEND, PREPEND, INSERT_IDX, DEL_FIRST, DEL_LAST, DEL_IDX, NO_CMD, INVALID_CMD, QUIT +} cmdType; + +void extractArgs(char input[], char argList[][PROMPT_ARG_LEN]) { + int argIndex = 0; + + char *ptr = NULL; + ptr = strtok(input, " "); + if (ptr == NULL) return; + + strncpy(argList[argIndex], ptr, PROMPT_ARG_LEN); + argList[argIndex][PROMPT_ARG_LEN - 1] = '\0'; // Ensure the output from strncpy is null terminated + argIndex++; + while(argIndex < 3) { + ptr = strtok(NULL, " "); + if (ptr == NULL) break; + strncpy(argList[argIndex], ptr, PROMPT_ARG_LEN); + argList[argIndex][PROMPT_ARG_LEN - 1] = '\0'; + argIndex++; + } +} + +void removeNewline(char in[]) { + if ((strlen(in) > 0) && (in[strlen(in) - 1] == '\n')) { + in[strlen(in) - 1] = '\0'; + } +} + +void strToLower(char in[]) { + for (char *p = in; *p; ++p) { + *p = tolower(*p); + } +} + +/* + * Command List + * ------------ + * 1) help [Shows help menu] + * 1) view [printList] + * 2) count [count] + * 3) append (value) [append] + * 4) prepend (value) [prepend] + * 5) insert (index) (value) [insertIdx] + * 6) del_first [deleteFirst] + * 7) del_last [deleteLast] + * 8) del_idx [deleteIdx] + */ +cmdType cmdIndex(char cmd[]) { + if (strcmp(cmd, "help") == 0) { + return HELP; + } else if (strcmp(cmd, "view") == 0) { + return PRINT_LIST; + } else if (strcmp(cmd, "count") == 0) { + return COUNT; + } else if (strcmp(cmd, "append") == 0) { + return APPEND; + } else if (strcmp(cmd, "prepend") == 0) { + return PREPEND; + } else if (strcmp(cmd, "insert") == 0) { + return INSERT_IDX; + } else if (strcmp(cmd, "del_first") == 0) { + return DEL_FIRST; + } else if (strcmp(cmd, "del_last") == 0) { + return DEL_LAST; + } else if (strcmp(cmd, "del_idx") == 0) { + return DEL_IDX; + } else if (strcmp(cmd, "exit") == 0 || strcmp(cmd, "quit") == 0) { + return QUIT; + } else if (strcmp(cmd, "") == 0) { + return NO_CMD; + } else { + return INVALID_CMD; + } +} + +void prompt(LinkedList *list) { + printf("\nInteract with list '%s' using the prompt below.\nRemember, you can always type 'help' for some assistance šŸ˜‰.\n\n", list->name); + + int promptLoop = 1; + int value; + int idx; + char *ptr = NULL; + + while (promptLoop) { + char promptIn[PROMPT_MAX] = {}; + printf("> "); + fgets(promptIn, PROMPT_MAX, stdin); + removeNewline(promptIn); + + char argList[NUM_PROMPT_ARGS][PROMPT_ARG_LEN] = {}; + extractArgs(promptIn, argList); + strToLower(argList[0]); + + switch (cmdIndex(argList[0])) { + case HELP: + printf("LinkBase v0.2.0\nāš ļø Note: All indexes and values must be integers\n\n"); + printf("%-20s\t%-20s\n", "view", "prints the contents of the list"); + printf("%-20s\t%-20s\n", "count", "counts the contents of the list"); + printf("%-20s\t%-20s\n", "append [value]", "appends a value to the list"); + printf("%-20s\t%-20s\n", "prepend [value]", "prepends a value to the list"); + printf("%-20s\t%-20s\n", "insert [index] [value]", "inserts a value into the list at a specified index"); + printf("%-20s\t%-20s\n", "del_first", "deletes the first value of the list"); + printf("%-20s\t%-20s\n", "del_last", "deletes the last value of the list"); + printf("%-20s\t%-20s\n", "del_idx [index]", "deletes a value at a specified index"); + printf("%-20s\t%-20s\n", "exit", "Ends the current session"); + printf("%-20s\t%-20s\n\n", "quit", "Ends the current session"); + break; + case PRINT_LIST: + printList(list, list->name); + break; + case COUNT: + printf("List '%s' has %d entries.\n", list->name, count(list)); + break; + case APPEND: + errno = 0; + value = (int) strtol(argList[1], &ptr, 10); + if (errno != 0) { + printf("Invalid argument. The value supplied must be an integer.\n"); + break; + } + + append(list, value); + printf("Value (%d) was successfully appended.\n", value); + break; + case PREPEND: + errno = 0; + value = (int) strtol(argList[1], &ptr, 10); + if (errno != 0) { + printf("Invalid argument. The value supplied must be an integer.\n"); + break; + } + + prepend(list, value); + printf("Value (%d) was successfully prepended\n", value); + break; + case INSERT_IDX: + errno = 0; + idx = (int) strtol(argList[1], &ptr, 10); + value = (int) strtol(argList[2], &ptr, 10); + if (errno != 0) { + printf("Incorrect syntax.\nUsage: insert [index] [value]\nNote: The index and value must be integers.\n\n"); + break; + } + + if (insertIdx(list, idx, value)) { + printf("Value (%d) was successfully inserted.\n", value); + } + break; + case DEL_FIRST: + if (deleteFirst(list)) { + printf("The first value has been deleted.\n"); + } + break; + case DEL_LAST: + if (deleteLast(list)) { + printf("The last value has been deleted.\n"); + } + break; + case DEL_IDX: + errno = 0; + idx = (int) strtol(argList[1], &ptr, 10); + if (errno != 0) { + printf("Incorrect syntax.\nUsage: del_idx [index]\nNote: The index must be an integer.\n\n"); + break; + } + + if (deleteIdx(list, idx)) { + printf("The value at index (%d) has been deleted.\n", idx); + } + break; + case NO_CMD: + break; + case INVALID_CMD: + printf("Invalid command šŸ˜–. Type 'help' to view the list of available commands.\n\n"); + break; + case QUIT: + printf("Stay safe šŸ¤™\n\n"); + promptLoop = 0; + break; + default: + printf("Invalid command šŸ˜–. Type 'help' to view the list of available commands.\n\n"); + break; + } + } +} + +void initialize() { + char listName[LIST_NAME_MAX] = {}; + while (1) { + printf("What should we call your list? šŸ¤”: "); + fgets(listName, LIST_NAME_MAX, stdin); + removeNewline(listName); + + if (strlen(listName) >= 3) { + break; + } + + printf("The name of the list must be at least 3 characters.\n\n"); + } + + LinkedList list = { + .head = NULL, + .tail = NULL, + .name = "", + .initialized = 0 + }; + initList(&list, listName); + prompt(&list); + freeList(&list); +} + +int main() { + printf("Welcome to LinkBase šŸ’¾.\nCopyright (c) 2020 Elikem Hermon. All rights reserved.\n\n"); + initialize(); + return 0; +} diff --git a/test.c b/test.c new file mode 100644 index 0000000..0ccb9c4 --- /dev/null +++ b/test.c @@ -0,0 +1,92 @@ +#include +#include "linkedList.h" + +#define DISPLAY_NAME_MAX 100 + +typedef enum { + INIT, APPEND, PREPEND, INSERT_IDX, DEL_FIRST, DEL_LAST, DEL_IDX +} testCaseType; + +void testCase(testCaseType type, LinkedList *list, char displayName[], const int *val, const int *idx) { + switch (type) { + case INIT: + initList(list, "testList"); + snprintf(displayName, DISPLAY_NAME_MAX, "%s (initial)", list->name); + break; + case APPEND: + if (val == NULL) return; + append(list, *val); + snprintf(displayName, DISPLAY_NAME_MAX, "%s (append)", list->name); + break; + case PREPEND: + if (val == NULL) return; + prepend(list, *val); + snprintf(displayName, DISPLAY_NAME_MAX, "%s (prepend)", list->name); + break; + case INSERT_IDX: + if (val == NULL || idx == NULL) return; + insertIdx(list, *idx, *val); + snprintf(displayName, DISPLAY_NAME_MAX, "%s (insert at index %d)", list->name, *idx); + break; + case DEL_FIRST: + deleteFirst(list); + snprintf(displayName, DISPLAY_NAME_MAX, "%s (delete first)", list->name); + break; + case DEL_LAST: + deleteLast(list); + snprintf(displayName, DISPLAY_NAME_MAX, "%s (delete last)", list->name); + break; + case DEL_IDX: + if (idx == NULL) return; + deleteIdx(list, *idx); + snprintf(displayName, DISPLAY_NAME_MAX, "%s (delete at index %d)", list->name, *idx); + break; + default: + return; + } + + printList(list, displayName); + printf("%s length: %d\n\n", list->name, count(list)); +} + +int main() { + LinkedList list = { + .head = NULL, + .tail = NULL, + .name = "", + .initialized = 0 + }; + + char displayName[DISPLAY_NAME_MAX]; + int val = 0; + int idx = 0; + + printHeading("Running Test Cases"); + testCase(INIT, &list, displayName, NULL, NULL); + testCase(APPEND, &list, displayName, &val, NULL); + val++; + testCase(PREPEND, &list, displayName, &val, NULL); + val++; + idx++; + testCase(INSERT_IDX, &list, displayName, &val, &idx); + testCase(DEL_FIRST, &list, displayName, NULL, NULL); + testCase(DEL_LAST, &list, displayName, NULL, NULL); + testCase(DEL_IDX, &list, displayName, NULL, &idx); + idx = 0; + testCase(DEL_IDX, &list, displayName, NULL, &idx); + testCase(PREPEND, &list, displayName, &val, NULL); + testCase(DEL_FIRST, &list, displayName, NULL, NULL); + testCase(DEL_LAST, &list, displayName, NULL, NULL); + idx = 10; + testCase(INSERT_IDX, &list, displayName, &val, &idx); + idx = 1; + val = 1; + testCase(INSERT_IDX, &list, displayName, &val, &idx); + val = 3; + testCase(PREPEND, &list, displayName, &val, NULL); + val = 0; + testCase(APPEND, &list, displayName, &val, NULL); + + freeList(&list); + return 0; +}