#include "miniDB.h" Movie* head = NULL; int size = 0; int main(int argc, char** argv) { if (argc < 4) { printf("Usage: miniDB \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[length]; while (fgets(buffer, length, file) != NULL && strcmp(buffer, "") != 0) { printf("Command read: %s\n", buffer); char* token = strtok(buffer, ", "); if (token == NULL) { token = strtok(buffer, ","); if (token == NULL) return 4; } if (strcmp(token, "ADD") == 0) { token = strtok(buffer, NULL); if (token == NULL) return 5; char* title = strdup(token); token = strtok(buffer, NULL); if (token == NULL) return 5; char* date = strdup(token); token = strtok(buffer, NULL); if (token == NULL) return 5; char* director = strdup(token); token = strtok(buffer, NULL); if (token == NULL) return 5; int id = atoi(token); if (add(title, date, director, id) != 0) return 6; free(title); free(date); free(director); title = NULL; date = NULL; director = NULL; } else if (strcmp(token, "LOOKUP") == 0) { token = strtok(buffer, NULL); if (token == NULL) return 5; char* feature = strdup(token); token = strtok(buffer, NULL); if (token == NULL) return 5; char* data = strdup(token); if (lookup(feature, data, output) != 0) return 6; free(feature); free(data); feature = NULL; data = NULL; } else if (strcmp(token, "DISPLAY") == 0) { token = strtok(buffer, NULL); if (token == NULL) return 5; char* feature = strdup(token); token = strtok(buffer, NULL); if (token == NULL) return 5; int order = atoi(token); token = strtok(buffer, NULL); if (token == NULL) return 5; int max = atoi(token); if (display(feature, order, max, output) != 0) return 6; free(feature); feature = NULL; } else if (strcmp(token, "EDIT") == 0) { token = strtok(buffer, NULL); if (token == NULL) return 5; int id = atoi(token); token = strtok(buffer, NULL); if (token == NULL) return 5; char* feature = strdup(token); token = strtok(buffer, NULL); if (token == NULL) return 5; char* data = strdup(token); if (edit(id, feature, data) != 0) return 6; free(feature); free(data); feature = NULL; data = NULL; } else if (strcmp(token, "REMOVE") == 0) { token = strtok(buffer, NULL); if (token == NULL) return 5; int id = atoi(token); if (removeId(id) != 0) return 6; } } 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[length]; while (fgets(buffer, length, file) != NULL && strcmp(buffer, "") != 0) { printf("Line read: %s\n", buffer); char* token = strtok(buffer, ", "); if (token == NULL) { token = strtok(buffer, ","); if (token == NULL) return 3; } // Now that it's kicked off with the correct delimeter... char* title = strdup(token); token = strtok(buffer, NULL); if (token == NULL) return 5; char* date = strdup(token); token = strtok(buffer, NULL); if (token == NULL) return 5; char* director = strdup(token); token = strtok(buffer, NULL); if (token == NULL) return 5; int id = atoi(token); if (add(title, date, director, id) != 0) return 6; free(title); free(date); free(director); title = NULL; date = NULL; director = NULL; } printf("End of file.\n"); if (fclose(file) != 0) { return 4; } 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_NOCASE"); } else if (strcmp(feature, "DATE") == 0) { success += fnmatch(data, target->date, "FNM_NOCASE"); } else if (strcmp(feature, "DIRECTOR") == 0) { success += fnmatch(data, target->director, "FNM_NOCASE"); } 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; }