diff --git a/BuildDataBase.c b/BuildDataBase.c index 8b05edf22ecc008aaead0fd786f12ac99c512555..3f1627e981f1dacb5e46f2df15f74ae265ef7928 100644 --- a/BuildDataBase.c +++ b/BuildDataBase.c @@ -56,7 +56,6 @@ void read_line(); // Separates file chunk into lines. void tokenize_line(); // Separates lines into fields. void populate_array(); // Populates array with fields. void resize_array(); // Reallocates memory for array. -char* remove_quotes(); // Removes quotes from string value. void print_all_songs(); // Prints info for all songs in array. void print_song_info(); // Prints all info for provided song. void sort_array(); // Sorts array by song name. @@ -71,15 +70,16 @@ void exit_program(); // Frees memory and closes program. * Initializes and runs program. */ int main(int argc, char* argv[]) { + write(1, "Reading csv...\n", 16); songs_array = calloc(songs_array_max, sizeof(songs_struct *)); int file_descriptor = open_file("Data/SongCSV_Small.csv", O_RDONLY); read_file(file_descriptor); - write(1, "\n\n\n\n\n", 6); - //print_all_songs(); - //write(1, "\nSorting...\n\n\n", 15); sort_array(); - print_all_songs(); + //print_all_songs(); + write(1, "Saving to file...\n", 19); save_array(); + write(1, "Finished.\n", 11); + write(1, "Closing program...\n", 19); close(file_descriptor); exit_program(); } @@ -284,31 +284,6 @@ void populate_array(int field_number, char *field_buffer) { } -/** - * Removes quotes from provided string. - */ -char* remove_quotes(char* a_string) { - size_t string_length = strlen(a_string); - int orig_index; - int replace_index = 0; - - for (orig_index = 0; orig_index < string_length; orig_index++) { - if (a_string[orig_index] != '\"') { - a_string[replace_index] = a_string[orig_index]; - replace_index++; - } - } - - // Fill rest of values with null terminators. - while (replace_index < string_length) { - a_string[replace_index] = '\0'; - replace_index++; - } - - return a_string; -} - - /** * Sorts array by song name. */ diff --git a/HelperFunctions.c b/HelperFunctions.c index 9ab8f671dd4f14b1a05b9810e7f51683f451136d..e36edb6399b2c241c0200e938924c9b06f79e004 100644 --- a/HelperFunctions.c +++ b/HelperFunctions.c @@ -113,7 +113,7 @@ double* copy_double(double *source_ptr) { */ char* to_lower_case(char* input_string) { int index = 0; - char* return_string = calloc(strlen((input_string) + 1), sizeof(char)); + char* return_string = calloc((strlen(input_string) + 1), sizeof(char)); while (input_string[index]) { return_string[index] = tolower(input_string[index]); index++; @@ -162,3 +162,57 @@ char* first_letter_upper(char* input_string) { } return return_string; } + + +/** + * Removes quotes from provided string. + * + * Return: Quote-less version of initial string. + */ +char* remove_quotes(char* input_string) { + size_t string_length = strlen(input_string); + int orig_index; + int replace_index = 0; + + for (orig_index = 0; orig_index < string_length; orig_index++) { + if (input_string[orig_index] != '\"') { + input_string[replace_index] = input_string[orig_index]; + replace_index++; + } + } + + // Fill rest of values with null terminators. + while (replace_index < string_length) { + input_string[replace_index] = '\0'; + replace_index++; + } + + return input_string; +} + + +/** + * Removes newline character from string. + * + * Return: Newline-less version of initial string. + */ +char* remove_newline(char* input_string) { + size_t string_length = strlen(input_string); + int orig_index; + int replace_index = 0; + + for (orig_index = 0; orig_index < string_length; orig_index++) { + if (input_string[orig_index] != '\n') { + input_string[replace_index] = input_string[orig_index]; + replace_index++; + } + } + + // Fill rest of values with null terminators. + while (replace_index < string_length) { + input_string[replace_index] = '\0'; + replace_index++; + } + + return input_string; +} diff --git a/HelperHeader.h b/HelperHeader.h index 9f7430110943b229ff594fb1937f9e22300049bf..3d52d6fd19a18455575bc72099d8ec5542ee4168 100644 --- a/HelperHeader.h +++ b/HelperHeader.h @@ -20,3 +20,5 @@ double* copy_double(double* source_ptr); char* to_lower_case(char* input_string); char* to_upper_case(char* input_string); char* first_letter_upper(char* input_string); +char* remove_quotes(char* input_string); +char* remove_newline(char* input_string); diff --git a/UseDataBase.c b/UseDataBase.c index f5122075dcb7e2afe91f53dc02b857ead538a342..d9f0f7e58c5357cfa1d2dd67655e671a259f9bd4 100644 --- a/UseDataBase.c +++ b/UseDataBase.c @@ -58,6 +58,10 @@ void populate_array(); // Populates array with fields. void resize_array(); // Reallocates memory for array. void print_all_songs(); // Prints info for all songs in array. void print_song_info(); // Prints all info for provided song. +void print_help_text(); // Prints helper text for user. +void find_song(); // Find song with given name. +songs_struct* search_array_by_song(); // Binary search for name. +songs_struct* search_array_by_album(); // Linear search for album. void exit_program(); // Frees memory and closes program. @@ -66,13 +70,23 @@ void exit_program(); // Frees memory and closes program. * Initializes and runs program. */ int main(int argc, char* argv[]) { + int run_program_bool; // Bool to keep program running. + int song_directory_descriptor; // File descriptor for directory data. + int song_binary_descriptor; // File descriptor for binary song data. + int* song_size; // "Directory" size of current song. + char* user_input_string; // String of user's input. + char* input_to_lower; // User input as all lower. + off_t read_value; // Return value of read attempt. + off_t offset_size; // Return value of lseek attempt. + + // Initialize vars. + run_program_bool = 1; + song_directory_descriptor = open_file("Data/SongDirectory_Small", O_RDONLY); + song_binary_descriptor = open_file("Data/BinarySongData_Small", O_RDONLY); songs_array = calloc(songs_array_max, sizeof(songs_struct *)); - int song_directory_descriptor = open_file("Data/SongDirectory_Small", O_RDONLY); - int song_binary_descriptor = open_file("Data/BinarySongData_Small", O_RDONLY); - int* song_size = calloc(1, (sizeof(int) + 1)); - off_t read_value; - off_t offset_size; + song_size = calloc(1, (sizeof(int) + 1)); + // Read songs until no more directories are present. while ((read_value = read(song_directory_descriptor, song_size, sizeof(int))) != 0) { if (read_value < 0) { err_sys("Failed to read line."); @@ -86,12 +100,48 @@ int main(int argc, char* argv[]) { read_songs(song_binary_descriptor, song_size); } - print_all_songs(); + print_help_text(); + + while (run_program_bool) { + user_input_string = calloc(1, BUFFER_SIZE); + + // Read input from console. + write(1, "Enter input: ", 14); + read_value = read(0, user_input_string, BUFFER_SIZE); + write(1, "\n", 2); + + user_input_string = remove_newline(user_input_string); + + // Read user input and handle accordingly. + if ((user_input_string != NULL) && (strcmp(user_input_string, "") != 0)) { + input_to_lower = to_lower_case(user_input_string); + + // Check if user needs reprinting of help text. + if (strcmp(input_to_lower, "help") == 0) { + print_help_text(); + } + // Check if user has requested to exit program. + else if (strcmp(input_to_lower, "zzz") == 0) { + run_program_bool = 0; + printf("Exiting Program...\n"); + } + // Check if user has requested to print all songs. + else if (strcmp(input_to_lower, "all") == 0) { + print_all_songs(); + } + else { // Attempt to find song with given name. + //printf("User Input: %s", input_to_lower); + find_song(input_to_lower); + } + free(input_to_lower); + } + free(user_input_string); + } + // Free memory and close program. free(song_size); close(song_directory_descriptor); close(song_binary_descriptor); - exit_program(); } @@ -117,8 +167,6 @@ void read_songs(int binary_descriptor, int* song_size) { void* read_buffer; read_buffer = calloc(1, BUFFER_SIZE); - printf("Song Struct Size: %d\n", *song_size); - ssize_t read_value = read(binary_descriptor, read_buffer, *song_size); if (read_value < 0) { err_sys("Failed to read in song."); @@ -130,7 +178,6 @@ void read_songs(int binary_descriptor, int* song_size) { } populate_array(song_size, read_buffer); - free(read_buffer); } @@ -146,95 +193,69 @@ void populate_array(int song_size, ssize_t read_buffer) { double* double_buffer; double* double_pointer; - songs_array[song_index] = calloc(1, sizeof(songs_struct)); // Get Song Name. char_pointer = ((char*)read_buffer); char_buffer = calloc(1, BUFFER_SIZE); - index = 0; while (char_pointer[0] != '\0') { char_buffer[index] = *char_pointer; ++char_pointer; index++; } - printf("Name: %s\n", char_buffer); songs_array[song_index]->song_name = copy_string(char_buffer); - printf("Struct Value: %s\n", songs_array[song_index]->song_name); ++char_pointer; free(char_buffer); - // Get Album. char_buffer = calloc(1, BUFFER_SIZE); - index = 0; while (char_pointer[0] != '\0') { char_buffer[index] = *char_pointer; ++char_pointer; index++; } - printf("Album: %s\n", char_buffer); songs_array[song_index]->album_name = copy_string(char_buffer); - printf("Struct Value: %s\n", songs_array[song_index]->album_name); ++char_pointer; free(char_buffer); - // Get Artist. char_buffer = calloc(1, BUFFER_SIZE); - index = 0; while (char_pointer[0] != '\0') { char_buffer[index] = *char_pointer; ++char_pointer; index++; } - printf("Artist: %s\n", char_buffer); songs_array[song_index]->artist = copy_string(char_buffer); - printf("Struct Value: %s\n", songs_array[song_index]->artist); ++char_pointer; free(char_buffer); - // Get Duration. float_buffer = calloc(1, (sizeof(float) + 1)); float_pointer = (float*)char_pointer; *float_buffer = *float_pointer; - - printf("Duraton: %.2f\n", *float_buffer); songs_array[song_index]->duration = copy_float(float_buffer); - printf("Struct Value: %.2f\n", *songs_array[song_index]->duration); ++float_pointer; free(float_buffer); - // Get Hotttnesss. double_buffer = calloc(1, (sizeof(double) + 1)); double_pointer = (double*)float_pointer; *double_buffer = *double_pointer; - - printf("Hotttnesss: %.2f\n", *double_buffer); songs_array[song_index]->hotttnesss = copy_double(double_buffer); - printf("Struct Value: %.2f\n", *songs_array[song_index]->hotttnesss); ++double_pointer; free(double_buffer); - // Get Year. int_buffer = calloc(1, (sizeof(int) + 1)); int_pointer = (int*)double_pointer; *int_buffer = *int_pointer; - - printf("Year: %d\n", *int_buffer); songs_array[song_index]->year = copy_int(int_buffer); - printf("Struct Value: %d\n", *songs_array[song_index]->year); ++int_pointer; free(int_buffer); - printf("\n\n"); - song_index++; } @@ -271,6 +292,132 @@ void print_song_info(songs_struct* song) { } +/** + * Prints helper text. + * Called on program start and again if user types "Help". + */ +void print_help_text() { + printf("To display help text again, type 'Help'.\n"); + printf("To print all songs, type 'All'\n"); + printf("To exit program, type 'ZZZ'.\n"); + printf("Otherwise, type name of song you wish to locate.\n\n"); +} + + +/** + * Searches through array and finds song based on user input. + */ +void find_song(char* user_input_string) { + int song_counter = -1; // To account for arrays starting at 0. + int index = 0; + char* temp_string; + songs_struct* song; + songs_struct* temp_song = calloc(1, sizeof(songs_struct*)); + + // Count current number of songs in array. + while (songs_array[index] != NULL) { + song_counter++; + index++; + } + + // Search for user's input, first by song_name, then by album name. + song = search_array_by_song(temp_song, 0, song_counter, user_input_string); + + // Check returned song. + if (song != NULL) { + print_song_info(song); + free(temp_song); + } else { // Not found. Search again by album instead of song_name. + song = search_array_by_album(0, song_counter, user_input_string); + if (song != NULL) { + print_song_info(song); + } else { + // Could not find song or album. + temp_string = first_letter_upper(user_input_string); + err_msg("Could not find song or album with name: %s\n", temp_string); + free(temp_string); + } + } + //free(song); +} + + +/** + * Uses binary search to locate song with desired name. + * + * Return: Either valid song or NULL, depending on if record is found or not. + */ +songs_struct* search_array_by_song(songs_struct* return_song, + int first_index, int last_index, char* desired_record) { + + //songs_struct* return_song = calloc(1, sizeof(songs_struct*)); // Song to return. + char* temp_string; + + // First check if this is the end of search or not. + if (first_index >= last_index) { + + // End of search. Handle accordingly. + temp_string = to_lower_case(songs_array[first_index]->song_name); + if ((strcmp(desired_record, temp_string)) == 0 ) { + // Match found. Use given struct. + free(temp_string); + return_song = songs_array[first_index]; + } else { + // End of search and no match found. Use NULL. + free(temp_string); + free(return_song); + return_song = NULL; + } + + } else { // Still more values to search. Handle accordingly. + int mid_index = (first_index + last_index) / 2; + temp_string = to_lower_case(songs_array[mid_index]->song_name); + if ((strcmp(desired_record, temp_string)) == 0 ) { + // Match found. Use given struct. + free(temp_string); + return_song = songs_array[mid_index]; + } else { + if ((strcmp(desired_record, temp_string)) < 0 ) { + // Current struct song name is higher letter than desired. + // Searching first half of provided structs. + free(temp_string); + return_song = search_array_by_song(return_song, first_index, mid_index, desired_record); + } else { + // Current struct song name is lower letter than desired. + // Searching later half of provided structs. + free(temp_string); + return_song = search_array_by_song(return_song, mid_index + 1, last_index, desired_record); + } + } + } + + return return_song; +} + + +/** + * Songs Array is not sorted by album, thus uses basic linear search. + * This is called far less often so that should be acceptable. + * + * Return either valid album or NULL, depending on if record is found or not. + */ +songs_struct* search_array_by_album(int first_index, int last_index, char* desired_record) { + int index = 0; + + while (songs_array[index] != NULL) { + char* temp_string = to_lower_case(songs_array[index]->album_name); + if (strcmp(temp_string, desired_record) == 0) { + free(temp_string); + return songs_array[index]; + } + index++; + free(temp_string); + } + + return NULL; +} + + /** * Frees remaining memory and so program can close cleanly. */