io.c 11 KB

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