#include #include #include #include #include #include #include #include "tree.h" /* On FreeBSD, we could just use the system's tree instead: #include */ struct tree_node { char *word; // This is the key unsigned int count; // This is the value RB_ENTRY(tree_node) tree_entry; }; int tncompare(struct tree_node *a, struct tree_node *b){ return strcmp(a->word, b->word); } RB_HEAD(word_tree, tree_node); RB_GENERATE_STATIC(word_tree, tree_node, tree_entry, tncompare); struct word_tree wtree; void new_word(char *start, char *stop){ /* Instead of printing it out, can we put it in a tree? */ char *word_place = malloc(1 + stop - start); for(int i = 0; start + i < stop; i++) word_place[i] = tolower(start[i]); word_place[stop - start] = 0; struct tree_node *existing_node = RB_FIND(word_tree, &wtree, (struct tree_node*)&word_place); if(existing_node){ existing_node->count++; free(word_place); } else { struct tree_node *nn = malloc(sizeof(struct tree_node)); nn->count = 1; nn->word = word_place; RB_INSERT(word_tree, &wtree, nn); } } int main(int argc, char ** argv){ if(argc < 2) { printf("Usage: %s filename\n", argv[0]); return 1; } int fd = open(argv[1], O_RDONLY); if(fd < 0){ perror(argv[1]); return 2; } ssize_t length = lseek(fd, 0, SEEK_END); printf("Opened file %s (%ld bytes)\n", argv[1], length); char *file_contents = mmap(0, length, PROT_READ, MAP_SHARED, fd, 0); char inword = 0; char *wordstart = 0; for(size_t i = 0; i < length; i++){ if(!inword && isalpha(file_contents[i])){ inword = 1; wordstart = &file_contents[i]; } else if( inword && !isalpha(file_contents[i])){ inword = 0; new_word(wordstart, &file_contents[i]); } } munmap(file_contents, length); close(fd); struct tree_node *i; RB_FOREACH(i, word_tree, &wtree){ printf("%s: %u\n", i->word, i->count); } return 0; }