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