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