2 * Copyright © 2006 Carl Worth
4 * This program is free software; you can redistribute it and\/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA."
19 /* Portably, schmortability. I want ease of programming. */
29 typedef struct _string {
35 #define TRIE_FLAGS_IS_WORD (1<<0)
38 (*trie_predicate_t) (trie_t *trie);
40 #define TRIE_CHAR_TO_INDEX(c) (tolower (c) - 'a')
41 #define TRIE_INDEX_TO_CHAR(i) (i + 'a')
50 fprintf (stderr, "Error: out of memory\n");
58 xrealloc (void *ptr, size_t size)
62 res = realloc (ptr, size);
64 fprintf (stderr, "Error: out of memory\n");
77 if (s[len - 1] == '\n')
82 string_init (string_t *string)
90 string_fini (string_t *string)
99 string_append_char (string_t *string, char c)
101 if (string->size == 0) {
103 string->s = xmalloc (string->size);
108 if (string->len + 1 == string->size) {
110 string->s = xrealloc (string->s, string->size);
113 string->s[string->len++] = c;
114 string->s[string->len] = '\0';
118 string_chop (string_t *string)
120 if (string->len == 0)
123 string->s[--string->len] = '\0';
127 trie_init (trie_t *trie)
131 for (i = 0; i < 26; i++)
132 trie->next[i] = NULL;
136 trie_destroy (trie_t *trie);
139 trie_fini (trie_t *trie)
143 for (i = 0; i < 26; i++)
145 trie_destroy (trie->next[i]);
153 trie = xmalloc (sizeof (trie_t));
161 trie_destroy (trie_t *trie)
169 trie_add (trie_t *trie,
170 const char *word_chunk)
172 char c = word_chunk[0];
176 trie->flags |= TRIE_FLAGS_IS_WORD;
180 i = TRIE_CHAR_TO_INDEX (c);
181 if (trie->next[i] == NULL)
182 trie->next[i] = trie_create ();
184 trie_add (trie->next[i], word_chunk + 1);
188 trie_find (trie_t *trie,
189 const char *word_chunk)
191 const char *s = word_chunk;
194 trie = trie->next[TRIE_CHAR_TO_INDEX (*s++)];
200 trie_count (trie_t *trie,
201 trie_predicate_t predicate)
206 if ((predicate) (trie))
209 for (i = 0; i < 26; i++) {
210 if (trie->next[i] == NULL)
213 count += trie_count (trie->next[i], predicate);
220 trie_print (trie_t *trie,
222 trie_predicate_t predicate,
231 if (length >= min_length && (predicate) (trie))
234 printf ("%s ", string->s);
237 if (length == max_length)
240 /* Loop over each element, appending the character and recursing. */
241 for (i = 0; i < 26; i++) {
242 if (trie->next[i] == NULL)
245 c = TRIE_INDEX_TO_CHAR (i);
247 string_append_char (string, c);
248 count += trie_print (trie->next[i], string, predicate,
249 length + 1, min_length, max_length);
250 string_chop (string);
257 dict_init (dict_t *dict)
263 dict_fini (dict_t *dict)
269 dict_add_word (dict_t *dict,
272 trie_add (dict, word);
276 dict_add_words_from_file (dict_t *dict,
277 const char *filename)
281 size_t line_size = 0;
284 file = fopen (filename, "r");
286 fprintf (stderr, "Error: failed to open %s: %s\n",
287 filename, strerror (errno));
292 bytes_read = getline (&line, &line_size, file);
293 if (bytes_read == -1)
296 dict_add_word (dict, line);
305 dict_lookup (dict_t *dict,
310 trie = trie_find (dict, word);
317 /* Yes, this function is rather silly. I have it here in the hope that
318 * it could be used for some better type-checking, (if only C had such
321 dict_root (dict_t *dict)
327 dict_cursor_next (dict_cursor_t cursor,
330 trie_t *trie = cursor;
333 return DICT_CURSOR_NIL;
335 return trie->next[TRIE_CHAR_TO_INDEX (next)];
339 dict_cursor_resolve (dict_cursor_t cursor)
343 if (cursor == DICT_CURSOR_NIL)
350 /* XXX: This static function pointer is really nasty and definitely
351 * un-thread safe. What I really want it a lambda so I can construct a
352 * composite predicate on the fly. Oh well... */
353 static dict_entry_predicate_t dict_entry_predicate = NULL;
356 dict_predicate (trie_t *trie)
360 entry = dict_cursor_resolve (trie);
361 if (! DICT_ENTRY_IS_WORD (entry))
364 if (dict_entry_predicate)
365 return (dict_entry_predicate) (*entry);
371 dict_count (dict_t *dict,
372 dict_entry_predicate_t predicate)
374 dict_entry_predicate = predicate;
375 return trie_count (dict, dict_predicate);
379 dict_print (dict_t *dict)
384 string_init (&string);
386 dict_entry_predicate = NULL;
387 count = trie_print (dict, &string, dict_predicate,
390 string_fini (&string);
396 dict_print_if (dict_t *dict,
397 dict_entry_predicate_t predicate)
402 string_init (&string);
404 dict_entry_predicate = predicate;
405 count = trie_print (dict, &string, dict_predicate,
408 string_fini (&string);
414 dict_print_by_length_if (dict_t *dict,
415 dict_entry_predicate_t predicate)
417 int length, total, words, count = 0;
420 string_init (&string);
422 dict_entry_predicate = predicate;
424 total = trie_count (dict, dict_predicate);
428 words = trie_print (dict, &string, dict_predicate,
435 } while (count < total);
437 string_fini (&string);