cs240/hw/hw12Old/miniDB.c
2018-10-15 17:20:57 -04:00

448 lines
11 KiB
C

#include "miniDB.h"
Movie* head = NULL;
int size = 0;
int main(int argc, char** argv) {
if (argc < 4) {
printf("Usage: miniDB <database> <commands> <output>\n");
} else {
if (load(argv[1]) != 0) {
printf("Error while loading database from '%s'.\n", argv[1]);
return 2;
}
if (read(argv[2], argv[3]) != 0) {
printf("Error while reading commands from '%s'.\n", argv[2]);
return 3;
}
if (save(argv[1]) != 0) {
printf("Error while saving database to '%s'.\n", argv[1]);
return 4;
}
}
return 0;
}
int read(char* filename, char* fileOut) {
if (filename == NULL) {
return 1;
}
FILE* file = fopen(filename, "r");
if (file == NULL)
return 2;
FILE* output = fopen(fileOut, "w"); // If appending, switch to "a".
if (output == NULL)
return 3;
int length = 512*3;
char* buffer = (char *) malloc(sizeof(char) * length); //[length];
char* _buffer = buffer;
while (fgets(buffer, length, file) != NULL && strcmp(buffer, "") != 0) {
printf("Command read: %s", buffer); // Buffer has newline.
char* tokens[5];
char* token;
int i = 0;
while ((token = strsep(&buffer, ",")) != NULL) { // Inline hax.
tokens[i] = strdup(token); // creates a duplicate.
//trimString(tokens[i]);
i++;
}
/*if (tokens[0] == NULL) { // Try without the space!
i = 0;
while ((token = strsep(&buffer, ",")) != NULL) {
tokens[i] = strdup(token);
i++;
}
}*/
if (strcmp(tokens[0], "ADD") == 0) {
if (add(tokens[1], tokens[2], tokens[3], atoi(tokens[4])) != 0)
return 6;
} else if (strcmp(tokens[0], "LOOKUP") == 0) {
if (lookup(tokens[1], tokens[2], output) != 0)
return 6;
} else if (strcmp(tokens[0], "DISPLAY") == 0) {
if (display(tokens[1], atoi(tokens[2]), atoi(tokens[3]), output) != 0)
return 6;
} else if (strcmp(tokens[0], "EDIT") == 0) {
if (edit(atoi(tokens[1]), tokens[2], tokens[3]) != 0)
return 6;
} else if (strcmp(tokens[0], "REMOVE") == 0) {
if (removeId(atoi(tokens[1]) != 0))
return 6;
}
// Free from strsep and strdup.
for (i = 0; i < 5; i++) {
if (tokens[i] != NULL) {
free(tokens[i]);
tokens[i] = NULL;
}
}
buffer = _buffer; // Realign the buffer. //(char *) malloc(sizeof(char) * length);
}
printf("End of commands.\n");
if (fclose(file) != 0)
return 7;
if (fclose(output) != 0)
return 8;
return 0;
}
int load(char* filename) {
if (filename == NULL) {
return 1;
}
FILE* file = fopen(filename, "r");
if (file == NULL)
return 2;
int length = 512*3; // HOLD ALL THE CHARS!
char* buffer = (char *) malloc(sizeof(char) * length); //[length];
char* _buffer = buffer;
while (fgets(buffer, length, file) != NULL && strcmp(buffer, "") != 0) {
printf("Line read: %s", buffer); // buffer contains newline.
char* tokens[4];
char* token;
int i = 0;
while ((token = strsep(&buffer, ",")) != NULL) { // Inline hax.
tokens[i] = strdup(token);
//trimString(tokens[i]);
i++;
}
/*if (tokens[0] == NULL) { // Try without the space!
i = 0;
while ((token = strsep(&buffer, ",")) != NULL) {
tokens[i] = strdup(token);
i++;
}
}*/
if (add(tokens[0], tokens[1], tokens[2], atoi(tokens[3])) != 0)
return 6;
for (i = 0; i < 4; i++) {
if (tokens[i] != NULL) {
free(tokens[i]);
tokens[i] = NULL;
}
}
buffer = _buffer;//buffer = (char *) malloc(sizeof(char) * length);
}
printf("End of file.\n");
if (fclose(file) != 0) {
return 4;
}
return 0;
}
int save(char* filename) {
if (filename == NULL) {
return 1;
}
FILE* file = fopen(filename, "w");
if (file == NULL)
return 2;
Movie* target = head;
while (target != NULL) {
fprintf(file, "%s, %s, %s, %d\n", target->title, target->date, target->director, target->id);
if (target->next != NULL)
target = target->next;
}
if (fclose(file) != 0) {
return 3;
}
return 0;
}
Movie* get(int id) {
if (head == NULL) {
return NULL;
}
Movie* target = head;
while (target->id != id) {
if (target->next != NULL) {
target = target->next;
} else
return NULL;
}
return target;
}
int add(char* title, char* date, char* director, int id) {
if (title == NULL || date == NULL || director == NULL)
return 1;
Movie* mov = (Movie *) malloc(sizeof(Movie));
if (mov == NULL)
return 2;
if (head == NULL) {
head = mov;
} else {
Movie* target = head;
while (target->next != NULL) {
target = target->next;
}
target->next = mov;
mov->next = NULL;
}
size++;
mov->title = strdup(title);
mov->date = strdup(date);
mov->director = strdup(director);
mov->id = id;
return 0;
}
int edit(int id, char* feature, char* data) {
if (feature == NULL || data == NULL)
return 1;
Movie* mov = get(id);
if (mov == NULL)
return 2;
if (strcmp(feature, "ID") == 0) {
mov->id = atoi(data);
} else if (strcmp(feature, "TITLE") == 0) {
free(mov->title);
mov->title = strdup(data);
} else if (strcmp(feature, "DATE") == 0) {
free(mov->date);
mov->date = strdup(data);
} else if (strcmp(feature, "DIRECTOR") == 0) {
free(mov->director);
mov->director = strdup(data);
} else {
return 3;
}
return 0;
}
int removeId(int id) {
if (head == NULL) {
return 1;
}
Movie* prev = NULL;
Movie* target = head;
while (target->id != id) {
if (target->next != NULL) {
prev = target;
target = target->next;
} else
return 2;
}
if (prev == NULL && target != NULL) {
head = target->next; // If next is NULL, that's okay.
} else {
prev->next = target->next; // Again, a NULL next is okay.
}
size--;
free(target->title);
free(target->date);
free(target->director);
target->title = NULL;
target->date = NULL;
target->director = NULL;
free(target);
target = NULL;
return 0;
}
int lookup(char* feature, char* data, FILE* out) {
if (feature == NULL || data == NULL || head == NULL) {
return 1;
}
printf("LOOKUP, %s, %s\n", feature, data);
fprintf(out, "LOOKUP, %s, %s\n", feature, data);
Movie* target = head;
while (target != NULL) {
char success = 0;
if (strcmp(feature, "ID") == 0) {
if (get(atoi(data)) == NULL)
success++;
} else if (strcmp(feature, "TITLE") == 0) {
success += fnmatch(data, target->title, FNM_CASEFOLD);
} else if (strcmp(feature, "DATE") == 0) {
success += fnmatch(data, target->date, FNM_CASEFOLD);
} else if (strcmp(feature, "DIRECTOR") == 0) {
success += fnmatch(data, target->director, FNM_CASEFOLD);
}
if (success == 0) {
printf("%s, %s, %s, %d\n", target->title, target->date, target->director, target->id);
fprintf(out, "%s, %s, %s, %d\n", target->title, target->date, target->director, target->id);
}
target = target->next;
}
return 0;
}
int display(char* feature, int order, int max, FILE* out) {
if (feature == NULL)
return 1;
printf("DISPLAY, %s, %d, %d\n", feature, order, max);
fprintf(out, "DISPLAY, %s, %d, %d\n", feature, order, max);
if (max <= 0) {
return 0;
} else if (max > size) {
max = size;
}
Movie* target = head;
int count = 0; // Number of Movies displayed.
int* countedIds = calloc(max, sizeof(int)); // Set 'em all to 0.
Movie* best = target;
while (count < max) {
while (target != NULL) {
if (idIncluded(target->id, countedIds, max) == 0) { // ID not counted yet. (Ignore counted ones)
if (order == 0) { // Ascending: smallest first.
if ( (strcmp(feature, "TITLE") == 0 && strcmp(target->title, best->title) < 0)
|| (strcmp(feature, "DATE") == 0 && strcmp(target->date, best->date) < 0)
|| (strcmp(feature, "DIRECTOR") == 0 && strcmp(target->director, best->director) < 0)
|| (strcmp(feature, "ID") == 0 && target->id < best->id) ) {
best = target;
}
} else { // Descending: largest first.
if ( (strcmp(feature, "TITLE") == 0 && strcmp(target->title, best->title) > 0)
|| (strcmp(feature, "DATE") == 0 && strcmp(target->date, best->date) > 0)
|| (strcmp(feature, "DIRECTOR") == 0 && strcmp(target->director, best->director) > 0)
|| (strcmp(feature, "ID") == 0 && target->id > best->id) ) {
best = target;
}
}
}
target = target->next; // Okay if target is NULL.
}
countedIds[count] = best->id;
printf("%s, %s, %s, %d\n", best->title, best->date, best->director, best->id);
fprintf(out, "%s, %s, %s, %d\n", best->title, best->date, best->director, best->id);
count++;
// Set best to an uncounted ID.
Movie* nextBest = head;
while (nextBest != NULL) {
if (idIncluded(nextBest->id, countedIds, max) == 0) {
best = nextBest;
break;
} else
nextBest = nextBest->next;
}
}
return 0;
}
int idIncluded(int id, int* idList, size_t len) {
for (int i = 0; i < len; i++) {
if (id == idList[i])
return 1;
}
return 0;
}
void trimString(char* str) {
/*int length = 0;
int start = -1;
int end = -1;
int i;
for (i = 0; str[i] != '\0'; i++) {
if (str[i] != ' ' && start == -1) {
start = i;
}
}
length = i;
int j;
for (j = length - 1; j > start; j--) {
if (str[j] != ' ' && end == -1) {
end = j;
break;
}
}
char* str2 = (char *) malloc(sizeof(char) * (end - start + 1));
strncpy(str2, str + start, end - start + 1);
str2[end + 1] = '\0';
return str2;*/
char* firstNoSpace = str;
while (*firstNoSpace != '\0' && *firstNoSpace == ' ') {
++firstNoSpace;
}
size_t len = strlen(firstNoSpace) + 1;
memmove(str, firstNoSpace, len);
char* endOfStr = str + len;
while (str < endOfStr && *endOfStr == ' ') {
--endOfStr;
}
*endOfStr = '\0';
}