(linenum→info "unix/slp.c:2238")

bsd-games/2.17/cribbage/io.c

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