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