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