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