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