| @@ -1,344 +1,348 @@ | | | @@ -1,344 +1,348 @@ |
1 | /*- | | 1 | /*- |
2 | * Copyright (c) 2013 The NetBSD Foundation, Inc. | | 2 | * Copyright (c) 2013 The NetBSD Foundation, Inc. |
3 | * All rights reserved. | | 3 | * All rights reserved. |
4 | * | | 4 | * |
5 | * This code is derived from software contributed to The NetBSD Foundation | | 5 | * This code is derived from software contributed to The NetBSD Foundation |
6 | * by David A. Holland. | | 6 | * by David A. Holland. |
7 | * | | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | | 9 | * modification, are permitted provided that the following conditions |
10 | * are met: | | 10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | | 14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. | | 15 | * documentation and/or other materials provided with the distribution. |
16 | * | | 16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 17 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
18 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 18 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
19 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 19 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
20 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 20 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 | * POSSIBILITY OF SUCH DAMAGE. | | 27 | * POSSIBILITY OF SUCH DAMAGE. |
28 | */ | | 28 | */ |
29 | | | 29 | |
30 | #include <stdio.h> | | 30 | #include <stdio.h> |
31 | #include <string.h> | | 31 | #include <string.h> |
32 | #include <stdlib.h> | | 32 | #include <stdlib.h> |
33 | #include <ctype.h> | | 33 | #include <ctype.h> |
34 | #include <time.h> | | 34 | #include <time.h> |
35 | #include <err.h> | | 35 | #include <err.h> |
36 | #include <assert.h> | | 36 | #include <assert.h> |
37 | #include <curses.h> | | 37 | #include <curses.h> |
38 | #include "pathnames.h" | | 38 | #include "pathnames.h" |
39 | | | 39 | |
40 | //////////////////////////////////////////////////////////// | | 40 | //////////////////////////////////////////////////////////// |
41 | | | 41 | |
42 | static char *xstrdup(const char *s) { | | 42 | static char *xstrdup(const char *s) { |
43 | char *ret; | | 43 | char *ret; |
44 | | | 44 | |
45 | ret = malloc(strlen(s) + 1); | | 45 | ret = malloc(strlen(s) + 1); |
46 | if (ret == NULL) { | | 46 | if (ret == NULL) { |
47 | errx(1, "Out of memory"); | | 47 | errx(1, "Out of memory"); |
48 | } | | 48 | } |
49 | strcpy(ret, s); | | 49 | strcpy(ret, s); |
50 | return ret; | | 50 | return ret; |
51 | } | | 51 | } |
52 | | | 52 | |
53 | //////////////////////////////////////////////////////////// | | 53 | //////////////////////////////////////////////////////////// |
54 | | | 54 | |
55 | struct stringarray { | | 55 | struct stringarray { |
56 | char **v; | | 56 | char **v; |
57 | int num; | | 57 | int num; |
58 | }; | | 58 | }; |
59 | | | 59 | |
60 | static void stringarray_init(struct stringarray *a) { | | 60 | static void stringarray_init(struct stringarray *a) { |
61 | a->v = NULL; | | 61 | a->v = NULL; |
62 | a->num = 0; | | 62 | a->num = 0; |
63 | } | | 63 | } |
64 | | | 64 | |
65 | static void stringarray_cleanup(struct stringarray *a) { | | 65 | static void stringarray_cleanup(struct stringarray *a) { |
66 | free(a->v); | | 66 | free(a->v); |
67 | } | | 67 | } |
68 | | | 68 | |
69 | static void stringarray_add(struct stringarray *a, const char *s) { | | 69 | static void stringarray_add(struct stringarray *a, const char *s) { |
70 | a->v = realloc(a->v, (a->num + 1) * sizeof(a->v[0])); | | 70 | a->v = realloc(a->v, (a->num + 1) * sizeof(a->v[0])); |
71 | if (a->v == NULL) { | | 71 | if (a->v == NULL) { |
72 | errx(1, "Out of memory"); | | 72 | errx(1, "Out of memory"); |
73 | } | | 73 | } |
74 | a->v[a->num] = xstrdup(s); | | 74 | a->v[a->num] = xstrdup(s); |
75 | a->num++; | | 75 | a->num++; |
76 | } | | 76 | } |
77 | | | 77 | |
78 | //////////////////////////////////////////////////////////// | | 78 | //////////////////////////////////////////////////////////// |
79 | | | 79 | |
80 | static struct stringarray lines; | | 80 | static struct stringarray lines; |
81 | static struct stringarray sollines; | | 81 | static struct stringarray sollines; |
82 | static bool hinting; | | 82 | static bool hinting; |
83 | static int scrolldown; | | 83 | static int scrolldown; |
84 | static unsigned curx; | | 84 | static unsigned curx; |
85 | static int cury; | | 85 | static int cury; |
86 | | | 86 | |
87 | static void readquote(void) { | | 87 | static void readquote(void) { |
88 | FILE *f = popen(_PATH_FORTUNE, "r"); | | 88 | FILE *f = popen(_PATH_FORTUNE, "r"); |
89 | if (!f) { | | 89 | if (!f) { |
90 | err(1, "%s", _PATH_FORTUNE); | | 90 | err(1, "%s", _PATH_FORTUNE); |
91 | } | | 91 | } |
92 | | | 92 | |
93 | char buf[128], buf2[8*sizeof(buf)]; | | 93 | char buf[128], buf2[8*sizeof(buf)]; |
94 | while (fgets(buf, sizeof(buf), f)) { | | 94 | while (fgets(buf, sizeof(buf), f)) { |
95 | char *s = strrchr(buf, '\n'); | | 95 | char *s = strrchr(buf, '\n'); |
96 | assert(s); | | 96 | assert(s); |
97 | assert(strlen(s)==1); | | 97 | assert(strlen(s)==1); |
98 | *s = 0; | | 98 | *s = 0; |
99 | | | 99 | |
100 | int i,j; | | 100 | int i,j; |
101 | for (i=j=0; buf[i]; i++) { | | 101 | for (i=j=0; buf[i]; i++) { |
102 | if (buf[i]=='\t') { | | 102 | if (buf[i]=='\t') { |
103 | buf2[j++] = ' '; | | 103 | buf2[j++] = ' '; |
104 | while (j%8) buf2[j++] = ' '; | | 104 | while (j%8) buf2[j++] = ' '; |
105 | } | | 105 | } |
106 | else if (buf[i]=='\b') { | | 106 | else if (buf[i]=='\b') { |
107 | if (j>0) j--; | | 107 | if (j>0) j--; |
108 | } | | 108 | } |
109 | else { | | 109 | else { |
110 | buf2[j++] = buf[i]; | | 110 | buf2[j++] = buf[i]; |
111 | } | | 111 | } |
112 | } | | 112 | } |
113 | buf2[j] = 0; | | 113 | buf2[j] = 0; |
114 | | | 114 | |
115 | stringarray_add(&lines, buf2); | | 115 | stringarray_add(&lines, buf2); |
116 | stringarray_add(&sollines, buf2); | | 116 | stringarray_add(&sollines, buf2); |
117 | } | | 117 | } |
118 | | | 118 | |
119 | pclose(f); | | 119 | pclose(f); |
120 | } | | 120 | } |
121 | | | 121 | |
122 | static void encode(void) { | | 122 | static void encode(void) { |
123 | int used[26]; | | | |
124 | for (int i=0; i<26; i++) used[i] = 0; | | | |
125 | | | | |
126 | int key[26]; | | 123 | int key[26]; |
127 | int keypos=0; | | 124 | for (int i=0; i<26; i++) key[i] = i; |
128 | while (keypos < 26) { | | 125 | for (int i=26; i>1; i--) { |
129 | int c = random()%26; | | 126 | int c = random() % i; |
130 | if (used[c]) continue; | | 127 | int t = key[i-1]; |
131 | key[keypos++] = c; | | 128 | key[i-1] = key[c]; |
132 | used[c] = 1; | | 129 | key[c] = t; |
133 | } | | 130 | } |
134 | | | 131 | |
135 | for (int y=0; y<lines.num; y++) { | | 132 | for (int y=0; y<lines.num; y++) { |
136 | for (unsigned x=0; lines.v[y][x]; x++) { | | 133 | for (unsigned x=0; lines.v[y][x]; x++) { |
137 | if (islower((unsigned char)lines.v[y][x])) { | | 134 | if (islower((unsigned char)lines.v[y][x])) { |
138 | int q = lines.v[y][x]-'a'; | | 135 | int q = lines.v[y][x]-'a'; |
139 | lines.v[y][x] = 'a'+key[q]; | | 136 | lines.v[y][x] = 'a'+key[q]; |
140 | } | | 137 | } |
141 | if (isupper((unsigned char)lines.v[y][x])) { | | 138 | if (isupper((unsigned char)lines.v[y][x])) { |
142 | int q = lines.v[y][x]-'A'; | | 139 | int q = lines.v[y][x]-'A'; |
143 | lines.v[y][x] = 'A'+key[q]; | | 140 | lines.v[y][x] = 'A'+key[q]; |
144 | } | | 141 | } |
145 | } | | 142 | } |
146 | } | | 143 | } |
147 | } | | 144 | } |
148 | | | 145 | |
149 | static int substitute(int ch) { | | 146 | static int substitute(int ch) { |
150 | assert(cury>=0 && cury<lines.num); | | 147 | assert(cury>=0 && cury<lines.num); |
151 | if (curx >= strlen(lines.v[cury])) { | | 148 | if (curx >= strlen(lines.v[cury])) { |
152 | beep(); | | 149 | beep(); |
153 | return -1; | | 150 | return -1; |
154 | } | | 151 | } |
155 | | | 152 | |
156 | int och = lines.v[cury][curx]; | | 153 | int och = lines.v[cury][curx]; |
157 | if (!isalpha((unsigned char)och)) { | | 154 | if (!isalpha((unsigned char)och)) { |
158 | beep(); | | 155 | beep(); |
159 | return -1; | | 156 | return -1; |
160 | } | | 157 | } |
161 | | | 158 | |
162 | int loch = tolower((unsigned char)och); | | 159 | int loch = tolower((unsigned char)och); |
163 | int uoch = toupper((unsigned char)och); | | 160 | int uoch = toupper((unsigned char)och); |
164 | int lch = tolower((unsigned char)ch); | | 161 | int lch = tolower((unsigned char)ch); |
165 | int uch = toupper((unsigned char)ch); | | 162 | int uch = toupper((unsigned char)ch); |
166 | | | 163 | |
167 | for (int y=0; y<lines.num; y++) { | | 164 | for (int y=0; y<lines.num; y++) { |
168 | for (unsigned x=0; lines.v[y][x]; x++) { | | 165 | for (unsigned x=0; lines.v[y][x]; x++) { |
169 | if (lines.v[y][x]==loch) { | | 166 | if (lines.v[y][x]==loch) { |
170 | lines.v[y][x] = lch; | | 167 | lines.v[y][x] = lch; |
171 | } | | 168 | } |
172 | else if (lines.v[y][x]==uoch) { | | 169 | else if (lines.v[y][x]==uoch) { |
173 | lines.v[y][x] = uch; | | 170 | lines.v[y][x] = uch; |
174 | } | | 171 | } |
175 | else if (lines.v[y][x]==lch) { | | 172 | else if (lines.v[y][x]==lch) { |
176 | lines.v[y][x] = loch; | | 173 | lines.v[y][x] = loch; |
177 | } | | 174 | } |
178 | else if (lines.v[y][x]==uch) { | | 175 | else if (lines.v[y][x]==uch) { |
179 | lines.v[y][x] = uoch; | | 176 | lines.v[y][x] = uoch; |
180 | } | | 177 | } |
181 | } | | 178 | } |
182 | } | | 179 | } |
183 | return 0; | | 180 | return 0; |
184 | } | | 181 | } |
185 | | | 182 | |
186 | //////////////////////////////////////////////////////////// | | 183 | //////////////////////////////////////////////////////////// |
187 | | | 184 | |
188 | static void redraw(void) { | | 185 | static void redraw(void) { |
189 | erase(); | | 186 | erase(); |
190 | bool won = true; | | 187 | bool won = true; |
191 | for (int i=0; i<LINES-1; i++) { | | 188 | for (int i=0; i<LINES-1; i++) { |
192 | move(i, 0); | | 189 | move(i, 0); |
193 | int ln = i+scrolldown; | | 190 | int ln = i+scrolldown; |
194 | if (ln < lines.num) { | | 191 | if (ln < lines.num) { |
195 | for (unsigned j=0; lines.v[i][j]; j++) { | | 192 | for (unsigned j=0; lines.v[i][j]; j++) { |
196 | int ch = lines.v[i][j]; | | 193 | int ch = lines.v[i][j]; |
197 | if (ch != sollines.v[i][j] && isalpha((unsigned char)ch)) { | | 194 | if (ch != sollines.v[i][j] && isalpha((unsigned char)ch)) { |
198 | won = false; | | 195 | won = false; |
199 | } | | 196 | } |
200 | bool bold=false; | | 197 | bool bold=false; |
201 | if (hinting && ch==sollines.v[i][j] && | | 198 | if (hinting && ch==sollines.v[i][j] && |
202 | isalpha((unsigned char)ch)) { | | 199 | isalpha((unsigned char)ch)) { |
203 | bold = true; | | 200 | bold = true; |
204 | attron(A_BOLD); | | 201 | attron(A_BOLD); |
205 | } | | 202 | } |
206 | addch(lines.v[i][j]); | | 203 | addch(lines.v[i][j]); |
207 | if (bold) { | | 204 | if (bold) { |
208 | attroff(A_BOLD); | | 205 | attroff(A_BOLD); |
209 | } | | 206 | } |
210 | } | | 207 | } |
211 | } | | 208 | } |
212 | clrtoeol(); | | 209 | clrtoeol(); |
213 | } | | 210 | } |
214 | | | 211 | |
215 | move(LINES-1, 0); | | 212 | move(LINES-1, 0); |
216 | if (won) { | | 213 | if (won) { |
217 | addstr("*solved* "); | | 214 | addstr("*solved* "); |
218 | } | | 215 | } |
219 | addstr("~ to quit, * to cheat, ^pnfb to move"); | | 216 | addstr("~ to quit, * to cheat, ^pnfb to move"); |
220 | | | 217 | |
221 | move(LINES-1, 0); | | 218 | move(LINES-1, 0); |
222 | | | 219 | |
223 | move(cury-scrolldown, curx); | | 220 | move(cury-scrolldown, curx); |
224 | | | 221 | |
225 | refresh(); | | 222 | refresh(); |
226 | } | | 223 | } |
227 | | | 224 | |
228 | static void opencurses(void) { | | 225 | static void opencurses(void) { |
229 | initscr(); | | 226 | initscr(); |
230 | cbreak(); | | 227 | cbreak(); |
231 | noecho(); | | 228 | noecho(); |
232 | } | | 229 | } |
233 | | | 230 | |
234 | static void closecurses(void) { | | 231 | static void closecurses(void) { |
235 | endwin(); | | 232 | endwin(); |
236 | } | | 233 | } |
237 | | | 234 | |
238 | //////////////////////////////////////////////////////////// | | 235 | //////////////////////////////////////////////////////////// |
239 | | | 236 | |
240 | static void loop(void) { | | 237 | static void loop(void) { |
241 | bool done=false; | | 238 | bool done=false; |
242 | while (!done) { | | 239 | while (!done) { |
243 | redraw(); | | 240 | redraw(); |
244 | int ch = getch(); | | 241 | int ch = getch(); |
245 | switch (ch) { | | 242 | switch (ch) { |
246 | case 1: /* ^A */ | | 243 | case 1: /* ^A */ |
| | | 244 | case KEY_BEG: |
247 | curx=0; | | 245 | curx=0; |
248 | break; | | 246 | break; |
249 | case 2: /* ^B */ | | 247 | case 2: /* ^B */ |
| | | 248 | case KEY_LEFT: |
250 | if (curx > 0) { | | 249 | if (curx > 0) { |
251 | curx--; | | 250 | curx--; |
252 | } | | 251 | } |
253 | else if (cury > 0) { | | 252 | else if (cury > 0) { |
254 | cury--; | | 253 | cury--; |
255 | curx = strlen(lines.v[cury]); | | 254 | curx = strlen(lines.v[cury]); |
256 | } | | 255 | } |
257 | break; | | 256 | break; |
258 | case 5: /* ^E */ | | 257 | case 5: /* ^E */ |
| | | 258 | case KEY_END: |
259 | curx = strlen(lines.v[cury]); | | 259 | curx = strlen(lines.v[cury]); |
260 | break; | | 260 | break; |
261 | case 6: /* ^F */ | | 261 | case 6: /* ^F */ |
| | | 262 | case KEY_RIGHT: |
262 | if (curx < strlen(lines.v[cury])) { | | 263 | if (curx < strlen(lines.v[cury])) { |
263 | curx++; | | 264 | curx++; |
264 | } | | 265 | } |
265 | else if (cury < lines.num - 1) { | | 266 | else if (cury < lines.num - 1) { |
266 | cury++; | | 267 | cury++; |
267 | curx = 0; | | 268 | curx = 0; |
268 | } | | 269 | } |
269 | break; | | 270 | break; |
270 | case 12: /* ^L */ | | 271 | case 12: /* ^L */ |
271 | clear(); | | 272 | clear(); |
272 | break; | | 273 | break; |
273 | case 14: /* ^N */ | | 274 | case 14: /* ^N */ |
| | | 275 | case KEY_DOWN: |
274 | if (cury < lines.num-1) { | | 276 | if (cury < lines.num-1) { |
275 | cury++; | | 277 | cury++; |
276 | } | | 278 | } |
277 | if (curx > strlen(lines.v[cury])) { | | 279 | if (curx > strlen(lines.v[cury])) { |
278 | curx = strlen(lines.v[cury]); | | 280 | curx = strlen(lines.v[cury]); |
279 | } | | 281 | } |
280 | if (scrolldown < cury - (LINES-2)) { | | 282 | if (scrolldown < cury - (LINES-2)) { |
281 | scrolldown = cury - (LINES-2); | | 283 | scrolldown = cury - (LINES-2); |
282 | } | | 284 | } |
283 | break; | | 285 | break; |
284 | case 16: /* ^P */ | | 286 | case 16: /* ^P */ |
| | | 287 | case KEY_UP: |
285 | if (cury > 0) { | | 288 | if (cury > 0) { |
286 | cury--; | | 289 | cury--; |
287 | } | | 290 | } |
288 | if (curx > strlen(lines.v[cury])) { | | 291 | if (curx > strlen(lines.v[cury])) { |
289 | curx = strlen(lines.v[cury]); | | 292 | curx = strlen(lines.v[cury]); |
290 | } | | 293 | } |
291 | if (scrolldown > cury) { | | 294 | if (scrolldown > cury) { |
292 | scrolldown = cury; | | 295 | scrolldown = cury; |
293 | } | | 296 | } |
294 | break; | | 297 | break; |
295 | case '*': | | 298 | case '*': |
296 | hinting = !hinting; | | 299 | hinting = !hinting; |
297 | break; | | 300 | break; |
298 | case '~': | | 301 | case '~': |
299 | done = true; | | 302 | done = true; |
300 | break; | | 303 | break; |
301 | default: | | 304 | default: |
302 | if (isalpha(ch)) { | | 305 | if (isalpha(ch)) { |
303 | if (!substitute(ch)) { | | 306 | if (!substitute(ch)) { |
304 | if (curx < strlen(lines.v[cury])) { | | 307 | if (curx < strlen(lines.v[cury])) { |
305 | curx++; | | 308 | curx++; |
306 | } | | 309 | } |
307 | if (curx==strlen(lines.v[cury]) && cury < lines.num-1) { | | 310 | if (curx==strlen(lines.v[cury]) && cury < lines.num-1) { |
308 | curx=0; | | 311 | curx=0; |
309 | cury++; | | 312 | cury++; |
310 | } | | 313 | } |
311 | } | | 314 | } |
312 | } | | 315 | } |
313 | else if (curx < strlen(lines.v[cury]) && ch==lines.v[cury][curx]) { | | 316 | else if (curx < strlen(lines.v[cury]) && ch==lines.v[cury][curx]) { |
314 | curx++; | | 317 | curx++; |
315 | if (curx==strlen(lines.v[cury]) && cury < lines.num-1) { | | 318 | if (curx==strlen(lines.v[cury]) && cury < lines.num-1) { |
316 | curx=0; | | 319 | curx=0; |
317 | cury++; | | 320 | cury++; |
318 | } | | 321 | } |
319 | } | | 322 | } |
320 | else { | | 323 | else { |
321 | beep(); | | 324 | beep(); |
322 | } | | 325 | } |
323 | break; | | 326 | break; |
324 | } | | 327 | } |
325 | } | | 328 | } |
326 | } | | 329 | } |
327 | | | 330 | |
328 | //////////////////////////////////////////////////////////// | | 331 | //////////////////////////////////////////////////////////// |
329 | | | 332 | |
330 | int main(void) { | | 333 | int main(void) { |
331 | stringarray_init(&lines); | | 334 | stringarray_init(&lines); |
332 | stringarray_init(&sollines); | | 335 | stringarray_init(&sollines); |
333 | srandom(time(NULL)); | | 336 | srandom(time(NULL)); |
334 | readquote(); | | 337 | readquote(); |
335 | encode(); | | 338 | encode(); |
336 | opencurses(); | | 339 | opencurses(); |
337 | | | 340 | |
| | | 341 | keypad(stdscr, TRUE); |
338 | loop(); | | 342 | loop(); |
339 | | | 343 | |
340 | closecurses(); | | 344 | closecurses(); |
341 | stringarray_cleanup(&sollines); | | 345 | stringarray_cleanup(&sollines); |
342 | stringarray_cleanup(&lines); | | 346 | stringarray_cleanup(&lines); |
343 | return 0; | | 347 | return 0; |
344 | } | | 348 | } |