grimoire/c/spellcheck.c

113 lines
2.1 KiB
C

#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#define DICTIONARY "/usr/share/dict/words"
struct trie {
struct trie *children[26];
uint8_t terminal;
};
void new_trie(struct trie *tree) {
uint8_t idx = 0;
for(; idx < 26; idx += 1) {
tree->children[idx] = NULL;
}
tree->terminal = 0;
}
void trie_insert(struct trie *tree, const char *str, uint8_t len) {
struct trie *node = tree;
uint8_t idx = 0;
for(; idx < len; idx += 1) {
uint8_t pos = tolower(str[idx]) - 'a';
if(node->children[pos] == NULL) {
void *mem = malloc(sizeof(struct trie));
if(mem == NULL) {
fprintf(stderr, "could not allocate memory: %s\n", strerror(errno));
exit(1);
}
node->children[pos] = mem;
new_trie(node->children[pos]);
}
node = node->children[pos];
}
node->terminal = 1;
}
uint8_t trie_has(struct trie *tree, const char *str, uint8_t len) {
struct trie *node = tree;
uint8_t idx = 0;
for(; idx < len; idx += 1) {
uint8_t pos = tolower(str[idx]) - 'a';
if(node->children[pos] == NULL) {
return 0;
}
node = node->children[pos];
}
return node->terminal;
}
int main(int argc, char **argv) {
struct trie dict;
new_trie(&dict);
int fd = open(DICTIONARY, O_RDONLY);
if(fd < 0) {
fprintf(stderr, "could not open %s: %s\n", DICTIONARY, strerror(errno));
return 1;
}
ssize_t bytes = 0;
char buf[1024] = { 0 };
char word[128] = { 0 };
uint8_t len = 0;
while((bytes = read(fd, buf, sizeof(buf))) > 0) {
ssize_t idx = 0;
for(; idx < bytes; idx += 1) {
if(buf[idx] == '\n') {
trie_insert(&dict, word, len);
len = 0;
bzero(word, sizeof(word));
} else if(len < sizeof(word)) {
word[len] = buf[idx];
len += 1;
}
}
}
if(bytes < 0) {
fprintf(stderr, "could not read from %s: %s\n", DICTIONARY, strerror(errno));
return 1;
}
const char *check = "paladin";
if(argc > 1) {
check = argv[1];
}
return !trie_has(&dict, check, strlen(check));
}