416 lines
7.7 KiB
C
416 lines
7.7 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#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 <input_file> <output_file>\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;
|
|
}
|