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