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