1 /*  an - Anagram generator
2     Copyright (C) 2012,2014  Paul Martin <pm@debian.org>
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 of the License, or
7     (at your option) 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 along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 #include <string.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <unicode/ustring.h>
23 #include "words.h"
24 #include "unicode.h"
25 #include "bitfield.h"
26 #include "malloc.h"
27 
28 /* Wordlist is a simple linked list, ordered in decreasing word length */
29 
30 void
free_word(struct word * word)31 free_word(struct word *word)
32 {
33     if (word != NULL) {
34         free(word->utf8_form);
35         free_bitfield(word->bits);
36         free(word);
37     }
38 }
39 
40 static void
insert_word(struct wordlist ** words,struct word * newword)41 insert_word(struct wordlist **words, struct word *newword)
42 {
43     struct wordlist *entry, *p, *oldp;
44     if (newword == NULL)
45         return;
46     entry = safe_calloc(sizeof(struct wordlist), 1);
47     entry->word = newword;
48     if (*words == NULL) {
49         *words = entry;
50         return;
51     }
52     p = *words;
53     oldp = NULL;
54     while (p) {
55         if (p->word->length <= newword->length) {
56             if (oldp == NULL) {
57                 *words = entry;
58             } else {
59                 oldp->next = entry;
60             }
61             entry->next = p;
62             return;
63         }
64         oldp = p;
65         p = p->next;
66     }
67     oldp->next = entry;
68 }
69 
70 void
add_word(struct wordlist ** words,UChar * alphabet,struct bitfield * masterbits,int maxlen,int minlen,const char * word)71 add_word(struct wordlist **words, UChar *alphabet, struct bitfield *masterbits,
72          int maxlen, int minlen, const char *word)
73 {
74     UChar *internal;
75     struct word *newword = safe_calloc(sizeof(struct word), 1);
76 
77     internal = utf8tointernal(word);
78     if (internal == NULL) {
79         free(newword);
80         return;
81     }
82 
83     newword->length = u_strlen(internal);
84     if ((newword->length == 0) ||
85         (newword->length > maxlen) ||
86         (newword->length < minlen)) {
87         free(internal);
88         free(newword);
89         return;
90     }
91 
92     newword->bits = make_bitfield(internal, alphabet);
93     free(internal);
94 
95     if (newword->bits == NULL) {
96         /* word not contained totally in alphabet */
97         free(newword);
98         return;
99     }
100     if (bf_contains(masterbits, newword->bits)) {
101         newword->utf8_form = safe_strdup(word);
102         insert_word(words, newword);
103     } else {
104         free_word(newword);
105     }
106 
107 }
108 
109 void
load_words(struct wordlist ** words,UChar * alphabet,struct bitfield * masterbits,int maxlen,int minlen,const char * filename)110 load_words(struct wordlist **words, UChar *alphabet,
111            struct bitfield *masterbits, int maxlen, int minlen,
112            const char *filename)
113 {
114     FILE *dict;
115     char line[LONGEST_WORD];
116 
117     dict = fopen(filename, "r");
118     if (dict == NULL) {
119         fprintf(stderr, "Cannot open %s for reading.\n", filename);
120         exit(99);
121     }
122     while (fgets(line, LONGEST_WORD, dict) != NULL) {
123         char *l = line + strlen(line) - 1;
124         while ((l > line) && ((*l == '\r') || (*l == '\n'))) {
125             *l = '\0';
126             l--;
127         }
128         if (line[0])
129             add_word(words, alphabet, masterbits, maxlen, minlen, line);
130     }
131     fclose(dict);
132 }
133 
134 /* A word stack is wordlist used for storing intermediate results */
135 
136 struct wordlist *
push_wordstack(struct wordlist * stack,struct word * word)137 push_wordstack(struct wordlist *stack, struct word* word)
138 {
139     struct wordlist *entry;
140     if (word == NULL)
141         return NULL;
142     entry = safe_calloc(sizeof(struct wordlist), 1);
143     entry->word = word;
144     entry->next = stack;
145     return entry;
146 }
147 
148 struct wordlist *
pop_wordstack(struct wordlist * stack)149 pop_wordstack(struct wordlist *stack)
150 {
151     struct wordlist *entry;
152     entry = stack->next;
153     free(stack);
154     return entry;
155 }
156 
157 void
print_wordstack(struct wordlist * stack)158 print_wordstack(struct wordlist *stack)
159 {
160     if (stack == NULL)
161         return;
162     if (stack->next != NULL) {
163         print_wordstack(stack->next);
164         fputs(" ", stdout);
165     }
166     fputs(stack->word->utf8_form, stdout);
167 }
168 
169