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