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