#include "set.h" #include <ctype.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> bool insert_text(Set *set, char *restrict word, size_t *index) { if (*index > 0) { word[*index] = 0; if (!multiset_insert(set, word, *index + 1)) { fprintf(stderr, "Set insert failed.\n"); return false; } *index = 0; } return true; } bool insert_words(FILE *fptr, Set *set) { static constexpr size_t buf_size = 4096; char buffer[buf_size]; size_t bytes = 0; size_t word_size = buf_size; size_t index = 0; char *word = malloc(word_size + 1); if (word == nullptr) { fprintf(stderr, "Error on allocation.\n"); return false; } while ((bytes = fread(buffer, sizeof(char), buf_size, fptr)) > 0) { for (size_t i = 0; i < bytes; ++i) { unsigned char c = (unsigned char)buffer[i]; if (isalnum(c)) { if (index >= word_size) { word_size *= 2; char *temp = realloc(word, word_size + 1); if (temp == nullptr) { free(word); return false; } word = temp; } word[index++] = (char)tolower(c); } else { if (!insert_text(set, word, &index)) { free(word); return false; } } } } if (ferror(fptr)) { free(word); return false; } if (index > 0) { word[index] = 0; if (!insert_text(set, word, &index)) { free(word); return false; } } free(word); return true; } void destroy(void *ptr) { free(ptr); } int compare(const void *a, const void *b) { if (a == nullptr && b == nullptr) return 0; if (a == nullptr) return -1; if (b == nullptr) return 1; return strcmp((const char *)a, (const char *)b); } void echo(const void *ptr) { printf("\t%s\n", (const char *)ptr); } void echo_count(const void *ptr, size_t count) { printf("\t%s: %zu\n", (const char *)ptr, count); } void echo_notab(const void *ptr) { printf("%s\n", (const char *)ptr); } int main(int argc, char **argv) { if (argc > 1) { size_t files = 0; Set *total = nullptr; bool show_info = true; bool use_multi = false; int start = 1; int file_index = 1; if (strcmp(argv[1], "-q") == 0) { show_info = false; start++; } else if (strcmp(argv[1], "-m") == 0) { use_multi = true; show_info = true; start++; } else if (strcmp(argv[1], "-mq") == 0) { show_info = false; use_multi = true; start++; } if (!set_init(&total, destroy, compare)) { fprintf(stderr, "Error creating set..\n"); return EXIT_FAILURE; } for (int i = start; i < argc; ++i) { FILE *fptr = fopen(argv[i], "rb"); if (fptr == nullptr) { if (show_info) fprintf(stderr, "Error file: %s could not be opened.\n", argv[i]); continue; } Set *temp_set = nullptr; if (!set_init(&temp_set, destroy, compare)) { fprintf(stderr, "Error initializing set.\n"); set_free(total); fclose(fptr); return EXIT_FAILURE; } if (insert_words(fptr, temp_set)) { if (!multiset_concat(total, temp_set)) { fprintf(stderr, "Error inserting set into total.\n"); set_free(total); set_free(temp_set); fclose(fptr); return EXIT_FAILURE; } else { set_free(temp_set); } if (show_info) { printf("Processed file[%d] -> %s.\n", file_index, argv[i]); file_index++; } files++; } else { set_free(total); set_free(temp_set); fclose(fptr); return EXIT_FAILURE; } fclose(fptr); } if (show_info) printf("Unique words across all files: {\n"); if (use_multi) multiset_print(total, echo_count); else set_print(total, (show_info == true) ? echo : echo_notab); if (show_info) { printf("}\n"); printf("%zu total unique words across %zu files.\n", set_count(total), files); } set_free(total); } return EXIT_SUCCESS; }