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