]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - cribbage/io.c
#include <termios.h>.
[bsdgames-darwin.git] / cribbage / io.c
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.5 1993/08/10 03:41:48 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 * msgcard:
79 * Call msgcrd in one of two forms
80 */
81 msgcard(c, brief)
82 CARD c;
83 BOOLEAN brief;
84 {
85 if (brief)
86 return msgcrd(c, TRUE, (char *) NULL, TRUE);
87 else
88 return msgcrd(c, FALSE, " of ", FALSE);
89 }
90
91
92
93 /*
94 * msgcrd:
95 * Print the value of a card in ascii
96 */
97 msgcrd(c, brfrank, mid, brfsuit)
98 CARD c;
99 char *mid;
100 BOOLEAN brfrank, brfsuit;
101 {
102 if (c.rank == EMPTY || c.suit == EMPTY)
103 return FALSE;
104 if (brfrank)
105 addmsg("%1.1s", rankchar[c.rank]);
106 else
107 addmsg(rankname[c.rank]);
108 if (mid != NULL)
109 addmsg(mid);
110 if (brfsuit)
111 addmsg("%1.1s", suitchar[c.suit]);
112 else
113 addmsg(suitname[c.suit]);
114 return TRUE;
115 }
116
117 /*
118 * printcard:
119 * Print out a card.
120 */
121 printcard(win, cardno, c, blank)
122 WINDOW *win;
123 int cardno;
124 CARD c;
125 BOOLEAN blank;
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 */
134 prcard(win, y, x, c, blank)
135 WINDOW *win;
136 int y, x;
137 CARD c;
138 BOOLEAN blank;
139 {
140 if (c.rank == EMPTY)
141 return;
142 mvwaddstr(win, y + 0, x, "+-----+");
143 mvwaddstr(win, y + 1, x, "| |");
144 mvwaddstr(win, y + 2, x, "| |");
145 mvwaddstr(win, y + 3, x, "| |");
146 mvwaddstr(win, y + 4, x, "+-----+");
147 if (!blank) {
148 mvwaddch(win, y + 1, x + 1, rankchar[c.rank][0]);
149 waddch(win, suitchar[c.suit][0]);
150 mvwaddch(win, y + 3, x + 4, rankchar[c.rank][0]);
151 waddch(win, suitchar[c.suit][0]);
152 }
153 }
154
155 /*
156 * prhand:
157 * Print a hand of n cards
158 */
159 prhand(h, n, win, blank)
160 CARD h[];
161 int n;
162 WINDOW *win;
163 BOOLEAN blank;
164 {
165 register int i;
166
167 werase(win);
168 for (i = 0; i < n; i++)
169 printcard(win, i, *h++, blank);
170 wrefresh(win);
171 }
172
173
174
175 /*
176 * infrom:
177 * reads a card, supposedly in hand, accepting unambigous brief
178 * input, returns the index of the card found...
179 */
180 infrom(hand, n, prompt)
181 CARD hand[];
182 int n;
183 char *prompt;
184 {
185 register int i, j;
186 CARD crd;
187
188 if (n < 1) {
189 printf("\nINFROM: %d = n < 1!!\n", n);
190 exit(74);
191 }
192 for (;;) {
193 msg(prompt);
194 if (incard(&crd)) { /* if card is full card */
195 if (!isone(crd, hand, n))
196 msg("That's not in your hand");
197 else {
198 for (i = 0; i < n; i++)
199 if (hand[i].rank == crd.rank &&
200 hand[i].suit == crd.suit)
201 break;
202 if (i >= n) {
203 printf("\nINFROM: isone or something messed up\n");
204 exit(77);
205 }
206 return i;
207 }
208 }
209 else /* if not full card... */
210 if (crd.rank != EMPTY) {
211 for (i = 0; i < n; i++)
212 if (hand[i].rank == crd.rank)
213 break;
214 if (i >= n)
215 msg("No such rank in your hand");
216 else {
217 for (j = i + 1; j < n; j++)
218 if (hand[j].rank == crd.rank)
219 break;
220 if (j < n)
221 msg("Ambiguous rank");
222 else
223 return i;
224 }
225 }
226 else
227 msg("Sorry, I missed that");
228 }
229 /* NOTREACHED */
230 }
231
232
233
234 /*
235 * incard:
236 * Inputs a card in any format. It reads a line ending with a CR
237 * and then parses it.
238 */
239 incard(crd)
240 CARD *crd;
241 {
242 char *getline();
243 register int i;
244 int rnk, sut;
245 char *line, *p, *p1;
246 BOOLEAN retval;
247
248 retval = FALSE;
249 rnk = sut = EMPTY;
250 if (!(line = getline()))
251 goto gotit;
252 p = p1 = line;
253 while( *p1 != ' ' && *p1 != NULL ) ++p1;
254 *p1++ = NULL;
255 if( *p == NULL ) goto gotit;
256 /* IMPORTANT: no real card has 2 char first name */
257 if( strlen(p) == 2 ) { /* check for short form */
258 rnk = EMPTY;
259 for( i = 0; i < RANKS; i++ ) {
260 if( *p == *rankchar[i] ) {
261 rnk = i;
262 break;
263 }
264 }
265 if( rnk == EMPTY ) goto gotit; /* it's nothing... */
266 ++p; /* advance to next char */
267 sut = EMPTY;
268 for( i = 0; i < SUITS; i++ ) {
269 if( *p == *suitchar[i] ) {
270 sut = i;
271 break;
272 }
273 }
274 if( sut != EMPTY ) retval = TRUE;
275 goto gotit;
276 }
277 rnk = EMPTY;
278 for( i = 0; i < RANKS; i++ ) {
279 if( !strcmp( p, rankname[i] ) || !strcmp( p, rankchar[i] ) ) {
280 rnk = i;
281 break;
282 }
283 }
284 if( rnk == EMPTY ) goto gotit;
285 p = p1;
286 while( *p1 != ' ' && *p1 != NULL ) ++p1;
287 *p1++ = NULL;
288 if( *p == NULL ) goto gotit;
289 if( !strcmp( "OF", p ) ) {
290 p = p1;
291 while( *p1 != ' ' && *p1 != NULL ) ++p1;
292 *p1++ = NULL;
293 if( *p == NULL ) goto gotit;
294 }
295 sut = EMPTY;
296 for( i = 0; i < SUITS; i++ ) {
297 if( !strcmp( p, suitname[i] ) || !strcmp( p, suitchar[i] ) ) {
298 sut = i;
299 break;
300 }
301 }
302 if( sut != EMPTY ) retval = TRUE;
303 gotit:
304 (*crd).rank = rnk;
305 (*crd).suit = sut;
306 return( retval );
307 }
308
309
310
311 /*
312 * getuchar:
313 * Reads and converts to upper case
314 */
315 getuchar()
316 {
317 register int c;
318
319 c = readchar();
320 if (islower(c))
321 c = toupper(c);
322 waddch(Msgwin, c);
323 return c;
324 }
325
326 /*
327 * number:
328 * Reads in a decimal number and makes sure it is between "lo" and
329 * "hi" inclusive.
330 */
331 number(lo, hi, prompt)
332 int lo, hi;
333 char *prompt;
334 {
335 char *getline();
336 register char *p;
337 register int sum;
338
339 sum = 0;
340 for (;;) {
341 msg(prompt);
342 if(!(p = getline()) || *p == NULL) {
343 msg(quiet ? "Not a number" : "That doesn't look like a number");
344 continue;
345 }
346 sum = 0;
347
348 if (!isdigit(*p))
349 sum = lo - 1;
350 else
351 while (isdigit(*p)) {
352 sum = 10 * sum + (*p - '0');
353 ++p;
354 }
355
356 if (*p != ' ' && *p != '\t' && *p != NULL)
357 sum = lo - 1;
358 if (sum >= lo && sum <= hi)
359 return sum;
360 if (sum == lo - 1)
361 msg("that doesn't look like a number, try again --> ");
362 else
363 msg("%d is not between %d and %d inclusive, try again --> ",
364 sum, lo, hi);
365 }
366 }
367
368 /*
369 * msg:
370 * Display a message at the top of the screen.
371 */
372 char Msgbuf[BUFSIZ] = { '\0' };
373
374 int Mpos = 0;
375
376 static int Newpos = 0;
377
378 /* VARARGS1 */
379 msg(fmt,ap)
380 char *fmt;
381 va_list ap;
382 {
383 (void)vsprintf(&Msgbuf[Newpos], fmt, &ap);
384 endmsg();
385 }
386
387 /*
388 * addmsg:
389 * Add things to the current message
390 */
391 /* VARARGS1 */
392 addmsg(fmt,ap)
393 char *fmt;
394 va_list ap;
395 {
396 (void)vsprintf(&Msgbuf[Newpos], fmt, &ap);
397 }
398
399 /*
400 * endmsg:
401 * Display a new msg.
402 */
403
404 int Lineno = 0;
405
406 endmsg()
407 {
408 register int len;
409 register char *mp, *omp;
410 static int lastline = 0;
411
412 /*
413 * All messages should start with uppercase
414 */
415 mvaddch(lastline + Y_MSG_START, SCORE_X, ' ');
416 if (islower(Msgbuf[0]) && Msgbuf[1] != ')')
417 Msgbuf[0] = toupper(Msgbuf[0]);
418 mp = Msgbuf;
419 len = strlen(mp);
420 if (len / MSG_X + Lineno >= MSG_Y) {
421 while (Lineno < MSG_Y) {
422 wmove(Msgwin, Lineno++, 0);
423 wclrtoeol(Msgwin);
424 }
425 Lineno = 0;
426 }
427 mvaddch(Lineno + Y_MSG_START, SCORE_X, '*');
428 lastline = Lineno;
429 do {
430 mvwaddstr(Msgwin, Lineno, 0, mp);
431 if ((len = strlen(mp)) > MSG_X) {
432 omp = mp;
433 for (mp = &mp[MSG_X-1]; *mp != ' '; mp--)
434 continue;
435 while (*mp == ' ')
436 mp--;
437 mp++;
438 wmove(Msgwin, Lineno, mp - omp);
439 wclrtoeol(Msgwin);
440 }
441 if (++Lineno >= MSG_Y)
442 Lineno = 0;
443 } while (len > MSG_X);
444 wclrtoeol(Msgwin);
445 Mpos = len;
446 Newpos = 0;
447 wrefresh(Msgwin);
448 refresh();
449 wrefresh(Msgwin);
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 }