From 3ebb9dc8dfb2e2e97a15582d3360b58ec4d087f2 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Fri, 21 Nov 2025 17:27:16 -0800 Subject: [PATCH] lab09 initial commit BEST PRACTICE --- lab09/Makefile | 60 +++++++ lab09/error.txt | 3 + lab09/input1.txt | 3 + lab09/input2.txt | 3 + lab09/input3.txt | 3 + lab09/input4.txt | 3 + lab09/input5.txt | 3 + lab09/lab9.c | 413 +++++++++++++++++++++++++++++++++++++++++++++++ lab09/output.txt | 1 + lab09/ref1.txt | 1 + lab09/ref2.txt | 1 + lab09/ref3.txt | 1 + lab09/ref4.txt | 1 + lab09/ref5.txt | 1 + 14 files changed, 497 insertions(+) create mode 100644 lab09/Makefile create mode 100644 lab09/error.txt create mode 100644 lab09/input1.txt create mode 100644 lab09/input2.txt create mode 100644 lab09/input3.txt create mode 100644 lab09/input4.txt create mode 100644 lab09/input5.txt create mode 100644 lab09/lab9.c create mode 100644 lab09/output.txt create mode 100644 lab09/ref1.txt create mode 100644 lab09/ref2.txt create mode 100644 lab09/ref3.txt create mode 100644 lab09/ref4.txt create mode 100644 lab09/ref5.txt diff --git a/lab09/Makefile b/lab09/Makefile new file mode 100644 index 0000000..a0eb9ce --- /dev/null +++ b/lab09/Makefile @@ -0,0 +1,60 @@ +# Compiler and flags +CC = gcc +CFLAGS = -Wall -std=c11 + +#Input file +INPUT = input5.txt +OUTPUT = output.txt +REF = ref.txt +# Source file +SRCS = lab9.c +# Output +TARGET = lab9.out + +# Default target +all: $(TARGET) + +# Rule to build the executable +$(TARGET): $(SRCS) + $(CC) $(CFLAGS) $(SRCS) -o $(TARGET) + +convert_input: $(INPUT) + @if [ -s $(INPUT) ] && file $(INPUT) | grep -q 'CRLF line terminators' ; then \ + { cat $(INPUT) | dos2unix; } | tee $(INPUT) >/dev/null; \ + fi + @if [ -s $(INPUT) ] && tail -c1 $(INPUT) | grep -q . ; then \ + echo >> $(INPUT); \ + tr -d '\r' < $(INPUT) > temp_file && mv temp_file $(INPUT); \ + fi + +convert_output: $(OUTPUT) + @if [ -s $(OUTPUT) ] && file $(OUTPUT) | grep -q 'CRLF line terminators' ; then \ + { cat $(OUTPUT) | dos2unix; } | tee $(OUTPUT) >/dev/null; \ + fi + @if [ -s $(OUTPUT) ] && tail -c1 $(OUTPUT) | grep -q . ; then \ + echo >> $(OUTPUT); \ + tr -d '\r' < $(OUTPUT) > temp_file && mv temp_file $(OUTPUT); \ + fi + +check: $(OUTPUT) $(REF) + @if [ -s $(REF) ] && file $(REF) | grep -q 'CRLF line terminators' ; then \ + { cat $(REF) | dos2unix; } | tee $(REF) >/dev/null; \ + fi + @if [ -s $(REF) ] && tail -c1 $(REF) | grep -q . ; then \ + echo >> $(REF); \ + tr -d '\r' < $(REF) > temp_file && mv temp_file $(REF); \ + fi + @diff -q $(OUTPUT) $(REF) > /dev/null; \ + if [ $$? -eq 0 ]; then \ + echo "Pass"; \ + else \ + echo "Fail"; \ + fi + +# Rule to run the program +run: $(TARGET) + ./$(TARGET) $(INPUT) $(OUTPUT) + +# Rule to clean generated files +clean: + rm -f $(TARGET) diff --git a/lab09/error.txt b/lab09/error.txt new file mode 100644 index 0000000..8bcb9b2 --- /dev/null +++ b/lab09/error.txt @@ -0,0 +1,3 @@ +1 +101,412,219,732,516,813,205,604,317,945,629,826,347,158,739,33767,501 +E diff --git a/lab09/input1.txt b/lab09/input1.txt new file mode 100644 index 0000000..b9b3b89 --- /dev/null +++ b/lab09/input1.txt @@ -0,0 +1,3 @@ +1 +101,412,219,732,516,813,205,604,317,945,629,826,347,158,739,32767,501 +E diff --git a/lab09/input2.txt b/lab09/input2.txt new file mode 100644 index 0000000..e964c72 --- /dev/null +++ b/lab09/input2.txt @@ -0,0 +1,3 @@ +2 +50,25,80,35,70,15,60,45,90,95,85,40,75,65,32768,55,100 +E diff --git a/lab09/input3.txt b/lab09/input3.txt new file mode 100644 index 0000000..b4f4b52 --- /dev/null +++ b/lab09/input3.txt @@ -0,0 +1,3 @@ +3 +3.5,7.2,1.8,9.6,4.3,2.1,5.7,8.9,6.4,10.2,12.6,11.1,14.3,15.7,13.2,16.8 +E diff --git a/lab09/input4.txt b/lab09/input4.txt new file mode 100644 index 0000000..a814830 --- /dev/null +++ b/lab09/input4.txt @@ -0,0 +1,3 @@ +4 +d,b,a,c,e,g,f,h,q,o,r,m,n,s,t,u +E diff --git a/lab09/input5.txt b/lab09/input5.txt new file mode 100644 index 0000000..190bed8 --- /dev/null +++ b/lab09/input5.txt @@ -0,0 +1,3 @@ +5 +apple,orange,banana,kiwi,grape,pear,lemon,peach,mango,pineapple,strawberry,watermelon,blueberry,raspberry,blackberry,cherry +E diff --git a/lab09/lab9.c b/lab09/lab9.c new file mode 100644 index 0000000..7a05619 --- /dev/null +++ b/lab09/lab9.c @@ -0,0 +1,413 @@ +#include +#include +#include +#include + +#define EXPECTED_ARGUMENTS 3 +#define PROGRAM_FILE 0 +#define INPUT_FILE 1 +#define OUTPUT_FILE 2 +#define EXPECTED_INPUT 1 + +#define SHORT 1 +#define INTEGER 2 +#define FLOAT 3 +#define CHAR 4 +#define STRING 5 + +#define MAX_STRING_LEN 256 +#define READING 1 +#define IS_EQUAL 0 +#define INDEX_OFFSET 1 +#define BASE_TEN 10 +#define DOUBLE 2 + +typedef struct NODE +{ + void *data; + struct NODE *next; +} NODE; + +void insertNode(NODE **head, void *data) +{ + NODE *node; + + node = malloc(sizeof(NODE)); + + node->data = data; + node->next = *head; + + *head = node; +} + +void freeList(NODE *head) +{ + NODE *temp; + + while (head != NULL) + { + temp = head; + head = head->next; + + free(temp->data); + free(temp); + } +} + +NODE* readFile(char *filepath, int *type, int *count) +{ + FILE *file; + + file = fopen(filepath, "r"); + + if (file == NULL) + { + // printf("Failed to read file %s\n", filepath); + return NULL; + } + + if (fscanf(file, "%d", type) != EXPECTED_INPUT) + { + // printf("Error: failed to read type from file\n"); + fclose(file); + return NULL; + } + + int ch; // skip new line characters and EOF + while ((ch = fgetc(file)) != '\n' && ch != EOF) {} + + NODE *head; + char token[MAX_STRING_LEN]; + + head = NULL; + *count = 0; + + while (READING) + { + // read till comma or new line + if (fscanf(file, " %255[^,\n]", token) != EXPECTED_INPUT) + { + break; + } + + // end of file + if (strcmp(token, "E") == IS_EQUAL) + { + break; + } + + void *data; + + data = NULL; + + switch (*type) + { + case SHORT: + { + long value; + + value = strtol(token, NULL, BASE_TEN); + + if (value < SHRT_MIN || value > SHRT_MAX) + { + // printf("Error: %ld is out of range for SHORT type (%d to %d)\n", + // value, SHRT_MIN, SHRT_MAX); + + fclose(file); + freeList(head); + return NULL; + } + + data = malloc(sizeof(short)); + *(short *)data = (short)value; + break; + } + + + case INTEGER: + { + data = malloc(sizeof(int)); + *(int *)data = atoi(token); + break; + } + + case FLOAT: + { + data = malloc(sizeof(float)); + *(float *)data = atof(token); + break; + } + + case CHAR: + { + data = malloc(sizeof(char)); + *(char *)data = token[0]; + break; + } + + case STRING: + { + data = malloc(MAX_STRING_LEN); + strncpy((char *)data, token, MAX_STRING_LEN - INDEX_OFFSET); + ((char *)data)[MAX_STRING_LEN - INDEX_OFFSET] = '\0'; + break; + } + + default: + // printf("Error: Bad input type\n"); + fclose(file); + return NULL; + } + + insertNode(&head, data); + (*count)++; + + ch = fgetc(file); + if (ch == EOF) + { + break; + } + + if (ch == '\n') + { + continue; + } + } + + fclose(file); + return head; +} + +void printList(NODE *head, int type) +{ + while (head != NULL) + { + switch (type) + { + case SHORT: printf("%hd -> ", *(short *)head->data); break; + case INTEGER: printf("%d -> ", *(int *) head->data); break; + case FLOAT: printf("%.1f -> ", *(float *)head->data); break; + case CHAR: printf("%c -> ", *(char *) head->data); break; + case STRING: printf("%s -> ", (char *) head->data); break; + } + + head = head->next; + } + + printf("null\n"); +} + +int compare(void *a, void *b, int type) +{ + switch (type) + { + case SHORT: + case INTEGER: + { + int va; + int vb; + + va = *(int *)a; + vb = *(int *)b; + + return (va > vb) - (va < vb); + } + + case FLOAT: + { + int va; + int vb; + + va = *(float *)a; + vb = *(float *)b; + + return (va > vb) - (va < vb); + } + + case CHAR: + { + char va; + char vb; + + va = *(char *)a; + vb = *(char *)b; + + return (va > vb) - (va < vb); + } + + case STRING: + return strcmp((char *)a, (char *)b); + } + + return 0; +} + +NODE* split(NODE *head) +{ + NODE *fast; + NODE *slow; + NODE *second; + + slow = head; + fast = head; + + while (fast != NULL && fast->next != NULL) + { + fast = fast->next->next; + if (fast != NULL) + { + slow = slow->next; + } + } + + second = slow->next; + slow->next = NULL; + + return second; +} + +NODE* merge(NODE *first, NODE *second, int type) +{ + if (first == NULL) + { + return second; + } + if (second == NULL) + { + return first; + } + + if (compare(first->data, second->data, type) <= IS_EQUAL) + { + first->next = merge(first->next, second, type); + return first; + } + else + { + second->next = merge(first, second->next, type); + return second; + } +} + +NODE* mergeSort(NODE *head, int type) +{ + if (head == NULL || head->next == NULL) + { + return head; + } + + NODE *second; + + second = split(head); + head = mergeSort(head, type); + second = mergeSort(second, type); + + return merge(head, second, type); +} + +void writeOutput(char *filePath, char *data) +{ + FILE *file; + + file = fopen(filePath, "w"); + + fputs(data, file); + fputs("\n", file); + + fclose(file); +} + +char* toString(NODE *head, int type) +{ + size_t capacity; + char *result; + + capacity = MAX_STRING_LEN; + result = malloc(capacity); + result[0] = '\0'; + + char temp[MAX_STRING_LEN]; + + while (head != NULL) + { + switch (type) + { + case SHORT: + snprintf(temp, sizeof(temp), "%hd", *(short *)head->data); + break; + + case INTEGER: + snprintf(temp, sizeof(temp), "%d", *(int *)head->data); + break; + + case FLOAT: + snprintf(temp, sizeof(temp), "%.1f", *(float *)head->data); + break; + + case CHAR: + snprintf(temp, sizeof(temp), "%c", *(char *)head->data); + break; + + case STRING: + snprintf(temp, sizeof(temp), "%s", (char *)head->data); + break; + } + + while (strlen(result) + strlen(temp) + 2 >= capacity) + { + capacity *= DOUBLE; + result = realloc(result, capacity); + } + + strcat(result, temp); + + if (head->next != NULL) + strcat(result, ","); + + head = head->next; + } + + return result; +} + +int main(int argc, char *argv[]) +{ + if (argc < EXPECTED_ARGUMENTS) + { + printf("Usage: %s \n", argv[PROGRAM_FILE]); + return 1; + } + + NODE *head; + int type; + int count; + + head = readFile(argv[INPUT_FILE], &type, &count); + + if (head == NULL) + { + writeOutput(argv[OUTPUT_FILE], "Error"); + // printf("Failed to read list.\n"); + return 1; + } + + printf("\nOriginal:\n"); + printList(head, type); + printf("\n"); + + head = mergeSort(head, type); + + char *listString; + + listString = toString(head, type); + + writeOutput(argv[OUTPUT_FILE], listString); + + printf("Sorted:\n"); + printList(head, type); + printf("\n"); + + freeList(head); + + return 0; +} diff --git a/lab09/output.txt b/lab09/output.txt new file mode 100644 index 0000000..a210e76 --- /dev/null +++ b/lab09/output.txt @@ -0,0 +1 @@ +apple,banana,blackberry,blueberry,cherry,grape,kiwi,lemon,mango,orange,peach,pear,pineapple,raspberry,strawberry,watermelon diff --git a/lab09/ref1.txt b/lab09/ref1.txt new file mode 100644 index 0000000..776e6d6 --- /dev/null +++ b/lab09/ref1.txt @@ -0,0 +1 @@ +101,158,205,219,317,347,412,501,516,604,629,732,739,813,826,945,32767 diff --git a/lab09/ref2.txt b/lab09/ref2.txt new file mode 100644 index 0000000..27ca029 --- /dev/null +++ b/lab09/ref2.txt @@ -0,0 +1 @@ +15,25,35,40,45,50,55,60,65,70,75,80,85,90,95,100,32768 diff --git a/lab09/ref3.txt b/lab09/ref3.txt new file mode 100644 index 0000000..83c2ee6 --- /dev/null +++ b/lab09/ref3.txt @@ -0,0 +1 @@ +1.8,2.1,3.5,4.3,5.7,6.4,7.2,8.9,9.6,10.2,11.1,12.6,13.2,14.3,15.7,16.8 diff --git a/lab09/ref4.txt b/lab09/ref4.txt new file mode 100644 index 0000000..901bcce --- /dev/null +++ b/lab09/ref4.txt @@ -0,0 +1 @@ +a,b,c,d,e,f,g,h,m,n,o,q,r,s,t,u diff --git a/lab09/ref5.txt b/lab09/ref5.txt new file mode 100644 index 0000000..a210e76 --- /dev/null +++ b/lab09/ref5.txt @@ -0,0 +1 @@ +apple,banana,blackberry,blueberry,cherry,grape,kiwi,lemon,mango,orange,peach,pear,pineapple,raspberry,strawberry,watermelon