1 /* vi: set tabstop=4 : */ 2 3 /* 4 * Terminal interface 5 * 6 * Input is raw and unechoed 7 */ 8 9 #ifdef unix 10 #include <sgtty.h> 11 #endif 12 #include <signal.h> 13 #include <curses.h> 14 #include <ctype.h> 15 #include <stdio.h> 16 17 #include "bog.h" 18 19 #ifdef ATARI 20 #include <osbind.h> 21 #endif 22 23 static int ccol, crow, maxw; 24 static int colstarts[MAXCOLS], ncolstarts; 25 static int lastline; 26 int ncols, nlines; 27 28 static int cont_catcher(), prwidth(), prword(), stop_catcher(), tty_cleanup(); 29 static int tty_setup(), tty_showboard(); 30 static int winch_catcher(); 31 32 extern int ngames, nmwords, npwords, tnmwords, tnpwords; 33 extern char *pword[], *mword[]; 34 35 /* 36 * Do system dependent initialization 37 * This is called once, when the program starts 38 */ 39 setup(sflag, seed) 40 int sflag; 41 long seed; 42 { 43 extern int debug; 44 45 if (tty_setup() < 0) 46 return(-1); 47 48 if (!sflag) 49 #ifdef ATARI 50 seed = Random(); 51 #else 52 time(&seed); 53 #endif 54 srandom(seed); 55 if (debug) 56 (void) printf("seed = %ld\n", seed); 57 return(0); 58 } 59 60 /* 61 * Do system dependent clean up 62 * This is called once, just before the program terminates 63 */ 64 cleanup() 65 { 66 67 tty_cleanup(); 68 } 69 70 /* 71 * Display the player's word list, the list of words not found, and the running 72 * stats 73 */ 74 results() 75 { 76 int col, row; 77 int denom1, denom2; 78 79 move(LIST_LINE, LIST_COL); 80 clrtobot(); 81 printw("Words you found (%d):", npwords); 82 refresh(); 83 move(LIST_LINE + 1, LIST_COL); 84 prtable(pword, npwords, 0, ncols, prword, prwidth); 85 86 getyx(stdscr, row, col); 87 move(row + 1, col); 88 printw("Words you missed (%d):", nmwords); 89 refresh(); 90 move(row + 2, col); 91 prtable(mword, nmwords, 0, ncols, prword, prwidth); 92 93 denom1 = npwords + nmwords; 94 denom2 = tnpwords + tnmwords; 95 96 move(SCORE_LINE, SCORE_COL); 97 printw("Percentage: %0.2f%% (%0.2f%% over %d game%s)\n", 98 denom1 ? (100.0 * npwords) / (double) (npwords + nmwords) : 0.0, 99 denom2 ? (100.0 * tnpwords) / (double) (tnpwords + tnmwords) : 0.0, 100 ngames, ngames > 1 ? "s" : ""); 101 } 102 103 static 104 prword(base, index) 105 char **base; 106 int index; 107 { 108 109 printw("%s", base[index]); 110 } 111 112 static 113 prwidth(base, index) 114 char **base; 115 int index; 116 { 117 118 return(strlen(base[index])); 119 } 120 121 /* 122 * Main input routine 123 * 124 * - doesn't accept words longer than MAXWORDLEN or containing caps 125 */ 126 char * 127 getline(q) 128 char *q; 129 { 130 register int ch, done; 131 register char *p; 132 int row, col; 133 134 p = q; 135 done = 0; 136 while (!done) { 137 ch = rawch(); 138 switch (ch) { 139 case '\n': 140 case '\r': 141 case ' ': 142 done = 1; 143 break; 144 case '\033': 145 findword(); 146 break; 147 case '\177': /* <del> */ 148 case '\010': /* <bs> */ 149 if (p == q) 150 break; 151 p--; 152 getyx(stdscr, row, col); 153 move(row, col - 1); 154 clrtoeol(); 155 refresh(); 156 break; 157 case '\025': /* <^u> */ 158 case '\027': /* <^w> */ 159 if (p == q) 160 break; 161 getyx(stdscr, row, col); 162 move(row, col - (int) (p - q)); 163 p = q; 164 clrtoeol(); 165 refresh(); 166 break; 167 #ifdef SIGTSTP 168 case '\032': /* <^z> */ 169 stop_catcher(); 170 break; 171 #endif 172 case '\023': /* <^s> */ 173 stoptime(); 174 printw("<PAUSE>"); 175 refresh(); 176 while ((ch = inputch()) != '\021' && ch != '\023') 177 ; 178 move(crow, ccol); 179 clrtoeol(); 180 refresh(); 181 starttime(); 182 break; 183 case '\003': /* <^c> */ 184 cleanup(); 185 exit(0); 186 /*NOTREACHED*/ 187 case '\004': /* <^d> */ 188 done = 1; 189 ch = EOF; 190 break; 191 case '\014': /* <^l> */ 192 case '\022': /* <^r> */ 193 redraw(); 194 break; 195 case '?': 196 stoptime(); 197 if (help() < 0) 198 showstr("Can't open help file", 1); 199 starttime(); 200 break; 201 default: 202 if (!islower(ch)) 203 break; 204 if ((int) (p - q) == MAXWORDLEN) { 205 p = q; 206 badword(); 207 break; 208 } 209 *p++ = ch; 210 addch(ch); 211 refresh(); 212 break; 213 } 214 } 215 *p = '\0'; 216 if (ch == EOF) 217 return((char *) NULL); 218 return(q); 219 } 220 221 inputch() 222 { 223 224 return(getch() & 0177); 225 } 226 227 redraw() 228 { 229 230 clearok(stdscr, 1); 231 refresh(); 232 } 233 234 #ifdef XXX 235 /* 236 * Flush all pending input 237 */ 238 flushin(fp) 239 FILE *fp; 240 { 241 242 flushinp(); 243 } 244 #endif XXX 245 246 #ifdef TIOCFLUSH 247 #include <sys/file.h> 248 249 flushin(fp) 250 FILE *fp; 251 { 252 int arg; 253 254 arg = FREAD; 255 (void) ioctl(fileno(fp), TIOCFLUSH, &arg); 256 } 257 #endif TIOCFLUSH 258 259 #ifdef ATARI 260 #include <osbind.h> 261 262 /*ARGSUSED*/ 263 flushin(fp) 264 FILE *fp; 265 { 266 267 while (Cconis() == -1) 268 getch(); 269 } 270 #endif ATARI 271 272 static int gone; 273 274 /* 275 * Stop the game timer 276 */ 277 stoptime() 278 { 279 long t; 280 extern long start_t; 281 282 time(&t); 283 gone = (int) (t - start_t); 284 } 285 286 /* 287 * Restart the game timer 288 */ 289 starttime() 290 { 291 long t; 292 extern long start_t; 293 294 time(&t); 295 start_t = t - (long) gone; 296 } 297 298 /* 299 * Initialize for the display of the player's words as they are typed 300 * This display starts at (LIST_LINE, LIST_COL) and goes "down" until the last 301 * line. After the last line a new column is started at LIST_LINE 302 * Keep track of each column position for showword() 303 * There is no check for exceeding COLS 304 */ 305 startwords() 306 { 307 308 crow = LIST_LINE; 309 ccol = LIST_COL; 310 maxw = 0; 311 ncolstarts = 1; 312 colstarts[0] = LIST_COL; 313 move(LIST_LINE, LIST_COL); 314 refresh(); 315 } 316 317 /* 318 * Add a word to the list and start a new column if necessary 319 * The maximum width of the current column is maintained so we know where 320 * to start the next column 321 */ 322 addword(w) 323 char *w; 324 { 325 int n; 326 327 if (crow == lastline) { 328 crow = LIST_LINE; 329 ccol += (maxw + 5); 330 colstarts[ncolstarts++] = ccol; 331 maxw = 0; 332 move(crow, ccol); 333 } 334 else { 335 move(++crow, ccol); 336 if ((n = strlen(w)) > maxw) 337 maxw = n; 338 } 339 refresh(); 340 } 341 342 /* 343 * The current word is unacceptable so erase it 344 */ 345 badword() 346 { 347 348 move(crow, ccol); 349 clrtoeol(); 350 refresh(); 351 } 352 353 /* 354 * Highlight the nth word in the list (starting with word 0) 355 * No check for wild arg 356 */ 357 showword(n) 358 int n; 359 { 360 int col, row; 361 362 row = LIST_LINE + n % (lastline - LIST_LINE + 1); 363 col = colstarts[n / (lastline - LIST_LINE + 1)]; 364 move(row, col); 365 standout(); 366 printw("%s", pword[n]); 367 standend(); 368 move(crow, ccol); 369 refresh(); 370 delay(15); 371 move(row, col); 372 printw("%s", pword[n]); 373 move(crow, ccol); 374 refresh(); 375 } 376 377 /* 378 * Get a word from the user and check if it is in either of the two 379 * word lists 380 * If it's found, show the word on the board for a short time and then 381 * erase the word 382 * 383 * Note: this function knows about the format of the board 384 */ 385 findword() 386 { 387 int c, col, found, i, r, row; 388 char buf[MAXWORDLEN + 1]; 389 extern char board[]; 390 extern int usedbits, wordpath[]; 391 extern char *mword[], *pword[]; 392 extern int nmwords, npwords; 393 394 getyx(stdscr, r, c); 395 getword(buf); 396 found = 0; 397 for (i = 0; i < npwords; i++) { 398 if (strcmp(buf, pword[i]) == 0) { 399 found = 1; 400 break; 401 } 402 } 403 if (!found) { 404 for (i = 0; i < nmwords; i++) { 405 if (strcmp(buf, mword[i]) == 0) { 406 found = 1; 407 break; 408 } 409 } 410 } 411 for (i = 0; i < MAXWORDLEN; i++) 412 wordpath[i] = -1; 413 usedbits = 0; 414 if (!found || checkword(buf, -1, wordpath) == -1) { 415 move(r, c); 416 clrtoeol(); 417 addstr("[???]"); 418 refresh(); 419 delay(10); 420 move(r, c); 421 clrtoeol(); 422 refresh(); 423 return; 424 } 425 426 standout(); 427 for (i = 0; wordpath[i] != -1; i++) { 428 row = BOARD_LINE + (wordpath[i] / 4) * 2 + 1; 429 col = BOARD_COL + (wordpath[i] % 4) * 4 + 2; 430 move(row, col); 431 if (board[wordpath[i]] == 'q') 432 printw("Qu"); 433 else 434 printw("%c", toupper(board[wordpath[i]])); 435 move(r, c); 436 refresh(); 437 delay(5); 438 } 439 440 standend(); 441 442 for (i = 0; wordpath[i] != -1; i++) { 443 row = BOARD_LINE + (wordpath[i] / 4) * 2 + 1; 444 col = BOARD_COL + (wordpath[i] % 4) * 4 + 2; 445 move(row, col); 446 if (board[wordpath[i]] == 'q') 447 printw("Qu"); 448 else 449 printw("%c", toupper(board[wordpath[i]])); 450 } 451 move(r, c); 452 clrtoeol(); 453 refresh(); 454 } 455 456 /* 457 * Display a string at the current cursor position for the given number of secs 458 */ 459 showstr(str, delaysecs) 460 char *str; 461 int delaysecs; 462 { 463 464 addstr(str); 465 refresh(); 466 delay(delaysecs * 10); 467 move(crow, ccol); 468 clrtoeol(); 469 refresh(); 470 } 471 472 putstr(s) 473 char *s; 474 { 475 476 addstr(s); 477 } 478 479 /* 480 * Get a valid word and put it in the buffer 481 */ 482 getword(q) 483 char *q; 484 { 485 int ch, col, done, i, row; 486 char *p; 487 488 done = 0; 489 i = 0; 490 p = q; 491 addch('['); 492 refresh(); 493 while (!done && i < MAXWORDLEN - 1) { 494 ch = getch() & 0177; 495 switch (ch) { 496 case '\177': /* <del> */ 497 case '\010': /* <bs> */ 498 if (p == q) 499 break; 500 p--; 501 getyx(stdscr, row, col); 502 move(row, col - 1); 503 clrtoeol(); 504 break; 505 case '\025': /* <^u> */ 506 case '\027': /* <^w> */ 507 if (p == q) 508 break; 509 getyx(stdscr, row, col); 510 move(row, col - (int) (p - q)); 511 p = q; 512 clrtoeol(); 513 break; 514 case ' ': 515 case '\n': 516 case '\r': 517 done = 1; 518 break; 519 case '\014': /* <^l> */ 520 case '\022': /* <^r> */ 521 clearok(stdscr, 1); 522 refresh(); 523 break; 524 default: 525 if (islower(ch)) { 526 *p++ = ch; 527 addch(ch); 528 i++; 529 } 530 break; 531 } 532 refresh(); 533 } 534 *p = '\0'; 535 addch(']'); 536 refresh(); 537 } 538 539 showboard(b) 540 char *b; 541 { 542 543 tty_showboard(b); 544 } 545 546 prompt(mesg) 547 char *mesg; 548 { 549 550 move(PROMPT_LINE, PROMPT_COL); 551 printw("%s", mesg); 552 move(PROMPT_LINE + 1, PROMPT_COL); 553 refresh(); 554 } 555 556 rawch() 557 { 558 559 #ifdef TIMER 560 return(timerch()); 561 #else 562 return(getch() & 0177); 563 #endif 564 } 565 566 static 567 tty_setup() 568 { 569 #ifdef SIGTSTP 570 int stop_catcher(), cont_catcher(); 571 #endif 572 #ifdef TIOCGWINSZ 573 int winch_catcher(); 574 #endif 575 576 initscr(); 577 raw(); 578 noecho(); 579 580 /* 581 * Does curses look at the winsize structure? 582 * Should handle SIGWINCH ... 583 */ 584 nlines = LINES; 585 lastline = nlines - 1; 586 ncols = COLS; 587 588 #ifdef SIGTSTP 589 (void) signal(SIGTSTP, stop_catcher); 590 (void) signal(SIGCONT, cont_catcher); 591 #endif 592 #ifdef TIOCGWINSZ 593 (void) signal(SIGWINCH, winch_catcher); 594 #endif 595 596 return(0); 597 } 598 599 #ifdef SIGTSTP 600 static 601 stop_catcher() 602 { 603 604 stoptime(); 605 noraw(); 606 echo(); 607 move(nlines - 1, 0); 608 refresh(); 609 610 (void) signal(SIGTSTP, SIG_DFL); 611 #ifdef BSD42 612 (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP-1))); 613 #endif 614 (void) kill(0, SIGTSTP); 615 (void) signal(SIGTSTP, stop_catcher); 616 } 617 618 static 619 cont_catcher() 620 { 621 622 (void) signal(SIGCONT, cont_catcher); 623 noecho(); 624 raw(); 625 clearok(stdscr, 1); 626 move(crow, ccol); 627 refresh(); 628 starttime(); 629 } 630 #endif SIGTSTP 631 632 #ifdef SIGWINCH 633 /* 634 * The signal is caught but nothing is done about it... 635 * It would mean reformatting the entire display 636 */ 637 static 638 winch_catcher() 639 { 640 641 struct winsize win; 642 643 (void) signal(SIGWINCH, winch_catcher); 644 (void) ioctl(fileno(stdout), TIOCGWINSZ, &win); 645 /* 646 LINES = win.ws_row; 647 COLS = win.ws_col; 648 */ 649 } 650 #endif 651 652 static 653 tty_cleanup() 654 { 655 656 move(nlines - 1, 0); 657 refresh(); 658 noraw(); 659 echo(); 660 endwin(); 661 } 662 663 static 664 tty_showboard(b) 665 char *b; 666 { 667 register int i; 668 int line; 669 670 clear(); 671 move(BOARD_LINE, BOARD_COL); 672 line = BOARD_LINE; 673 printw("+---+---+---+---+"); 674 move(++line, BOARD_COL); 675 for (i = 0; i < 16; i++) { 676 if (b[i] == 'q') 677 printw("| Qu"); 678 else 679 printw("| %c ", toupper(b[i])); 680 if ((i + 1) % 4 == 0) { 681 printw("|"); 682 move(++line, BOARD_COL); 683 printw("+---+---+---+---+"); 684 move(++line, BOARD_COL); 685 } 686 } 687 move(SCORE_LINE, SCORE_COL); 688 printw("Type '?' for help"); 689 refresh(); 690 } 691 692 static 693 tty_prompt(p) 694 char *p; 695 { 696 697 move(PROMPT_LINE, PROMPT_COL); 698 printw("%s", p); 699 clrtoeol(); 700 refresh(); 701 } 702 703