#include #include #include #include #include // ANSI color codes #define RESET "\033[0m" #define RED "\033[31m" #define GREEN "\033[32m" #define YELLOW "\033[33m" #define BLUE "\033[34m" #define MAGENTA "\033[35m" #define CYAN "\033[36m" #define WHITE "\033[37m" #define MAX_LINE_LENGTH 1024 #define NUM_THREADS 4 // Define the struct to hold the parsed data for each line typedef struct { char *titleId; // Dynamically allocated int ordering; char *title; // Dynamically allocated char *region; // Dynamically allocated char *language; // Dynamically allocated char *types; // Dynamically allocated char *attributes; // Dynamically allocated int isOriginalTitle; } TitleLanguages; typedef struct { FILE *fh; long start_offset; long end_offset; TitleLanguages **parsed_lines; int *line_count; int thread_id; } ThreadArgs; char *strdup(const char *s); // Function to read and store all lines (as strings) void *processAkaLinesThread(void *args) { ThreadArgs *thread_args = (ThreadArgs *)args; FILE *fh = thread_args->fh; long start_offset = thread_args->start_offset; long end_offset = thread_args->end_offset; TitleLanguages **parsed_lines = thread_args->parsed_lines; int *line_count = thread_args->line_count; printf(MAGENTA "┌──────────────────────────────────────\n└── " CYAN "Starting Thread" YELLOW " %d\n" RESET, thread_args->thread_id); // Set the file pointer to the start_offset position fseek(fh, start_offset, SEEK_SET); char line[MAX_LINE_LENGTH]; // Buffer for each line int alloc_size = 10; // Initial memory allocation size *parsed_lines = malloc(alloc_size * sizeof(TitleLanguages)); // Allocate memory for the array of TitleLanguages structs if (!*parsed_lines) { perror("Memory allocation failed"); return NULL; } // Read lines until we reach the end_offset while (ftell(fh) < end_offset && fgets(line, sizeof(line), fh)) { // Remove newline character from line line[strcspn(line, "\n")] = 0; // If we've reached the allocated size, reallocate more memory for TitleLanguages array if (*line_count >= alloc_size) { alloc_size *= 2; // Double the allocated size *parsed_lines = realloc(*parsed_lines, alloc_size * sizeof(TitleLanguages)); if (!*parsed_lines) { perror("Memory reallocation failed"); return NULL; } } TitleLanguages *current_line = &(*parsed_lines)[*line_count]; // Parse the fields from the line and directly store them into the struct current_line->titleId = strdup(strtok(line, "\t")); current_line->ordering = atoi(strtok(NULL, "\t")); current_line->title = strdup(strtok(NULL, "\t")); current_line->region = strdup(strtok(NULL, "\t")); current_line->language = strdup(strtok(NULL, "\t")); current_line->types = strdup(strtok(NULL, "\t")); current_line->attributes = strdup(strtok(NULL, "\t")); current_line->isOriginalTitle = atoi(strtok(NULL, "\t")); // If any memory allocation fails, free all previously allocated memory if (!current_line->titleId || !current_line->title || !current_line->region || !current_line->language || !current_line->types || !current_line->attributes) { perror("Memory allocation failed"); return NULL; } (*line_count)++; } return NULL; } // Function to read the Akas file and process lines int readAkas(TitleLanguages **languages) { FILE *fh = NULL; // Open the file specified by the constant FILENAME fh = fopen("imdb/title.akas.tsv", "r"); if (!fh) { perror("Error opening file"); return 1; } // Get the file size to divide the file into chunks for threads fseek(fh, 0, SEEK_END); long file_size = ftell(fh); fclose(fh); // Create threads to process file chunks pthread_t threads[NUM_THREADS]; ThreadArgs thread_args[NUM_THREADS]; long chunk_size = file_size / NUM_THREADS; TitleLanguages *merged_languages = NULL; int merged_line_count = 0; for (int i = 0; i < NUM_THREADS; i++) { thread_args[i].fh = fopen("imdb/title.akas.tsv", "r"); thread_args[i].start_offset = i * chunk_size; thread_args[i].end_offset = (i == NUM_THREADS - 1) ? file_size : (i + 1) * chunk_size; thread_args[i].parsed_lines = malloc(sizeof(TitleLanguages *)); if (!thread_args[i].parsed_lines) { perror("Memory allocation failed for thread_args[i].parsed_lines"); exit(1); } thread_args[i].line_count = malloc(sizeof(int)); if (!thread_args[i].line_count) { perror("Memory allocation failed for thread_args[i].line_count"); exit(1); } *thread_args[i].line_count = 0; thread_args[i].thread_id = i; pthread_create(&threads[i], NULL, processAkaLinesThread, &thread_args[i]); } // Join threads and combine results for (int i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); // Merge thread results into the final languages array for (int j = 0; j < *thread_args[i].line_count; j++) { merged_languages = realloc(merged_languages, (merged_line_count + 1) * sizeof(TitleLanguages)); if (!merged_languages) { perror("Memory reallocation failed"); return 1; } merged_languages[merged_line_count] = (*thread_args[i].parsed_lines)[j]; merged_line_count++; } // Clean up thread-specific memory free(thread_args[i].parsed_lines); free(thread_args[i].line_count); fclose(thread_args[i].fh); } printf("Processing complete. Total lines read: %d\n", merged_line_count); // Assign the merged languages back to the caller *languages = merged_languages; return merged_line_count; } int main(void) { TitleLanguages *languages = NULL; int line_count = 0; // Pass the address of languages to readAkas line_count = readAkas(&languages); // Print the first 4 lines and last 4 lines of the struct array printf("First and last 4 lines processed:\n"); for (int i = 0; i < line_count; i++) { // Print first 4 lines if (i < 4) { printf("Line %d: %s, %d, %s, %s, %s, %s, %d\n", i + 1, languages[i].titleId, languages[i].ordering, languages[i].title, languages[i].region, languages[i].language, languages[i].types, languages[i].isOriginalTitle); } // Print last 4 lines if (i >= line_count - 4) { printf("Line %d: %s, %d, %s, %s, %s, %s, %d\n", i + 1, languages[i].titleId, languages[i].ordering, languages[i].title, languages[i].region, languages[i].language, languages[i].types, languages[i].isOriginalTitle); } } // Clean up the array of structs and the dynamically allocated strings for (int i = 0; i < line_count; i++) { free(languages[i].titleId); free(languages[i].title); free(languages[i].region); free(languages[i].language); free(languages[i].types); free(languages[i].attributes); } free(languages); return 0; }