'-' means stdin fix; bug report 4.3BSD/bin/86
[unix-history] / usr / src / games / cribbage / io.c
CommitLineData
6cca9b39
KM
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
8static char sccsid[] = "@(#)io.c 5.1 (Berkeley) %G%";
9#endif not lint
9a6fbd6d 10
5836528f
KA
11# include <curses.h>
12# include <ctype.h>
f870d435 13# include <signal.h>
5836528f
KA
14# include "deck.h"
15# include "cribbage.h"
39911be8 16# include "cribcur.h"
cd994cb6 17
5836528f 18# define LINESIZE 128
cd994cb6 19
39911be8
KA
20# ifdef CTRL
21# undef CTRL
22# endif
5836528f
KA
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
cd994cb6
KA
29
30char linebuf[ LINESIZE ];
31
32char *rankname[ RANKS ] = { "ACE", "TWO", "THREE", "FOUR",
5836528f
KA
33 "FIVE", "SIX", "SEVEN", "EIGHT",
34 "NINE", "TEN", "JACK", "QUEEN",
35 "KING" };
cd994cb6
KA
36
37char *rankchar[ RANKS ] = { "A", "2", "3", "4", "5", "6", "7",
5836528f 38 "8", "9", "T", "J", "Q", "K" };
cd994cb6
KA
39
40char *suitname[ SUITS ] = { "SPADES", "HEARTS", "DIAMONDS",
5836528f 41 "CLUBS" };
cd994cb6
KA
42
43char *suitchar[ SUITS ] = { "S", "H", "D", "C" };
44
45
46
47/*
5836528f
KA
48 * msgcard:
49 * Call msgcrd in one of two forms
cd994cb6 50 */
5836528f
KA
51msgcard(c, brief)
52CARD c;
53BOOLEAN brief;
cd994cb6 54{
5836528f
KA
55 if (brief)
56 return msgcrd(c, TRUE, (char *) NULL, TRUE);
57 else
58 return msgcrd(c, FALSE, " of ", FALSE);
cd994cb6
KA
59}
60
61
62
63/*
5836528f
KA
64 * msgcrd:
65 * Print the value of a card in ascii
cd994cb6 66 */
5836528f
KA
67msgcrd(c, brfrank, mid, brfsuit)
68CARD c;
69char *mid;
70BOOLEAN brfrank, brfsuit;
cd994cb6 71{
5836528f
KA
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;
cd994cb6
KA
85}
86
cd994cb6 87/*
5836528f
KA
88 * printcard:
89 * Print out a card.
cd994cb6 90 */
5dc185f5 91printcard(win, cardno, c, blank)
5836528f
KA
92WINDOW *win;
93int cardno;
94CARD c;
5dc185f5 95BOOLEAN blank;
5836528f 96{
5dc185f5 97 prcard(win, cardno * 2, cardno, c, blank);
5836528f 98}
cd994cb6 99
5836528f
KA
100/*
101 * prcard:
102 * Print out a card on the window at the specified location
103 */
f62fed8c 104prcard(win, y, x, c, blank)
5836528f
KA
105WINDOW *win;
106int y, x;
107CARD c;
f62fed8c 108BOOLEAN blank;
5836528f
KA
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, "+-----+");
f62fed8c
KA
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 }
5836528f 123}
cd994cb6 124
5836528f
KA
125/*
126 * prhand:
127 * Print a hand of n cards
128 */
5dc185f5 129prhand(h, n, win, blank)
5836528f
KA
130CARD h[];
131int n;
132WINDOW *win;
5dc185f5 133BOOLEAN blank;
cd994cb6 134{
5836528f
KA
135 register int i;
136
137 werase(win);
138 for (i = 0; i < n; i++)
5dc185f5 139 printcard(win, i, *h++, blank);
5836528f 140 wrefresh(win);
cd994cb6
KA
141}
142
143
144
145/*
5836528f
KA
146 * infrom:
147 * reads a card, supposedly in hand, accepting unambigous brief
148 * input, returns the index of the card found...
cd994cb6 149 */
5836528f
KA
150infrom(hand, n, prompt)
151CARD hand[];
152int n;
153char *prompt;
cd994cb6 154{
5836528f
KA
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 (;;) {
59d2ab16 163 msg(prompt);
5836528f
KA
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");
5836528f
KA
198 }
199 /* NOTREACHED */
cd994cb6
KA
200}
201
202
203
204/*
5836528f
KA
205 * incard:
206 * Inputs a card in any format. It reads a line ending with a CR
207 * and then parses it.
cd994cb6 208 */
5836528f
KA
209incard(crd)
210CARD *crd;
cd994cb6 211{
5836528f
KA
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;
cd994cb6 273gotit:
5836528f
KA
274 (*crd).rank = rnk;
275 (*crd).suit = sut;
276 return( retval );
cd994cb6
KA
277}
278
279
280
281/*
5836528f
KA
282 * getuchar:
283 * Reads and converts to upper case
cd994cb6 284 */
cd994cb6
KA
285getuchar()
286{
5836528f 287 register int c;
cd994cb6 288
5836528f
KA
289 c = readchar();
290 if (islower(c))
291 c = toupper(c);
39911be8 292 waddch(Msgwin, c);
5836528f 293 return c;
cd994cb6
KA
294}
295
cd994cb6 296/*
d864f6e8
KA
297 * number:
298 * Reads in a decimal number and makes sure it is between "lo" and
299 * "hi" inclusive.
cd994cb6 300 */
d864f6e8
KA
301number(lo, hi, prompt)
302int lo, hi;
303char *prompt;
cd994cb6 304{
d864f6e8
KA
305 char *getline();
306 register char *p;
307 register int sum;
5836528f
KA
308
309 sum = 0;
d864f6e8
KA
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 }
5836528f 316 sum = 0;
d864f6e8
KA
317
318 if (!isdigit(*p))
5836528f 319 sum = lo - 1;
d864f6e8
KA
320 else
321 while (isdigit(*p)) {
322 sum = 10 * sum + (*p - '0');
5836528f 323 ++p;
d864f6e8
KA
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 }
cd994cb6
KA
336}
337
5836528f
KA
338/*
339 * msg:
340 * Display a message at the top of the screen.
341 */
62136f2a 342char Msgbuf[BUFSIZ] = { '\0' };
5836528f
KA
343
344int Mpos = 0;
cd994cb6 345
5836528f
KA
346static int Newpos = 0;
347
348/* VARARGS1 */
349msg(fmt, args)
350char *fmt;
351int args;
352{
5836528f
KA
353 doadd(fmt, &args);
354 endmsg();
355}
cd994cb6
KA
356
357/*
5836528f
KA
358 * addmsg:
359 * Add things to the current message
cd994cb6 360 */
5836528f
KA
361/* VARARGS1 */
362addmsg(fmt, args)
363char *fmt;
364int args;
365{
366 doadd(fmt, &args);
367}
cd994cb6 368
5836528f
KA
369/*
370 * endmsg:
39911be8 371 * Display a new msg.
5836528f 372 */
f6867294
KA
373
374int Lineno = 0;
375
5836528f 376endmsg()
cd994cb6 377{
39911be8
KA
378 register int len;
379 register char *mp, *omp;
f6867294 380 static int lastline = 0;
39911be8 381
5836528f 382 /*
f6867294 383 * All messages should start with uppercase
5836528f 384 */
f6867294 385 mvaddch(lastline + Y_MSG_START, SCORE_X, ' ');
5836528f
KA
386 if (islower(Msgbuf[0]) && Msgbuf[1] != ')')
387 Msgbuf[0] = toupper(Msgbuf[0]);
39911be8
KA
388 mp = Msgbuf;
389 len = strlen(mp);
ecbc5dbf
KA
390 if (len / MSG_X + Lineno >= MSG_Y) {
391 while (Lineno < MSG_Y) {
392 wmove(Msgwin, Lineno++, 0);
393 wclrtoeol(Msgwin);
394 }
f6867294 395 Lineno = 0;
ecbc5dbf 396 }
f6867294
KA
397 mvaddch(Lineno + Y_MSG_START, SCORE_X, '*');
398 lastline = Lineno;
39911be8 399 do {
f6867294 400 mvwaddstr(Msgwin, Lineno, 0, mp);
39911be8
KA
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++;
f6867294 408 wmove(Msgwin, Lineno, mp - omp);
39911be8
KA
409 wclrtoeol(Msgwin);
410 }
f6867294
KA
411 if (++Lineno >= MSG_Y)
412 Lineno = 0;
39911be8
KA
413 } while (len > MSG_X);
414 wclrtoeol(Msgwin);
ecbc5dbf 415 Mpos = len;
5836528f 416 Newpos = 0;
39911be8 417 wrefresh(Msgwin);
5836528f 418 refresh();
39911be8 419 wrefresh(Msgwin);
cd994cb6
KA
420}
421
5836528f
KA
422/*
423 * doadd:
424 * Perform an add onto the message buffer
425 */
426doadd(fmt, args)
427char *fmt;
428int *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}
cd994cb6 442
f6867294
KA
443/*
444 * do_wait:
445 * Wait for the user to type ' ' before doing anything else
446 */
447do_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
5836528f
KA
465/*
466 * wait_for
467 * Sit around until the guy types the right key
468 */
469wait_for(ch)
470register 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}
cd994cb6 481
5836528f
KA
482/*
483 * readchar:
484 * Reads and returns a character, checking for gross input errors
485 */
486readchar()
487{
488 register int cnt, y, x;
489 auto char c;
490
491over:
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 }
5836528f
KA
500 if (c == '\r')
501 return '\n';
502 else
503 return c;
504}
cd994cb6 505
5836528f
KA
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 */
511char *
512getline()
513{
514 register char *sp;
515 register int c, oy, ox;
39911be8 516 register WINDOW *oscr;
5836528f 517
39911be8
KA
518 oscr = stdscr;
519 stdscr = Msgwin;
5836528f
KA
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));
5836528f
KA
552 Mpos++;
553 }
554 }
555 *sp = '\0';
39911be8 556 stdscr = oscr;
5836528f
KA
557 return linebuf;
558}
f870d435
KA
559
560/*
561 * bye:
562 * Leave the program, cleaning things up as we go.
563 */
564bye()
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}