1 /*- 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 05/31/93"; 10 #endif /* not lint */ 11 12 #include <ctype.h> 13 #include <curses.h> 14 #include <signal.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <termios.h> 18 #include <unistd.h> 19 20 #if __STDC__ 21 #include <stdarg.h> 22 #else 23 #include <varargs.h> 24 #endif 25 26 #include "deck.h" 27 #include "cribbage.h" 28 #include "cribcur.h" 29 30 #define LINESIZE 128 31 32 #ifdef CTRL 33 #undef CTRL 34 #endif 35 #define CTRL(X) (X - 'A' + 1) 36 37 char linebuf[LINESIZE]; 38 39 char *rankname[RANKS] = { 40 "ACE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", 41 "EIGHT", "NINE", "TEN", "JACK", "QUEEN", "KING" 42 }; 43 44 char *rankchar[RANKS] = { 45 "A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K" 46 }; 47 48 char *suitname[SUITS] = {"SPADES", "HEARTS", "DIAMONDS", "CLUBS"}; 49 50 char *suitchar[SUITS] = {"S", "H", "D", "C"}; 51 52 /* 53 * msgcard: 54 * Call msgcrd in one of two forms 55 */ 56 int 57 msgcard(c, brief) 58 CARD c; 59 BOOLEAN brief; 60 { 61 if (brief) 62 return (msgcrd(c, TRUE, NULL, TRUE)); 63 else 64 return (msgcrd(c, FALSE, " of ", FALSE)); 65 } 66 67 /* 68 * msgcrd: 69 * Print the value of a card in ascii 70 */ 71 int 72 msgcrd(c, brfrank, mid, brfsuit) 73 CARD c; 74 BOOLEAN brfrank, brfsuit; 75 char *mid; 76 { 77 if (c.rank == EMPTY || c.suit == EMPTY) 78 return (FALSE); 79 if (brfrank) 80 addmsg("%1.1s", rankchar[c.rank]); 81 else 82 addmsg(rankname[c.rank]); 83 if (mid != NULL) 84 addmsg(mid); 85 if (brfsuit) 86 addmsg("%1.1s", suitchar[c.suit]); 87 else 88 addmsg(suitname[c.suit]); 89 return (TRUE); 90 } 91 92 /* 93 * printcard: 94 * Print out a card. 95 */ 96 void 97 printcard(win, cardno, c, blank) 98 WINDOW *win; 99 int cardno; 100 CARD c; 101 BOOLEAN blank; 102 { 103 prcard(win, cardno * 2, cardno, c, blank); 104 } 105 106 /* 107 * prcard: 108 * Print out a card on the window at the specified location 109 */ 110 void 111 prcard(win, y, x, c, blank) 112 WINDOW *win; 113 int y, x; 114 CARD c; 115 BOOLEAN blank; 116 { 117 if (c.rank == EMPTY) 118 return; 119 120 mvwaddstr(win, y + 0, x, "+-----+"); 121 mvwaddstr(win, y + 1, x, "| |"); 122 mvwaddstr(win, y + 2, x, "| |"); 123 mvwaddstr(win, y + 3, x, "| |"); 124 mvwaddstr(win, y + 4, x, "+-----+"); 125 if (!blank) { 126 mvwaddch(win, y + 1, x + 1, rankchar[c.rank][0]); 127 waddch(win, suitchar[c.suit][0]); 128 mvwaddch(win, y + 3, x + 4, rankchar[c.rank][0]); 129 waddch(win, suitchar[c.suit][0]); 130 } 131 } 132 133 /* 134 * prhand: 135 * Print a hand of n cards 136 */ 137 void 138 prhand(h, n, win, blank) 139 CARD h[]; 140 int n; 141 WINDOW *win; 142 BOOLEAN blank; 143 { 144 register int i; 145 146 werase(win); 147 for (i = 0; i < n; i++) 148 printcard(win, i, *h++, blank); 149 wrefresh(win); 150 } 151 152 /* 153 * infrom: 154 * reads a card, supposedly in hand, accepting unambigous brief 155 * input, returns the index of the card found... 156 */ 157 int 158 infrom(hand, n, prompt) 159 CARD hand[]; 160 int n; 161 char *prompt; 162 { 163 register int i, j; 164 CARD crd; 165 166 if (n < 1) { 167 printf("\nINFROM: %d = n < 1!!\n", n); 168 exit(74); 169 } 170 for (;;) { 171 msg(prompt); 172 if (incard(&crd)) { /* if card is full card */ 173 if (!isone(crd, hand, n)) 174 msg("That's not in your hand"); 175 else { 176 for (i = 0; i < n; i++) 177 if (hand[i].rank == crd.rank && 178 hand[i].suit == crd.suit) 179 break; 180 if (i >= n) { 181 printf("\nINFROM: isone or something messed up\n"); 182 exit(77); 183 } 184 return (i); 185 } 186 } else /* if not full card... */ 187 if (crd.rank != EMPTY) { 188 for (i = 0; i < n; i++) 189 if (hand[i].rank == crd.rank) 190 break; 191 if (i >= n) 192 msg("No such rank in your hand"); 193 else { 194 for (j = i + 1; j < n; j++) 195 if (hand[j].rank == crd.rank) 196 break; 197 if (j < n) 198 msg("Ambiguous rank"); 199 else 200 return (i); 201 } 202 } else 203 msg("Sorry, I missed that"); 204 } 205 /* NOTREACHED */ 206 } 207 208 /* 209 * incard: 210 * Inputs a card in any format. It reads a line ending with a CR 211 * and then parses it. 212 */ 213 int 214 incard(crd) 215 CARD *crd; 216 { 217 register int i; 218 int rnk, sut; 219 char *line, *p, *p1; 220 BOOLEAN retval; 221 222 retval = FALSE; 223 rnk = sut = EMPTY; 224 if (!(line = getline())) 225 goto gotit; 226 p = p1 = line; 227 while (*p1 != ' ' && *p1 != NULL) 228 ++p1; 229 *p1++ = NULL; 230 if (*p == NULL) 231 goto gotit; 232 233 /* IMPORTANT: no real card has 2 char first name */ 234 if (strlen(p) == 2) { /* check for short form */ 235 rnk = EMPTY; 236 for (i = 0; i < RANKS; i++) { 237 if (*p == *rankchar[i]) { 238 rnk = i; 239 break; 240 } 241 } 242 if (rnk == EMPTY) 243 goto gotit; /* it's nothing... */ 244 ++p; /* advance to next char */ 245 sut = EMPTY; 246 for (i = 0; i < SUITS; i++) { 247 if (*p == *suitchar[i]) { 248 sut = i; 249 break; 250 } 251 } 252 if (sut != EMPTY) 253 retval = TRUE; 254 goto gotit; 255 } 256 rnk = EMPTY; 257 for (i = 0; i < RANKS; i++) { 258 if (!strcmp(p, rankname[i]) || !strcmp(p, rankchar[i])) { 259 rnk = i; 260 break; 261 } 262 } 263 if (rnk == EMPTY) 264 goto gotit; 265 p = p1; 266 while (*p1 != ' ' && *p1 != NULL) 267 ++p1; 268 *p1++ = NULL; 269 if (*p == NULL) 270 goto gotit; 271 if (!strcmp("OF", p)) { 272 p = p1; 273 while (*p1 != ' ' && *p1 != NULL) 274 ++p1; 275 *p1++ = NULL; 276 if (*p == NULL) 277 goto gotit; 278 } 279 sut = EMPTY; 280 for (i = 0; i < SUITS; i++) { 281 if (!strcmp(p, suitname[i]) || !strcmp(p, suitchar[i])) { 282 sut = i; 283 break; 284 } 285 } 286 if (sut != EMPTY) 287 retval = TRUE; 288 gotit: 289 (*crd).rank = rnk; 290 (*crd).suit = sut; 291 return (retval); 292 } 293 294 /* 295 * getuchar: 296 * Reads and converts to upper case 297 */ 298 int 299 getuchar() 300 { 301 register int c; 302 303 c = readchar(); 304 if (islower(c)) 305 c = toupper(c); 306 waddch(Msgwin, c); 307 return (c); 308 } 309 310 /* 311 * number: 312 * Reads in a decimal number and makes sure it is between "lo" and 313 * "hi" inclusive. 314 */ 315 int 316 number(lo, hi, prompt) 317 int lo, hi; 318 char *prompt; 319 { 320 register char *p; 321 register int sum; 322 323 for (sum = 0;;) { 324 msg(prompt); 325 if (!(p = getline()) || *p == NULL) { 326 msg(quiet ? "Not a number" : 327 "That doesn't look like a number"); 328 continue; 329 } 330 sum = 0; 331 332 if (!isdigit(*p)) 333 sum = lo - 1; 334 else 335 while (isdigit(*p)) { 336 sum = 10 * sum + (*p - '0'); 337 ++p; 338 } 339 340 if (*p != ' ' && *p != '\t' && *p != NULL) 341 sum = lo - 1; 342 if (sum >= lo && sum <= hi) 343 break; 344 if (sum == lo - 1) 345 msg("that doesn't look like a number, try again --> "); 346 else 347 msg("%d is not between %d and %d inclusive, try again --> ", 348 sum, lo, hi); 349 } 350 return (sum); 351 } 352 353 /* 354 * msg: 355 * Display a message at the top of the screen. 356 */ 357 char Msgbuf[BUFSIZ] = {'\0'}; 358 int Mpos = 0; 359 static int Newpos = 0; 360 361 void 362 #if __STDC__ 363 msg(const char *fmt, ...) 364 #else 365 msg(fmt, va_alist) 366 char *fmt; 367 va_dcl 368 #endif 369 { 370 va_list ap; 371 372 #if __STDC__ 373 va_start(ap, fmt); 374 #else 375 va_start(ap); 376 #endif 377 (void)vsprintf(&Msgbuf[Newpos], fmt, ap); 378 va_end(ap); 379 endmsg(); 380 } 381 382 /* 383 * addmsg: 384 * Add things to the current message 385 */ 386 void 387 #if __STDC__ 388 addmsg(const char *fmt, ...) 389 #else 390 addmsg(fmt, va_alist) 391 char *fmt; 392 va_dcl 393 #endif 394 { 395 va_list ap; 396 397 #if __STDC__ 398 va_start(ap, fmt); 399 #else 400 va_start(ap); 401 #endif 402 (void)vsprintf(&Msgbuf[Newpos], fmt, ap); 403 va_end(ap); 404 } 405 406 /* 407 * endmsg: 408 * Display a new msg. 409 */ 410 int Lineno = 0; 411 412 void 413 endmsg() 414 { 415 static int lastline = 0; 416 register int len; 417 register char *mp, *omp; 418 419 /* All messages should start with uppercase */ 420 mvaddch(lastline + Y_MSG_START, SCORE_X, ' '); 421 if (islower(Msgbuf[0]) && Msgbuf[1] != ')') 422 Msgbuf[0] = toupper(Msgbuf[0]); 423 mp = Msgbuf; 424 len = strlen(mp); 425 if (len / MSG_X + Lineno >= MSG_Y) { 426 while (Lineno < MSG_Y) { 427 wmove(Msgwin, Lineno++, 0); 428 wclrtoeol(Msgwin); 429 } 430 Lineno = 0; 431 } 432 mvaddch(Lineno + Y_MSG_START, SCORE_X, '*'); 433 lastline = Lineno; 434 do { 435 mvwaddstr(Msgwin, Lineno, 0, mp); 436 if ((len = strlen(mp)) > MSG_X) { 437 omp = mp; 438 for (mp = &mp[MSG_X - 1]; *mp != ' '; mp--) 439 continue; 440 while (*mp == ' ') 441 mp--; 442 mp++; 443 wmove(Msgwin, Lineno, mp - omp); 444 wclrtoeol(Msgwin); 445 } 446 if (++Lineno >= MSG_Y) 447 Lineno = 0; 448 } while (len > MSG_X); 449 wclrtoeol(Msgwin); 450 Mpos = len; 451 Newpos = 0; 452 wrefresh(Msgwin); 453 refresh(); 454 wrefresh(Msgwin); 455 } 456 457 /* 458 * do_wait: 459 * Wait for the user to type ' ' before doing anything else 460 */ 461 void 462 do_wait() 463 { 464 static char prompt[] = {'-', '-', 'M', 'o', 'r', 'e', '-', '-', '\0'}; 465 466 if (Mpos + sizeof prompt < MSG_X) 467 wmove(Msgwin, Lineno > 0 ? Lineno - 1 : MSG_Y - 1, Mpos); 468 else { 469 mvwaddch(Msgwin, Lineno, 0, ' '); 470 wclrtoeol(Msgwin); 471 if (++Lineno >= MSG_Y) 472 Lineno = 0; 473 } 474 waddstr(Msgwin, prompt); 475 wrefresh(Msgwin); 476 wait_for(' '); 477 } 478 479 /* 480 * wait_for 481 * Sit around until the guy types the right key 482 */ 483 void 484 wait_for(ch) 485 register int ch; 486 { 487 register char c; 488 489 if (ch == '\n') 490 while ((c = readchar()) != '\n') 491 continue; 492 else 493 while (readchar() != ch) 494 continue; 495 } 496 497 /* 498 * readchar: 499 * Reads and returns a character, checking for gross input errors 500 */ 501 int 502 readchar() 503 { 504 register int cnt; 505 char c; 506 507 over: 508 cnt = 0; 509 while (read(STDIN_FILENO, &c, sizeof(char)) <= 0) 510 if (cnt++ > 100) { /* if we are getting infinite EOFs */ 511 bye(); /* quit the game */ 512 exit(1); 513 } 514 if (c == CTRL('L')) { 515 wrefresh(curscr); 516 goto over; 517 } 518 if (c == '\r') 519 return ('\n'); 520 else 521 return (c); 522 } 523 524 /* 525 * getline: 526 * Reads the next line up to '\n' or EOF. Multiple spaces are 527 * compressed to one space; a space is inserted before a ',' 528 */ 529 char * 530 getline() 531 { 532 register char *sp; 533 register int c, oy, ox; 534 register WINDOW *oscr; 535 536 oscr = stdscr; 537 stdscr = Msgwin; 538 getyx(stdscr, oy, ox); 539 refresh(); 540 /* loop reading in the string, and put it in a temporary buffer */ 541 for (sp = linebuf; (c = readchar()) != '\n'; clrtoeol(), refresh()) { 542 if (c == -1) 543 continue; 544 else 545 if (c == erasechar()) { /* process erase character */ 546 if (sp > linebuf) { 547 register int i; 548 549 sp--; 550 for (i = strlen(unctrl(*sp)); i; i--) 551 addch('\b'); 552 } 553 continue; 554 } else 555 if (c == killchar()) { /* process kill 556 * character */ 557 sp = linebuf; 558 move(oy, ox); 559 continue; 560 } else 561 if (sp == linebuf && c == ' ') 562 continue; 563 if (sp >= &linebuf[LINESIZE - 1] || !(isprint(c) || c == ' ')) 564 putchar(CTRL('G')); 565 else { 566 if (islower(c)) 567 c = toupper(c); 568 *sp++ = c; 569 addstr(unctrl(c)); 570 Mpos++; 571 } 572 } 573 *sp = '\0'; 574 stdscr = oscr; 575 return (linebuf); 576 } 577 578 void 579 rint(signo) 580 int signo; 581 { 582 bye(); 583 exit(1); 584 } 585 586 /* 587 * bye: 588 * Leave the program, cleaning things up as we go. 589 */ 590 void 591 bye() 592 { 593 signal(SIGINT, SIG_IGN); 594 mvcur(0, COLS - 1, LINES - 1, 0); 595 fflush(stdout); 596 endwin(); 597 putchar('\n'); 598 } 599