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