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