#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 READING 1 #define ERROR_CODE 1 #define OK_CODE 0 #define MAX_STRING_LEN 256 #define SCAN_MAX_LEN 255 #define SCAN_FORMAT_LEN 16 #define IS_EQUAL 0 #define INDEX_OFFSET 1 #define BASE_TEN 10 #define TYPE_SHORT 1 #define TYPE_INTEGER 2 #define TYPE_FLOAT 3 #define TYPE_CHAR 4 #define TYPE_STRING 5 #define NEWLINE '\n' #define VALUE_SEPARATOR ',' #define NULL_TERMINATOR '\0' #define SENTINEL_STRING "E" char A_NUMBER[] = "A01385066"; 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); } } int compare(void *a, void *b, int type) { if (type == TYPE_SHORT) { short va; short vb; va = *(short *)a; vb = *(short *)b; return (va > vb) - (va < vb); } if (type == TYPE_INTEGER) { int va; int vb; va = *(int *)a; vb = *(int *)b; return (va > vb) - (va < vb); } if (type == TYPE_FLOAT) { float va; float vb; va = *(float *)a; vb = *(float *)b; return (va > vb) - (va < vb); } if (type == TYPE_CHAR) { char va; char vb; va = *(char *)a; vb = *(char *)b; return (va > vb) - (va < vb); } return strcmp((char *)a, (char *)b); } NODE* split(NODE *head) { NODE *fast; NODE *slow; NODE *second; fast = head; slow = 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; } second->next = merge(first, second->next, type); return second; } NODE* mergeSort(NODE *head, int type) { NODE *second; if (head == NULL || head->next == NULL) { return head; } second = split(head); head = mergeSort(head, type); second = mergeSort(second, type); return merge(head, second, type); } NODE* readFile(char *filepath, int *type, int *count) { FILE *file; NODE *head; int ch; size_t size; file = fopen(filepath, "r"); if (file == NULL) { return NULL; } if (fscanf(file, "%d", type) != EXPECTED_INPUT) { fclose(file); return NULL; } ch = fgetc(file); while (ch != NEWLINE && ch != EOF) { ch = fgetc(file); } head = NULL; *count = 0; size = MAX_STRING_LEN; if (*type == TYPE_SHORT) { size = sizeof(short); } else if (*type == TYPE_INTEGER) { size = sizeof(int); } else if (*type == TYPE_FLOAT) { size = sizeof(float); } else if (*type == TYPE_CHAR) { size = sizeof(char); } while (READING) { char buffer[MAX_STRING_LEN]; char scanFormat[SCAN_FORMAT_LEN]; void *data; char *end; long longValue; float floatValue; int scanResult; data = malloc(size); if (data == NULL) { fclose(file); freeList(head); return NULL; } scanResult = snprintf(scanFormat, SCAN_FORMAT_LEN, "%%%d[^,\n]", SCAN_MAX_LEN); if (scanResult < 0) { free(data); fclose(file); freeList(head); return NULL; } if (fscanf(file, scanFormat, buffer) != EXPECTED_INPUT) { free(data); break; } if (strcmp(buffer, SENTINEL_STRING) == IS_EQUAL) { free(data); break; } if (*type == TYPE_SHORT) { longValue = strtol(buffer, &end, BASE_TEN); if (*end != NULL_TERMINATOR || longValue < SHRT_MIN || longValue > SHRT_MAX) { free(data); fclose(file); freeList(head); return NULL; } *(short *)data = (short)longValue; } else if (*type == TYPE_INTEGER) { longValue = strtol(buffer, &end, BASE_TEN); if (*end != NULL_TERMINATOR || longValue < INT_MIN || longValue > INT_MAX) { free(data); fclose(file); freeList(head); return NULL; } *(int *)data = (int)longValue; } else if (*type == TYPE_FLOAT) { floatValue = strtof(buffer, &end); if (*end != NULL_TERMINATOR) { free(data); fclose(file); freeList(head); return NULL; } *(float *)data = floatValue; } else if (*type == TYPE_CHAR) { if (strlen(buffer) != INDEX_OFFSET) { free(data); fclose(file); freeList(head); return NULL; } *(char *)data = buffer[0]; } else { strncpy((char *)data, buffer, MAX_STRING_LEN); ((char *)data)[MAX_STRING_LEN - INDEX_OFFSET] = NULL_TERMINATOR; } insertNode(&head, data); (*count)++; ch = fgetc(file); if (ch == EOF) { break; } if (ch == NEWLINE) { continue; } } fclose(file); return head; } void printValue(FILE *file, void *data, int type) { if (type == TYPE_SHORT) { fprintf(file, "%hd", *(short *)data); return; } if (type == TYPE_INTEGER) { fprintf(file, "%d", *(int *)data); return; } if (type == TYPE_FLOAT) { fprintf(file, "%.1f", *(float *)data); return; } if (type == TYPE_CHAR) { fprintf(file, "%c", *(char *)data); return; } fprintf(file, "%s", (char *)data); } void writeOutput(char *filepath, NODE *head, int type, int isError) { FILE *file; file = fopen(filepath, "w"); if (file == NULL) { return; } if (isError == ERROR_CODE) { fputs("Error\n", file); fclose(file); return; } while (head != NULL) { printValue(file, head->data, type); if (head->next != NULL) { fputc(VALUE_SEPARATOR, file); } head = head->next; } fputc(NEWLINE, file); fclose(file); } int main(int argc, char *argv[]) { NODE *head; int type; int count; if (argc < EXPECTED_ARGUMENTS) { printf("Usage: %s \n", argv[PROGRAM_FILE]); return 1; } head = readFile(argv[INPUT_FILE], &type, &count); if (head == NULL) { writeOutput(argv[OUTPUT_FILE], head, type, ERROR_CODE); return 1; } head = mergeSort(head, type); writeOutput(argv[OUTPUT_FILE], head, type, OK_CODE); freeList(head); return 0; }