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