]> git.cworth.org Git - wordgame/blob - dict.c
Begin to wean grid.c away from trie and toward dict.
[wordgame] / dict.c
1 /*
2  * Copyright © 2006 Carl Worth
3  *
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)
7  * any later version.
8  *
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.
13  *
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."
17  */
18
19 /* Portably, schmortability. I want ease of programming. */
20 #define _GNU_SOURCE
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <ctype.h>
26
27 #include "dict.h"
28
29 void *
30 xmalloc (size_t size)
31 {
32     void *res;
33
34     res = malloc (size);
35     if (res == NULL) {
36         fprintf (stderr, "Error: out of memory\n");
37         exit (1);
38     }
39
40     return res;
41 }
42
43 void *
44 xrealloc (void *ptr, size_t size)
45 {
46     void *res;
47
48     res = realloc (ptr, size);
49     if (res == NULL) {
50         fprintf (stderr, "Error: out of memory\n");
51         exit (1);
52     }
53
54     return res;
55 }
56
57 void
58 chomp (char *s)
59 {
60     int len = strlen (s);
61     if (s[len - 1] == '\n')
62         s[len - 1] = '\0';
63 }
64
65 void
66 string_init (string_t *string)
67 {
68     string->size = 0;
69     string->s = NULL;
70     string->len = 0;
71 }
72
73 void
74 string_fini (string_t *string)
75 {
76     string->size = 0;
77     if (string->s)
78         free (string->s);
79     string->len = 0;
80 }
81
82 void
83 string_append_char (string_t *string, char c)
84 {
85     if (string->size == 0) {
86         string->size = 8;
87         string->s = xmalloc (string->size);
88         string->s[0] = '\0';
89         string->len = 0;
90     }
91
92     if (string->len + 1 == string->size) {
93         string->size *= 2;
94         string->s = xrealloc (string->s, string->size);
95     }
96
97     string->s[string->len++] = c;
98     string->s[string->len] = '\0';
99 }
100
101 void
102 string_chop (string_t *string)
103 {
104     if (string->len == 0)
105         return;
106
107     string->s[--string->len] = '\0';
108 }
109
110 static void
111 trie_init (trie_t *trie)
112 {
113     int i;
114     trie->flags = 0;
115     for (i = 0; i < 26; i++)
116         trie->next[i] = NULL;
117 }
118
119 void
120 trie_destroy (trie_t *trie);
121
122 static void
123 trie_fini (trie_t *trie)
124 {
125     int i;
126
127     for (i = 0; i < 26; i++)
128         if (trie->next[i])
129             trie_destroy (trie->next[i]);
130 }
131
132 trie_t *
133 trie_create (void)
134 {
135     trie_t *trie;
136
137     trie = xmalloc (sizeof (trie_t));
138
139     trie_init (trie);
140
141     return trie;
142 }
143
144 void
145 trie_destroy (trie_t *trie)
146 {
147     trie_fini (trie);
148
149     free (trie);
150 }
151
152 void
153 trie_add (trie_t        *trie,
154           const char    *word_chunk)
155 {
156     char c = word_chunk[0];
157     int i;
158
159     if (c == '\0') {
160         trie->flags |= TRIE_FLAGS_IS_WORD;
161         return;
162     }
163
164     i = TRIE_CHAR_TO_INDEX (c);
165     if (trie->next[i] == NULL)
166         trie->next[i] = trie_create ();
167
168     trie_add (trie->next[i], word_chunk + 1);
169 }
170
171 trie_t *
172 trie_find (trie_t       *trie,
173            const char   *word_chunk)
174 {
175     const char *s = word_chunk;
176
177     while (trie && *s)
178         trie = trie->next[TRIE_CHAR_TO_INDEX (*s++)];
179
180     return trie;
181 }
182
183 int
184 trie_print (trie_t              *trie,
185             string_t            *string,
186             trie_predicate_t     predicate)
187 {
188     char c;
189     int i;
190     int count = 0;
191
192     if (trie->flags & TRIE_FLAGS_IS_WORD
193         && (predicate == NULL || predicate (trie)))
194     {
195         count = 1;
196         printf ("%s ", string->s);
197     }
198
199     /* Loop over each element, appending the character and recursing. */
200     for (i = 0; i < 26; i++) {
201         if (trie->next[i] == NULL)
202             continue;
203
204         c = TRIE_INDEX_TO_CHAR (i);
205
206         string_append_char (string, c);
207         count += trie_print (trie->next[i], string, predicate);
208         string_chop (string);
209     }
210
211     return count;
212 }
213
214 bool_t
215 trie_seen_predicate (trie_t *trie)
216 {
217     return (trie->flags & TRIE_FLAGS_SEEN);
218 }
219
220 int
221 trie_print_seen (trie_t *trie, string_t *word)
222 {
223     return trie_print (trie, word, trie_seen_predicate);
224 }
225
226 bool_t
227 trie_unseen_predicate (trie_t *trie)
228 {
229     return (! trie_seen_predicate (trie));
230 }
231
232 int
233 trie_print_unseen (trie_t *trie, string_t *word)
234 {
235     return trie_print (trie, word, trie_unseen_predicate);
236 }
237
238 void
239 dict_init (dict_t *dict)
240 {
241     trie_init (dict);
242 }
243
244 void
245 dict_fini (dict_t *dict)
246 {
247     trie_fini (dict);
248 }
249
250 void
251 dict_add_word (dict_t           *dict,
252                const char       *word)
253 {
254     trie_add (dict, word);
255 }
256
257 void
258 dict_add_words_from_file (dict_t        *dict,
259                           const char    *filename)
260 {
261     FILE *file;
262     char *line = NULL;
263     size_t line_size = 0;
264     ssize_t bytes_read;
265
266     file = fopen (filename, "r");
267     if (file == NULL) {
268         fprintf (stderr, "Error: failed to open %s: %s\n",
269                  filename, strerror (errno));
270         exit (1);
271     }
272
273     while (1) {
274         bytes_read = getline (&line, &line_size, file);
275         if (bytes_read == -1)
276             break;
277         chomp (line);
278         dict_add_word (dict, line);
279     }
280     if (line)
281         free (line);
282
283     fclose (file);
284 }
285
286 void
287 dict_print (dict_t *dict)
288 {
289     string_t string;
290
291     string_init (&string);
292
293     trie_print (dict, &string, NULL);
294
295     string_fini (&string);
296 }