1*564d7699SAaron LI /* $NetBSD: cgram.c,v 1.11 2021/02/21 22:21:56 rillig Exp $ */ 2*564d7699SAaron LI 31efcf41bSAaron LI /*- 4*564d7699SAaron LI * Copyright (c) 2013, 2021 The NetBSD Foundation, Inc. 51efcf41bSAaron LI * All rights reserved. 61efcf41bSAaron LI * 71efcf41bSAaron LI * This code is derived from software contributed to The NetBSD Foundation 8*564d7699SAaron LI * by David A. Holland and Roland Illig. 91efcf41bSAaron LI * 101efcf41bSAaron LI * Redistribution and use in source and binary forms, with or without 111efcf41bSAaron LI * modification, are permitted provided that the following conditions 121efcf41bSAaron LI * are met: 131efcf41bSAaron LI * 1. Redistributions of source code must retain the above copyright 141efcf41bSAaron LI * notice, this list of conditions and the following disclaimer. 151efcf41bSAaron LI * 2. Redistributions in binary form must reproduce the above copyright 161efcf41bSAaron LI * notice, this list of conditions and the following disclaimer in the 171efcf41bSAaron LI * documentation and/or other materials provided with the distribution. 181efcf41bSAaron LI * 191efcf41bSAaron LI * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 201efcf41bSAaron LI * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 211efcf41bSAaron LI * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 221efcf41bSAaron LI * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231efcf41bSAaron LI * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241efcf41bSAaron LI * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251efcf41bSAaron LI * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261efcf41bSAaron LI * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271efcf41bSAaron LI * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281efcf41bSAaron LI * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291efcf41bSAaron LI * POSSIBILITY OF SUCH DAMAGE. 301efcf41bSAaron LI */ 311efcf41bSAaron LI 321efcf41bSAaron LI #include <assert.h> 33a22b106bSAaron LI #include <ctype.h> 341efcf41bSAaron LI #include <curses.h> 35*564d7699SAaron LI #include <err.h> 36*564d7699SAaron LI #include <stdbool.h> 37a22b106bSAaron LI #include <stdio.h> 38a22b106bSAaron LI #include <stdlib.h> 39a22b106bSAaron LI #include <string.h> 40a22b106bSAaron LI #include <time.h> 41a22b106bSAaron LI 421efcf41bSAaron LI #include "pathnames.h" 431efcf41bSAaron LI 441efcf41bSAaron LI //////////////////////////////////////////////////////////// 451efcf41bSAaron LI 46*564d7699SAaron LI static char 47*564d7699SAaron LI ch_toupper(char ch) 48a22b106bSAaron LI { 49*564d7699SAaron LI return (char)toupper((unsigned char)ch); 50*564d7699SAaron LI } 511efcf41bSAaron LI 52*564d7699SAaron LI static char 53*564d7699SAaron LI ch_tolower(char ch) 54*564d7699SAaron LI { 55*564d7699SAaron LI return (char)tolower((unsigned char)ch); 56*564d7699SAaron LI } 57a22b106bSAaron LI 58*564d7699SAaron LI static bool 59*564d7699SAaron LI ch_isalpha(char ch) 60*564d7699SAaron LI { 61*564d7699SAaron LI return isalpha((unsigned char)ch) != 0; 62*564d7699SAaron LI } 63*564d7699SAaron LI 64*564d7699SAaron LI static bool 65*564d7699SAaron LI ch_islower(char ch) 66*564d7699SAaron LI { 67*564d7699SAaron LI return islower((unsigned char)ch) != 0; 68*564d7699SAaron LI } 69*564d7699SAaron LI 70*564d7699SAaron LI static bool 71*564d7699SAaron LI ch_isupper(char ch) 72*564d7699SAaron LI { 73*564d7699SAaron LI return isupper((unsigned char)ch) != 0; 74*564d7699SAaron LI } 75*564d7699SAaron LI 76*564d7699SAaron LI static int 77*564d7699SAaron LI imax(int a, int b) 78*564d7699SAaron LI { 79*564d7699SAaron LI return a > b ? a : b; 80*564d7699SAaron LI } 81*564d7699SAaron LI 82*564d7699SAaron LI static int 83*564d7699SAaron LI imin(int a, int b) 84*564d7699SAaron LI { 85*564d7699SAaron LI return a < b ? a : b; 861efcf41bSAaron LI } 871efcf41bSAaron LI 881efcf41bSAaron LI //////////////////////////////////////////////////////////// 891efcf41bSAaron LI 90*564d7699SAaron LI struct string { 91*564d7699SAaron LI char *s; 92*564d7699SAaron LI size_t len; 93*564d7699SAaron LI size_t cap; 941efcf41bSAaron LI }; 951efcf41bSAaron LI 96*564d7699SAaron LI struct stringarray { 97*564d7699SAaron LI struct string *v; 98*564d7699SAaron LI size_t num; 99*564d7699SAaron LI }; 100*564d7699SAaron LI 101*564d7699SAaron LI static void 102*564d7699SAaron LI string_init(struct string *s) 103*564d7699SAaron LI { 104*564d7699SAaron LI s->s = NULL; 105*564d7699SAaron LI s->len = 0; 106*564d7699SAaron LI s->cap = 0; 107*564d7699SAaron LI } 108*564d7699SAaron LI 109*564d7699SAaron LI static void 110*564d7699SAaron LI string_add(struct string *s, char ch) 111*564d7699SAaron LI { 112*564d7699SAaron LI if (s->len >= s->cap) { 113*564d7699SAaron LI s->cap = 2 * s->cap + 16; 114*564d7699SAaron LI s->s = realloc(s->s, s->cap); 115*564d7699SAaron LI if (s->s == NULL) 116*564d7699SAaron LI errx(1, "Out of memory"); 117*564d7699SAaron LI } 118*564d7699SAaron LI s->s[s->len++] = ch; 119*564d7699SAaron LI } 120*564d7699SAaron LI 121*564d7699SAaron LI static void 122*564d7699SAaron LI string_finish(struct string *s) 123*564d7699SAaron LI { 124*564d7699SAaron LI string_add(s, '\0'); 125*564d7699SAaron LI s->len--; 126*564d7699SAaron LI } 127*564d7699SAaron LI 128a22b106bSAaron LI static void 129a22b106bSAaron LI stringarray_init(struct stringarray *a) 130a22b106bSAaron LI { 1311efcf41bSAaron LI a->v = NULL; 1321efcf41bSAaron LI a->num = 0; 1331efcf41bSAaron LI } 1341efcf41bSAaron LI 135a22b106bSAaron LI static void 136a22b106bSAaron LI stringarray_cleanup(struct stringarray *a) 137a22b106bSAaron LI { 138*564d7699SAaron LI for (size_t i = 0; i < a->num; i++) 139*564d7699SAaron LI free(a->v[i].s); 1401efcf41bSAaron LI free(a->v); 1411efcf41bSAaron LI } 1421efcf41bSAaron LI 143a22b106bSAaron LI static void 144*564d7699SAaron LI stringarray_add(struct stringarray *a, struct string *s) 145a22b106bSAaron LI { 146*564d7699SAaron LI size_t num = a->num++; 147*564d7699SAaron LI a->v = realloc(a->v, a->num * sizeof a->v[0]); 148a22b106bSAaron LI if (a->v == NULL) 1491efcf41bSAaron LI errx(1, "Out of memory"); 150*564d7699SAaron LI a->v[num] = *s; 151*564d7699SAaron LI } 152a22b106bSAaron LI 153*564d7699SAaron LI static void 154*564d7699SAaron LI stringarray_dup(struct stringarray *dst, const struct stringarray *src) 155*564d7699SAaron LI { 156*564d7699SAaron LI assert(dst->num == 0); 157*564d7699SAaron LI for (size_t i = 0; i < src->num; i++) { 158*564d7699SAaron LI struct string str; 159*564d7699SAaron LI string_init(&str); 160*564d7699SAaron LI for (const char *p = src->v[i].s; *p != '\0'; p++) 161*564d7699SAaron LI string_add(&str, *p); 162*564d7699SAaron LI string_finish(&str); 163*564d7699SAaron LI stringarray_add(dst, &str); 164*564d7699SAaron LI } 1651efcf41bSAaron LI } 1661efcf41bSAaron LI 1671efcf41bSAaron LI //////////////////////////////////////////////////////////// 1681efcf41bSAaron LI 1691efcf41bSAaron LI static struct stringarray lines; 1701efcf41bSAaron LI static struct stringarray sollines; 1711efcf41bSAaron LI static bool hinting; 172*564d7699SAaron LI static int extent_x; 173*564d7699SAaron LI static int extent_y; 174*564d7699SAaron LI static int offset_x; 175*564d7699SAaron LI static int offset_y; 176*564d7699SAaron LI static int cursor_x; 177*564d7699SAaron LI static int cursor_y; 178*564d7699SAaron LI 179*564d7699SAaron LI static int 180*564d7699SAaron LI cur_max_x(void) 181*564d7699SAaron LI { 182*564d7699SAaron LI return (int)lines.v[cursor_y].len; 183*564d7699SAaron LI } 184*564d7699SAaron LI 185*564d7699SAaron LI static int 186*564d7699SAaron LI cur_max_y(void) 187*564d7699SAaron LI { 188*564d7699SAaron LI return extent_y - 1; 189*564d7699SAaron LI } 1901efcf41bSAaron LI 191a22b106bSAaron LI static void 192a22b106bSAaron LI readquote(void) 193a22b106bSAaron LI { 1941efcf41bSAaron LI FILE *f = popen(_PATH_FORTUNE, "r"); 195*564d7699SAaron LI if (f == NULL) 1961efcf41bSAaron LI err(1, "%s", _PATH_FORTUNE); 1971efcf41bSAaron LI 198*564d7699SAaron LI struct string line; 199*564d7699SAaron LI string_init(&line); 2001efcf41bSAaron LI 201*564d7699SAaron LI int ch; 202*564d7699SAaron LI while ((ch = fgetc(f)) != EOF) { 203*564d7699SAaron LI if (ch == '\n') { 204*564d7699SAaron LI string_finish(&line); 205*564d7699SAaron LI stringarray_add(&lines, &line); 206*564d7699SAaron LI string_init(&line); 207*564d7699SAaron LI } else if (ch == '\t') { 208*564d7699SAaron LI string_add(&line, ' '); 209*564d7699SAaron LI while (line.len % 8 != 0) 210*564d7699SAaron LI string_add(&line, ' '); 211*564d7699SAaron LI } else if (ch == '\b') { 212*564d7699SAaron LI if (line.len > 0) 213*564d7699SAaron LI line.len--; 214a22b106bSAaron LI } else { 215*564d7699SAaron LI string_add(&line, (char)ch); 2161efcf41bSAaron LI } 2171efcf41bSAaron LI } 2181efcf41bSAaron LI 219*564d7699SAaron LI stringarray_dup(&sollines, &lines); 220*564d7699SAaron LI 221*564d7699SAaron LI extent_y = (int)lines.num; 222*564d7699SAaron LI for (int i = 0; i < extent_y; i++) 223*564d7699SAaron LI extent_x = imax(extent_x, (int)lines.v[i].len); 2241efcf41bSAaron LI 2251efcf41bSAaron LI pclose(f); 2261efcf41bSAaron LI } 2271efcf41bSAaron LI 228a22b106bSAaron LI static void 229a22b106bSAaron LI encode(void) 230a22b106bSAaron LI { 2311efcf41bSAaron LI int key[26]; 232a22b106bSAaron LI 233a22b106bSAaron LI for (int i = 0; i < 26; i++) 234a22b106bSAaron LI key[i] = i; 235*564d7699SAaron LI 2361efcf41bSAaron LI for (int i = 26; i > 1; i--) { 237*564d7699SAaron LI int c = (int)(random() % i); 2381efcf41bSAaron LI int t = key[i - 1]; 2391efcf41bSAaron LI key[i - 1] = key[c]; 2401efcf41bSAaron LI key[c] = t; 2411efcf41bSAaron LI } 2421efcf41bSAaron LI 243*564d7699SAaron LI for (int y = 0; y < extent_y; y++) { 244*564d7699SAaron LI for (char *p = lines.v[y].s; *p != '\0'; p++) { 245*564d7699SAaron LI if (ch_islower(*p)) 246*564d7699SAaron LI *p = (char)('a' + key[*p - 'a']); 247*564d7699SAaron LI if (ch_isupper(*p)) 248*564d7699SAaron LI *p = (char)('A' + key[*p - 'A']); 2491efcf41bSAaron LI } 2501efcf41bSAaron LI } 2511efcf41bSAaron LI } 2521efcf41bSAaron LI 253*564d7699SAaron LI static bool 254*564d7699SAaron LI substitute(char ch) 255a22b106bSAaron LI { 256*564d7699SAaron LI assert(cursor_x >= 0 && cursor_x < extent_x); 257*564d7699SAaron LI assert(cursor_y >= 0 && cursor_y < extent_y); 258*564d7699SAaron LI if (cursor_x >= cur_max_x()) { 2591efcf41bSAaron LI beep(); 260*564d7699SAaron LI return false; 2611efcf41bSAaron LI } 2621efcf41bSAaron LI 263*564d7699SAaron LI char och = lines.v[cursor_y].s[cursor_x]; 264*564d7699SAaron LI if (!ch_isalpha(och)) { 2651efcf41bSAaron LI beep(); 266*564d7699SAaron LI return false; 2671efcf41bSAaron LI } 2681efcf41bSAaron LI 269*564d7699SAaron LI char loch = ch_tolower(och); 270*564d7699SAaron LI char uoch = ch_toupper(och); 271*564d7699SAaron LI char lch = ch_tolower(ch); 272*564d7699SAaron LI char uch = ch_toupper(ch); 2731efcf41bSAaron LI 274*564d7699SAaron LI for (int y = 0; y < (int)lines.num; y++) { 275*564d7699SAaron LI for (char *p = lines.v[y].s; *p != '\0'; p++) { 276*564d7699SAaron LI if (*p == loch) 277*564d7699SAaron LI *p = lch; 278*564d7699SAaron LI else if (*p == uoch) 279*564d7699SAaron LI *p = uch; 280*564d7699SAaron LI else if (*p == lch) 281*564d7699SAaron LI *p = loch; 282*564d7699SAaron LI else if (*p == uch) 283*564d7699SAaron LI *p = uoch; 2841efcf41bSAaron LI } 2851efcf41bSAaron LI } 286*564d7699SAaron LI return true; 2871efcf41bSAaron LI } 2881efcf41bSAaron LI 2891efcf41bSAaron LI //////////////////////////////////////////////////////////// 2901efcf41bSAaron LI 291*564d7699SAaron LI static bool 292*564d7699SAaron LI is_solved(void) 293*564d7699SAaron LI { 294*564d7699SAaron LI for (size_t i = 0; i < lines.num; i++) 295*564d7699SAaron LI if (strcmp(lines.v[i].s, sollines.v[i].s) != 0) 296*564d7699SAaron LI return false; 297*564d7699SAaron LI return true; 298*564d7699SAaron LI } 299*564d7699SAaron LI 300a22b106bSAaron LI static void 301a22b106bSAaron LI redraw(void) 302a22b106bSAaron LI { 3031efcf41bSAaron LI erase(); 304a22b106bSAaron LI 305*564d7699SAaron LI int max_y = imin(LINES - 1, extent_y - offset_y); 306*564d7699SAaron LI for (int y = 0; y < max_y; y++) { 307*564d7699SAaron LI move(y, 0); 308d60ecdb4SAaron LI 309*564d7699SAaron LI int len = (int)lines.v[offset_y + y].len; 310*564d7699SAaron LI int max_x = imin(COLS - 1, len - offset_x); 311*564d7699SAaron LI const char *line = lines.v[offset_y + y].s; 312*564d7699SAaron LI const char *solline = sollines.v[offset_y + y].s; 313d60ecdb4SAaron LI 314*564d7699SAaron LI for (int x = 0; x < max_x; x++) { 315*564d7699SAaron LI char ch = line[offset_x + x]; 316*564d7699SAaron LI bool bold = hinting && 317*564d7699SAaron LI ch == solline[offset_x + x] && 318*564d7699SAaron LI ch_isalpha(ch); 319*564d7699SAaron LI 320*564d7699SAaron LI if (bold) 321*564d7699SAaron LI attron(A_BOLD); 322*564d7699SAaron LI addch(ch); 323*564d7699SAaron LI if (bold) 324*564d7699SAaron LI attroff(A_BOLD); 3251efcf41bSAaron LI } 3261efcf41bSAaron LI clrtoeol(); 3271efcf41bSAaron LI } 3281efcf41bSAaron LI 3291efcf41bSAaron LI move(LINES - 1, 0); 330*564d7699SAaron LI if (is_solved()) 3311efcf41bSAaron LI addstr("*solved* "); 3321efcf41bSAaron LI addstr("~ to quit, * to cheat, ^pnfb to move"); 3331efcf41bSAaron LI 334*564d7699SAaron LI move(cursor_y - offset_y, cursor_x - offset_x); 3351efcf41bSAaron LI 3361efcf41bSAaron LI refresh(); 3371efcf41bSAaron LI } 3381efcf41bSAaron LI 339a22b106bSAaron LI static void 340a22b106bSAaron LI opencurses(void) 341a22b106bSAaron LI { 3421efcf41bSAaron LI initscr(); 3431efcf41bSAaron LI cbreak(); 3441efcf41bSAaron LI noecho(); 345*564d7699SAaron LI keypad(stdscr, true); 3461efcf41bSAaron LI } 3471efcf41bSAaron LI 348a22b106bSAaron LI static void 349a22b106bSAaron LI closecurses(void) 350a22b106bSAaron LI { 3511efcf41bSAaron LI endwin(); 3521efcf41bSAaron LI } 3531efcf41bSAaron LI 3541efcf41bSAaron LI //////////////////////////////////////////////////////////// 3551efcf41bSAaron LI 356a22b106bSAaron LI static void 357*564d7699SAaron LI saturate_cursor(void) 358a22b106bSAaron LI { 359*564d7699SAaron LI cursor_y = imax(cursor_y, 0); 360*564d7699SAaron LI cursor_y = imin(cursor_y, cur_max_y()); 361a22b106bSAaron LI 362*564d7699SAaron LI assert(cursor_x >= 0); 363*564d7699SAaron LI cursor_x = imin(cursor_x, cur_max_x()); 364*564d7699SAaron LI } 365a22b106bSAaron LI 366*564d7699SAaron LI static void 367*564d7699SAaron LI scroll_into_view(void) 368*564d7699SAaron LI { 369*564d7699SAaron LI if (cursor_x < offset_x) 370*564d7699SAaron LI offset_x = cursor_x; 371*564d7699SAaron LI if (cursor_x > offset_x + COLS - 1) 372*564d7699SAaron LI offset_x = cursor_x - (COLS - 1); 373*564d7699SAaron LI 374*564d7699SAaron LI if (cursor_y < offset_y) 375*564d7699SAaron LI offset_y = cursor_y; 376*564d7699SAaron LI if (cursor_y > offset_y + LINES - 2) 377*564d7699SAaron LI offset_y = cursor_y - (LINES - 2); 378*564d7699SAaron LI } 379*564d7699SAaron LI 380*564d7699SAaron LI static void 381*564d7699SAaron LI handle_char_input(int ch) 382*564d7699SAaron LI { 383*564d7699SAaron LI if (isascii(ch) && ch_isalpha((char)ch)) { 384*564d7699SAaron LI if (substitute((char)ch)) { 385*564d7699SAaron LI if (cursor_x < cur_max_x()) 386*564d7699SAaron LI cursor_x++; 387*564d7699SAaron LI if (cursor_x == cur_max_x() && 388*564d7699SAaron LI cursor_y < cur_max_y()) { 389*564d7699SAaron LI cursor_x = 0; 390*564d7699SAaron LI cursor_y++; 391*564d7699SAaron LI } 392*564d7699SAaron LI } 393*564d7699SAaron LI } else if (cursor_x < cur_max_x() && 394*564d7699SAaron LI ch == lines.v[cursor_y].s[cursor_x]) { 395*564d7699SAaron LI cursor_x++; 396*564d7699SAaron LI if (cursor_x == cur_max_x() && 397*564d7699SAaron LI cursor_y < cur_max_y()) { 398*564d7699SAaron LI cursor_x = 0; 399*564d7699SAaron LI cursor_y++; 400*564d7699SAaron LI } 401*564d7699SAaron LI } else { 402*564d7699SAaron LI beep(); 403*564d7699SAaron LI } 404*564d7699SAaron LI } 405*564d7699SAaron LI 406*564d7699SAaron LI static bool 407*564d7699SAaron LI handle_key(void) 408*564d7699SAaron LI { 4091efcf41bSAaron LI int ch = getch(); 410*564d7699SAaron LI 4111efcf41bSAaron LI switch (ch) { 4121efcf41bSAaron LI case 1: /* ^A */ 413359c8e75SAaron LI case KEY_HOME: 414*564d7699SAaron LI cursor_x = 0; 4151efcf41bSAaron LI break; 4161efcf41bSAaron LI case 2: /* ^B */ 4171efcf41bSAaron LI case KEY_LEFT: 418*564d7699SAaron LI if (cursor_x > 0) { 419*564d7699SAaron LI cursor_x--; 420*564d7699SAaron LI } else if (cursor_y > 0) { 421*564d7699SAaron LI cursor_y--; 422*564d7699SAaron LI cursor_x = cur_max_x(); 4231efcf41bSAaron LI } 4241efcf41bSAaron LI break; 4251efcf41bSAaron LI case 5: /* ^E */ 4261efcf41bSAaron LI case KEY_END: 427*564d7699SAaron LI cursor_x = cur_max_x(); 4281efcf41bSAaron LI break; 4291efcf41bSAaron LI case 6: /* ^F */ 4301efcf41bSAaron LI case KEY_RIGHT: 431*564d7699SAaron LI if (cursor_x < cur_max_x()) { 432*564d7699SAaron LI cursor_x++; 433*564d7699SAaron LI } else if (cursor_y < cur_max_y()) { 434*564d7699SAaron LI cursor_y++; 435*564d7699SAaron LI cursor_x = 0; 4361efcf41bSAaron LI } 4371efcf41bSAaron LI break; 4381efcf41bSAaron LI case 12: /* ^L */ 4391efcf41bSAaron LI clear(); 4401efcf41bSAaron LI break; 4411efcf41bSAaron LI case 14: /* ^N */ 4421efcf41bSAaron LI case KEY_DOWN: 443*564d7699SAaron LI cursor_y++; 4441efcf41bSAaron LI break; 4451efcf41bSAaron LI case 16: /* ^P */ 4461efcf41bSAaron LI case KEY_UP: 447*564d7699SAaron LI cursor_y--; 448*564d7699SAaron LI break; 449*564d7699SAaron LI case KEY_PPAGE: 450*564d7699SAaron LI cursor_y -= LINES - 2; 451*564d7699SAaron LI break; 452*564d7699SAaron LI case KEY_NPAGE: 453*564d7699SAaron LI cursor_y += LINES - 2; 4541efcf41bSAaron LI break; 4551efcf41bSAaron LI case '*': 4561efcf41bSAaron LI hinting = !hinting; 4571efcf41bSAaron LI break; 4581efcf41bSAaron LI case '~': 459*564d7699SAaron LI return false; 4601efcf41bSAaron LI default: 461*564d7699SAaron LI handle_char_input(ch); 4621efcf41bSAaron LI break; 4631efcf41bSAaron LI } 464*564d7699SAaron LI return true; 4651efcf41bSAaron LI } 466*564d7699SAaron LI 467*564d7699SAaron LI static void 468*564d7699SAaron LI init(void) 469*564d7699SAaron LI { 470*564d7699SAaron LI stringarray_init(&lines); 471*564d7699SAaron LI stringarray_init(&sollines); 472*564d7699SAaron LI srandom((unsigned int)time(NULL)); 473*564d7699SAaron LI readquote(); 474*564d7699SAaron LI encode(); 475*564d7699SAaron LI opencurses(); 476*564d7699SAaron LI } 477*564d7699SAaron LI 478*564d7699SAaron LI static void 479*564d7699SAaron LI loop(void) 480*564d7699SAaron LI { 481*564d7699SAaron LI for (;;) { 482*564d7699SAaron LI redraw(); 483*564d7699SAaron LI if (!handle_key()) 484*564d7699SAaron LI break; 485*564d7699SAaron LI saturate_cursor(); 486*564d7699SAaron LI scroll_into_view(); 487*564d7699SAaron LI } 488*564d7699SAaron LI } 489*564d7699SAaron LI 490*564d7699SAaron LI static void 491*564d7699SAaron LI clean_up(void) 492*564d7699SAaron LI { 493*564d7699SAaron LI closecurses(); 494*564d7699SAaron LI stringarray_cleanup(&sollines); 495*564d7699SAaron LI stringarray_cleanup(&lines); 4961efcf41bSAaron LI } 4971efcf41bSAaron LI 4981efcf41bSAaron LI //////////////////////////////////////////////////////////// 4991efcf41bSAaron LI 500a22b106bSAaron LI int 501a22b106bSAaron LI main(void) 502a22b106bSAaron LI { 503*564d7699SAaron LI init(); 5041efcf41bSAaron LI loop(); 505*564d7699SAaron LI clean_up(); 5061efcf41bSAaron LI } 507