home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume28 / ldb / part05 < prev    next >
Encoding:
Text File  |  1992-03-14  |  35.3 KB  |  1,145 lines

  1. Newsgroups: comp.sources.misc
  2. From: ROSS@emf780.den.mmc.com ("Perry R. Ross")
  3. Subject:  v28i097:  ldb - Play backgammon by e-mail, Part05/05
  4. Message-ID: <1992Mar13.035627.11956@sparky.imd.sterling.com>
  5. X-Md4-Signature: c65053223a8f794c4c9d57dbc5b1a19e
  6. Date: Fri, 13 Mar 1992 03:56:27 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: ROSS@emf780.den.mmc.com (Perry R. Ross)
  10. Posting-number: Volume 28, Issue 97
  11. Archive-name: ldb/part05
  12. Environment: UNIX, C, VMS, VAXC, CURSES, 32BIT
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 5 (of 5)."
  21. # Contents:  fe_curses.c
  22. # Wrapped by ross@emf780 on Tue Mar 10 09:24:27 1992
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'fe_curses.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'fe_curses.c'\"
  26. else
  27. echo shar: Extracting \"'fe_curses.c'\" \(33230 characters\)
  28. sed "s/^X//" >'fe_curses.c' <<'END_OF_FILE'
  29. X/*    fe_curses.c        9/5/91
  30. X *
  31. X * Copyright 1991  Perry R. Ross
  32. X *
  33. X * Permission to use, copy, modify, and distribute this software and its
  34. X * documentation without fee is hereby granted, subject to the restrictions
  35. X * detailed in the README file, which is included here by reference.
  36. X * Any other use requires written permission from the author.  This software
  37. X * is distributed "as is" without any warranty, including any implied
  38. X * warranties of merchantability or fitness for a particular purpose.
  39. X * The author shall not be liable for any damages resulting from the
  40. X * use of this software.  By using this software, the user agrees
  41. X * to these terms.
  42. X */
  43. X
  44. X#include "ldb.h"
  45. X
  46. X/*======================================================================
  47. X * This file is the "curses" front-end for ldb.  It performs all
  48. X * display output and keyboard input in a way that will (hopefully)
  49. X * allow other front-ends to be added later.  These could include
  50. X * MAC's (blech), IBM PC's (double blech), and X, although it must
  51. X * be stated that, as of this writing, ldb is not organized in an
  52. X * event-driven manner, so it will take more work to port to X than
  53. X * just writing fe_motif.c or what have you.  But I'm working on it.
  54. X *
  55. X * All publicly-accessible functions in the front-end begin with Fe.
  56. X * These are the functions that must be written to implement a new
  57. X * front-end.  There are a few private functions in this file, which
  58. X * begin with P.  These are used internally by fe_curses.c and need not
  59. X * be implemented in other front-ends.
  60. X *
  61. X * The front-end is activated by calling FeInitialize.  In addition to
  62. X * performing any required initialization, it is mandatory for FeInitialize
  63. X * to set FeIsActive to non-zero.  The front-end is closed down by
  64. X * calling FeFinishSession, which must set FeIsActive to 0.  No calls
  65. X * to any Fe functions may be made while FeIsActive is 0.
  66. X *======================================================================
  67. X */
  68. X
  69. XPRIVATE char PGetChr();
  70. XPRIVATE PGetString();
  71. XPRIVATE PDrawComment();
  72. X
  73. X/* VAX C doesn't have tgetstr, but if you're using vax-c,    */
  74. X/* you're probably using a DEC terminal anyway.            */
  75. X#ifdef vaxc
  76. X#define PClearScreen() fputs("\33[H\33[2J",stdout);fflush(stdout)
  77. X#else
  78. XPRIVATE PClearScreen();
  79. X#endif
  80. X
  81. X
  82. X/*----------------------------------------------------------------------
  83. X *    FeInitialize -- initialize the front end
  84. X *
  85. X * This function initializes the curses package, turns off echo,
  86. X * turns on cbreak mode (to allow reading one character at a time),
  87. X * turns off mapping return to newline, and sets the FeIsActive flag.
  88. X *----------------------------------------------------------------------
  89. X */
  90. X
  91. XFeInitialize()
  92. X{
  93. X
  94. Xinitscr();
  95. Xnoecho();
  96. Xcbreak();
  97. Xnonl();
  98. XFeIsActive = 1;
  99. X}
  100. X
  101. X
  102. X/*----------------------------------------------------------------------
  103. X *    FeFinishSession -- shut down the front end
  104. X *
  105. X * This function moves the cursor to the bottom of the screen, clears
  106. X * the bottom line, closes down the curses package, and clears the
  107. X * FeIsActive flag.
  108. X *----------------------------------------------------------------------
  109. X */
  110. X
  111. XFeFinishSession()
  112. X{
  113. X
  114. Xif (FeIsActive) {
  115. X    move(23,0);
  116. X    clrtoeol();
  117. X    refresh();
  118. X    endwin();
  119. X    FeIsActive = 0;
  120. X    }
  121. X}
  122. X
  123. X
  124. X/*----------------------------------------------------------------------
  125. X *    FeDrawScreen -- draw the constant parts of the screen
  126. X *
  127. X * This function draws the parts of the screen that don't change for
  128. X * each game.  This includes the board outline and a few other
  129. X * miscellaneous things.
  130. X *----------------------------------------------------------------------
  131. X */
  132. X
  133. XFeDrawScreen()
  134. X{
  135. Xstatic char horz[] = "_____________________________________________________";
  136. Xint i;
  137. X
  138. Xclear();
  139. Xmvaddstr(2,5,horz);
  140. Xmvaddstr(17,5,horz);
  141. Xfor (i = 3; i < 18; i++) {
  142. X    mvaddch(i,5,'|');
  143. X    mvaddch(i,29,'|');
  144. X    mvaddch(i,33,'|');
  145. X    mvaddch(i,57,'|');
  146. X    }
  147. Xmvaddstr(10,30,"BAR");
  148. Xmvaddstr(3,61,"----------------");
  149. Xmvaddstr(4,63,"Roll  Move");
  150. Xmvaddstr(12,61,"----------------");
  151. Xmvaddstr(13,63,"Roll  Move");
  152. Xmvaddstr(18,63,"-----[ ]------");
  153. Xfor (i = 18; i < 24; i++)
  154. X    mvaddch(i,62,'|');
  155. Xmvaddstr(18,0,"Messages:");
  156. Xmvaddstr(19,0,"Sent:");
  157. Xmvaddstr(21,0,"Rcvd:");
  158. Xrefresh();
  159. X}
  160. X
  161. X
  162. X
  163. X/*----------------------------------------------------------------------
  164. X *    FeDrawGame -- draw all items associated with a game
  165. X *
  166. X * This function displays all information related to a specific game.
  167. X * This includes the point labels, move blocks, cube; shoot, just
  168. X * about everything you can think of.
  169. X *----------------------------------------------------------------------
  170. X */
  171. X
  172. XFeDrawGame(g)
  173. Xstruct game *g;
  174. X{
  175. Xint i, p, r1, r2, p1, p2;
  176. Xchar blots[12], tmp[60], *n;
  177. Xstatic char pts1[] = " 1   2   3   4   5   6 |   | 7   8   9  10  11  12";
  178. Xstatic char pts2[] = "24  23  22  21  20  19 |   |18  17  16  15  14  13";
  179. X
  180. Xmove(0,0);
  181. Xclrtoeol();
  182. Xmove(0,0);
  183. Xn = (g->opname != NULL) ? g->opname : "UNKNOWN";
  184. Xprintw("Playing: %s (%s)",g->opaddr,n);        /* who am I playing? */
  185. Xif (g->flags & F_INVERT) {        /* board is inverted?  */
  186. X    mvaddstr(16,6,pts2);        /* draw inverted point labels */
  187. X    mvaddstr(4,6,pts1);
  188. X    r1 = 11;            /* remember which move block to use */
  189. X    r2 = 2;
  190. X    p = 1;
  191. X    }
  192. Xelse {
  193. X    mvaddstr(4,6,pts2);        /* draw normal point labels */
  194. X    mvaddstr(16,6,pts1);
  195. X    r1 = 2;                /* remember which move block to use */
  196. X    r2 = 11;
  197. X    p = 0;
  198. X    }
  199. Xif (g->mydir > 0) {        /* I'm playing up, switch move blocks */
  200. X    i = r1;
  201. X    r1 = r2;
  202. X    r2 = i;
  203. X    p = 1 - p;
  204. X    }
  205. Xmove(r1,61);
  206. Xclrtoeol();                /* label the move blocks */
  207. Xsprintf(tmp,"Opponent (%s)",colorname(g->opcolor));
  208. Xi = 61 + ( (16 - strlen(tmp)) >> 1 );    /* center the string */
  209. Xmvaddstr(r1,i,tmp);
  210. Xmove(r2,61);
  211. Xclrtoeol();
  212. Xsprintf(tmp,"You (%s)",colorname(g->mycolor));
  213. Xi = 61 + ( (16 - strlen(tmp)) >> 1 );
  214. Xmvaddstr(r2,i,tmp);
  215. X
  216. XFeLabelBoard(bdlabels[g->curbd]);    /* which board am I looking at? */
  217. Xswitch (g->curbd) {            /* which board should I draw? */
  218. Xcase BD_BEFOP:
  219. X    FeDrawBoard(g->opbd,g->opmvs,g->opdir,0,g->flags & F_INVERT);
  220. X    break;
  221. Xcase BD_AFTOP:
  222. X    FeDrawBoard(g->mybd,g->opmvs,g->opdir,1,g->flags & F_INVERT);
  223. X    break;
  224. Xcase BD_CUR:
  225. X    FeDrawBoard(g->board,NULL,g->mydir,0,g->flags & F_INVERT);
  226. X    break;
  227. X    }
  228. Xmvaddch(5,59,'|');            /* draw those little arrows */
  229. Xmvaddch(14,59,'|');            /* that tell us which direction */
  230. Xmvaddch(15,59,'|');            /* we are going */
  231. Xif (p == 0) {
  232. X    mvaddstr(4,1,"-->");
  233. X    mvaddstr(4,58,"--");
  234. X    mvaddch(6,59,'V');
  235. X    mvaddstr(16,58,"<-");
  236. X    mvaddstr(16,1,"<--");
  237. X    mvaddch(14,58,' ');
  238. X    mvaddch(14,60,' ');
  239. X    mvaddch(13,59,' ');
  240. X    }
  241. Xelse {
  242. X    mvaddstr(4,1,"<--");
  243. X    mvaddstr(4,58,"<-");
  244. X    mvaddch(6,59,'|');
  245. X    mvaddstr(16,58,"--");
  246. X    mvaddstr(16,1,"-->");
  247. X    mvaddch(14,58,'/');
  248. X    mvaddch(14,60,'\\');
  249. X    mvaddch(13,59,'.');
  250. X    }
  251. X*blots = '\0';                /* did any of our blots get hit? */
  252. Xfor (i = 0, p = 0; i < 4; i++) {
  253. X    FeDrawMove(g,0,i);        /* draw my moves */
  254. X    FeDrawMove(g,1,i);        /* draw opponent's moves */
  255. X    if (g->blot[i] > 0) {
  256. X        strcat(blots," ");    /* add a blot to the list */
  257. X        sprintf(tmp,"%d",g->blot[i]);
  258. X        strcat(blots,tmp);
  259. X        p++;
  260. X        }
  261. X    }
  262. XFeDrawCube(g);        /* draw the current game value */
  263. XPDrawComment(0, g);        /* draw my old comment */
  264. XPDrawComment(1, g);        /* draw opponent's comment */
  265. Xif (g->state == ST_MYACCEPT)
  266. X    strcpy(tmp,"Opponent has doubled.");
  267. Xelse if (g->state == ST_GAMEOVER) {    /* game is over, find out why */
  268. X    switch (g->term) {
  269. X    case T_IWIN:        /* I won, check for gammon/backgammon */
  270. X        if (g->board[OFFPT(g->opdir)].qty == 0) {
  271. X            p1 = (g->mydir > 0) ? 19 : 0;    /* check my inner tbl*/
  272. X            p2 = (g->mydir > 0) ? 25 : 6;    /* for op's pieces */
  273. X            if (addpcs(g->board,g->opcolor,p1,p2) > 0)
  274. X                sprintf(tmp,"Backgammon!  You win %d points.",
  275. X                    3*g->gameval);
  276. X            else
  277. X                sprintf(tmp,"Gammon!  You win %d points.",
  278. X                    2*g->gameval);
  279. X            }
  280. X        else
  281. X            sprintf(tmp,"You win!  Game value was %d point%s.",
  282. X                g->gameval,(g->gameval == 1) ? "" : "s");
  283. X        break;
  284. X    case T_ILOSE:        /* I lost, check for gammon/backgammon */
  285. X        if (g->board[OFFPT(g->mydir)].qty == 0) {
  286. X            p1 = (g->opdir > 0) ? 19 : 0;/* check op's inner tbl*/
  287. X            p2 = (g->opdir > 0) ? 25 : 6;    /* for my pieces */
  288. X            if (addpcs(g->board,g->mycolor,p1,p2) > 0)
  289. X                sprintf(tmp,"Backgammon!  You lose %d points.",
  290. X                    3*g->gameval);
  291. X            else
  292. X                sprintf(tmp,"Gammon!  You lose %d points.",
  293. X                    2*g->gameval);
  294. X            }
  295. X        else
  296. X            sprintf(tmp,"You lose.  Game value was %d point%s.",
  297. X                g->gameval,(g->gameval == 1) ? "" : "s");
  298. X        break;
  299. X    case T_ICONCEDE:            /* I wimped out */
  300. X        sprintf(tmp,"You conceded.  You lose %d point%s.",
  301. X            g->gameval,(g->gameval == 1) ? "" : "s");
  302. X        break;
  303. X    case T_OPCONCEDE:            /* Opponent wimped out */
  304. X        sprintf(tmp,"Opponent conceded.  You win %d point%s.",
  305. X            g->gameval,(g->gameval == 1) ? "" : "s");
  306. X        break;
  307. X    case T_IDECLINE:            /* I declined the double */
  308. X        sprintf(tmp,"Double declined.  You lose %d point%s.",
  309. X            g->gameval,(g->gameval == 1) ? "" : "s");
  310. X        break;
  311. X    case T_OPDECLINE:        /* Opponent declined my double */
  312. X        sprintf(tmp,"Double declined.  You win %d point%s.",
  313. X            g->gameval,(g->gameval == 1) ? "" : "s");
  314. X        break;
  315. X        }
  316. X    }
  317. Xelse if (*blots)
  318. X    sprintf(tmp,"Blot%s hit:%s",(p == 1) ? "" : "s",blots);
  319. Xelse
  320. X    *tmp = '\0';
  321. XFeStatusLine(tmp);
  322. XFeMessage(g->dispmsg);        /* put message (if any) on message line */
  323. Xif (g->dispmsg != NULL) {    /* if there was a message, it has been */
  324. X    free(g->dispmsg);    /* displayed, so it can thrown away */
  325. X    g->dispmsg = NULL;
  326. X    }
  327. Xrefresh();
  328. X}
  329. X
  330. X
  331. X/*----------------------------------------------------------------------
  332. X *    FeDrawPoint -- draw all pieces on a point
  333. X *
  334. X * This function redraws all 15 slots on a point.  It is passed a
  335. X * board image and the index of the point to draw, from which it
  336. X * extracts the number of pieces on that point and the character used
  337. X * to represent pieces.  It will draw as many of these pieces as
  338. X * exist on the point, and will draw blanks over the remaining slots
  339. X * to erase any pieces that may have existed before.
  340. X * If the nh argument is greater than 0, it specifies how many of
  341. X * the pieces drawn should be highlighted.  This is used to highlight
  342. X * pieces moved by the opponent.
  343. X *----------------------------------------------------------------------
  344. X */
  345. X
  346. XFeDrawPoint(b,pt,nh,inv)
  347. Xboard b;        /* the board array */
  348. Xint pt;            /* which point are we to draw */
  349. Xint nh;            /* how many pieces should be highlighted */
  350. Xint inv;        /* is the board inverted? */
  351. X{
  352. Xstatic int cols[BOARDSIZE] = {  31,7,11,15,19,23,27,35,39,43,47,51,55,
  353. X                55,51,47,43,39,35,27,23,19,15,11,7,31,2,2};
  354. Xint sr, r;        /* the row we are at */
  355. Xint c;        /* the column we are at */
  356. Xint d;        /* which direction does the column grow 1/-1 */
  357. Xint i;        /* counter */
  358. Xchar x;        /* char to draw piece with */
  359. Xint nn;        /* number of normal pieces */
  360. X
  361. Xif ( (pt > 12) && (pt != DOWNOFF)) {
  362. X    sr = inv ? 15 : 5;    /* starting row is 5 (unless inverted) */
  363. X    d = inv ? -1 : 1;    /* direction is down (unless inverted) */
  364. X    }
  365. Xelse {
  366. X    sr = inv ? 5 : 15;    /* starting row is 15 (unless inverted) */
  367. X    d = inv ? 1 : -1;    /* direction is up (unless inverted) */
  368. X    }
  369. Xc = cols[pt];
  370. Xx = b[pt].color;        /* char to draw piece with */
  371. Xif (nh < 0)
  372. X    nh = 0;
  373. Xelse if (nh > b[pt].qty)
  374. X    nh = b[pt].qty;
  375. Xnn = b[pt].qty - nh;        /* how many normal pcs */
  376. Xr = sr;
  377. Xfor (i = 0; i < 15; i++) {        /* draw all 15 slots on this point */
  378. X    if (nn <= 0) {        /* no more normal pieces */
  379. X        if (nh <= 0)    /* and no highlighted pieces */
  380. X            x = ' ';    /* so draw blanks */
  381. X        else {
  382. X            standout();    /* go into highlight mode */
  383. X            nh--;
  384. X            }
  385. X        }
  386. X    else
  387. X        nn--;
  388. X    mvaddch(r,c,x);            /* draw this piece */
  389. X    standend();            /* make sure we're not highlighting */
  390. X    if (i == 4) {
  391. X        r = sr;            /* reset row */
  392. X        c--;            /* use col to left of first row */
  393. X        }
  394. X    else if (i == 9) {
  395. X        r = sr;            /* reset row */
  396. X        c += 2;            /* use col to right of first row */
  397. X        }
  398. X    else
  399. X        r += d;            /* bump row number */
  400. X    }
  401. X}
  402. X
  403. X
  404. X/*----------------------------------------------------------------------
  405. X *    FeDrawMove -- draw a line in a move block
  406. X *
  407. X * This function draws one line in a move block.  This consists of the
  408. X * value of the roll, the starting and ending position of the piece
  409. X * moved, and an asterisk if the move was from the opponent and hit
  410. X * one of our blots.
  411. X *----------------------------------------------------------------------
  412. X */
  413. X
  414. XFeDrawMove(g,who,mn)
  415. Xstruct game *g;            /* the game structure */
  416. Xint who;            /* 0 = opponent, 1 = me */
  417. Xint mn;                /* which move to draw */
  418. X{
  419. Xint p, r, d;
  420. Xstruct mv *m;
  421. X
  422. Xd = who ? g->mydir : g->opdir;        /* this move upbound or downbound? */
  423. Xp = (d > 0);                /* upper or lower block? */
  424. Xif (g->flags & F_INVERT)        /* inverted board */
  425. X    p = !p;                /* switch move blocks */
  426. Xr = mn + (p ? 5 : 14);            /* figure out the row number */
  427. Xm = who ? &g->mvs[mn] : &g->opmvs[mn];    /* find the move structure */
  428. Xmove(r,64);
  429. Xclrtoeol();                /* clear the old move */
  430. Xif (m->roll > 0) {
  431. X    move(r,64);
  432. X    printw("%d",m->roll);        /* draw the roll */
  433. X    move(r,69);
  434. X    if (m->pt < 0) {        /* if it is unused, say so */
  435. X        addstr("UNUSED");
  436. X        return;
  437. X        }
  438. X    if ( ( (p = m->pt) == UPBAR) || (m->pt == DOWNBAR) ) {
  439. X        p = BARPT(d);        /* if coming off bar, say so */
  440. X        printw("BAR-");
  441. X        }
  442. X    else
  443. X        printw("%d-",m->pt);    /* draw starting point */
  444. X    if ( ( (p += d*m->roll) <= 0) || (p >= 25) )
  445. X        printw("OFF");        /* if bearing off, say so */
  446. X    else
  447. X        printw("%d",p);        /* draw ending point */
  448. X    if ( (who == 0) && g->blot[mn])    /* if opponent move hit a blot */
  449. X        mvaddch(r,76,'*');    /* mark it */
  450. X    }
  451. X}
  452. X
  453. X
  454. X/*----------------------------------------------------------------------
  455. X *    FeDrawBoard -- draw all points on a board
  456. X *
  457. X * This is a convenience function that calls FeDrawPoint for all
  458. X * points on a board.  It takes as an argument an array of moves,
  459. X * as well as an argument that determines whether DrawPoint should be
  460. X * instructed to highlight the source of those moves, the destination,
  461. X * or nothing.
  462. X *----------------------------------------------------------------------
  463. X */
  464. X
  465. XFeDrawBoard(b,mvs,dir,sd,inv)
  466. Xboard b;            /* board image */
  467. Xstruct mv mvs[4];        /* moves to highlight (NULL = none) */
  468. Xint dir;            /* direction */
  469. Xint sd;                /* 0=highlight source, 1=dest */
  470. Xint inv;            /* is the board inverted? */
  471. X{
  472. Xint i, s, e;
  473. Xstatic char hcnt[BOARDSIZE];    /* number of pieces to highlight */
  474. X
  475. Xfor (i = 0; i < BOARDSIZE; i++)
  476. X    hcnt[i] = 0;        /* init to no highlight */
  477. Xif (mvs != NULL) {    /* find all points that should be highlighted */
  478. X    for (i = 0; i < 4; i++) {
  479. X        if ( (mvs[i].roll <= 0) || ( (s = mvs[i].pt) < 0) )
  480. X            continue;    /* this move is unused */
  481. X        if ( (s < 1) || (s > 24) )    /* if coming off bar */
  482. X            s = BARPT(dir);        /* use correct bar point */
  483. X        e = s + dir*mvs[i].roll;    /* add in the roll used */
  484. X        if ( (e < 1) || (e > 24) )    /* off the board */
  485. X            e = OFFPT(dir);    /* use correct off point */
  486. X        if (sd > 0) {            /* we are showing dest */
  487. X            hcnt[e]++;        /* inc destination count */
  488. X            hcnt[s]--;        /* handle continued moves */
  489. X            }
  490. X        else {                /* we are showing start */
  491. X            hcnt[s]++;        /* inc start count */
  492. X            hcnt[e]--;        /* handle continued moves */
  493. X            }
  494. X        }
  495. X    }
  496. Xfor (i = 0; i < BOARDSIZE; i++)        /* draw each point */
  497. X    FeDrawPoint(b,i,hcnt[i],inv);
  498. X}
  499. X
  500. X
  501. X/*----------------------------------------------------------------------
  502. X *    FeLabelBoard -- center a string above the board.
  503. X *
  504. X * This function is used to label which board the user is seeing.
  505. X *----------------------------------------------------------------------
  506. X */
  507. X
  508. XFeLabelBoard(s)
  509. Xchar *s;
  510. X{
  511. Xint i;
  512. X
  513. Xif (strlen(s) > 50)        /* 50 chars is all the room we have */
  514. X    s[50] = '\0';        /* chop it off */
  515. Xmvaddstr(1,5,BLANKS(50));    /* clear old contents */
  516. Xif ( (i = 31 - strlen(s)/2) < 0)
  517. X    i = 0;
  518. Xmvaddstr(1,i,s);        /* draw the string */
  519. X}
  520. X
  521. X
  522. X/*----------------------------------------------------------------------
  523. X *    FeGetPoint -- read a point number from the user
  524. X *
  525. X * This function prompts the user for a point number.  The user types
  526. X * the input on the line of the move block corresponding to the
  527. X * roll being used.  Normally, the input is a number between 1 and 24.  
  528. X * Numbers that do not use 2 digits (i.e. 1-9) must have a non-digit
  529. X * character typed after them; alternatively, the user may enter them
  530. X * with a leading 0.  There are a number of special characters that
  531. X * are also recognized:
  532. X *    char            return value
  533. X *    ---------------------------------------------------------------
  534. X *    space            the "spdflt" argument.
  535. X *    return/linefeed        the "crdflt" argument.
  536. X *    DEL/ESC/BS        cancel move.
  537. X *    b/B            the user's bar point.
  538. X *    p/P            the point from which a piece would have
  539. X *                to be moved to land on spdflt.
  540. X *    o/O            The point from which the selected roll
  541. X *                could be used to bear off.  If that point
  542. X *                is unoccupied, the next lower occupied
  543. X *                point is returned.
  544. X *----------------------------------------------------------------------
  545. X */
  546. X
  547. XFeGetPoint(g,r,crdflt,spdflt)
  548. Xstruct game *g;                /* game structure */
  549. Xint r;                    /* which row in move block */
  550. Xint crdflt;                /* what to return for cr/nl */
  551. Xint spdflt;                /* what to return for space */
  552. X{
  553. Xint n, row;
  554. Xchar buf[4];
  555. X
  556. Xrow = r;
  557. Xif (g->flags & F_INVERT)        /* which move block do I use? */
  558. X    row += (g->mydir < 0) ? 5 : 14;    /* inverted board */
  559. Xelse
  560. X    row += (g->mydir > 0) ? 5 : 14;    /* normal board */
  561. Xmove(row,69);
  562. Xclrtoeol();
  563. Xmove(row,69);
  564. Xrefresh();
  565. X*buf = PGetChr(0);
  566. Xif ( (*buf == '\n') || (*buf == '\r') )    /* return means repeat move */
  567. X    return(crdflt);
  568. Xif (*buf == ' ')            /* space means continue move */
  569. X    return(spdflt);
  570. Xif ( (*buf == '\177') || (*buf == '\033') || (*buf == '\b') )
  571. X    return(-1);            /* DEL/ESC/BS means cancel move */
  572. Xif ( (*buf == 'b') || (*buf == 'B') )    /* bar */
  573. X    return(BARPT(g->mydir));
  574. Xif ( (*buf == 'p') || (*buf == 'P') ) {    /* P means spdflt - roll*dir */
  575. X    n = spdflt - g->mvs[r].roll*g->mydir;    /* make point */
  576. X    if ( (n < 1) || (n > 24) )        /* not on board */
  577. X        n = 99;                /* force invalid point */
  578. X    return(n);
  579. X    }
  580. Xif ( (*buf == 'o') || (*buf == 'O') ) {    /* O means bear a piece off */
  581. X    n = ( (g->mydir > 0) ? 25 : 0 ) - g->mydir*g->mvs[r].roll;
  582. X    while ( (n > 0) && (n <= 24) &&
  583. X       ( (g->board[n].qty <= 0) || (g->board[n].color != g->mycolor)) )
  584. X        n += g->mydir;
  585. X    if ( (n < 1) || (n > 24) )    /* no piece found */
  586. X        n = 99;            /* force invalid point */
  587. X    return(n);
  588. X    }
  589. Xif ( ! isdigit(*buf))
  590. X    return(99);            /* force invalid point message */
  591. Xaddch(*buf);                /* echo the char */
  592. Xrefresh();
  593. Xbuf[1] = PGetChr(0);
  594. Xbuf[2] = '\0';                /* null terminate */
  595. Xif ( ((n = atoi(buf)) == UPBAR) || (n == DOWNBAR) )
  596. X    return(BARPT(g->mydir));
  597. Xreturn(n);
  598. X}
  599. X
  600. X
  601. X/*----------------------------------------------------------------------
  602. X *    PGetChr -- get a single character
  603. X *
  604. X * This function gets one character from the user and returns it.
  605. X * If the "e" argument is non-zero, the character is echoed at the
  606. X * current cursor position.  The ^L and ^R characters are intercepted
  607. X * and cause the screen to be redrawn without returning from PGetChr.
  608. X *----------------------------------------------------------------------
  609. X */
  610. X
  611. XPRIVATE char PGetChr(e)
  612. Xint e;
  613. X{
  614. Xchar c;
  615. Xint y, x;
  616. X
  617. Xloop:
  618. Xif ( ((c = getch() & 0x7f) == 0x0c) || (c == 0x12) ) {    /* ^L or ^R? */
  619. X    wrefresh(curscr);    /* repaint current screen */
  620. X    goto loop;        /* and get another char */
  621. X    }
  622. Xif (c == rc.superkey) {            /* uh oh, we're busted */
  623. X    getyx(stdscr,y,x);        /* save old cursor postition */
  624. X    PClearScreen();            /* get the screen cleared fast */
  625. X    nl();                /* set tty back to normal */
  626. X    echo();
  627. X    system(rc.supercmd);        /* run the supervisor command */
  628. X    nonl();                /* ok, we're safe again */
  629. X    noecho();
  630. X    PClearScreen();            /* get the screen cleared fast */
  631. X    wrefresh(curscr);        /* redisplay the game */
  632. X    move(y,x);            /* put cursor back where it was */
  633. X    refresh();
  634. X    goto loop;            /* and get another character */
  635. X    }
  636. Xif (e && isprint(c)) {        /* echo char? */
  637. X    addch(c);        /* yup */
  638. X    refresh();
  639. X    }
  640. Xreturn(c);
  641. X}
  642. X
  643. X
  644. X/*----------------------------------------------------------------------
  645. X *    PClearScreen -- clear the screen somehow
  646. X *
  647. X * This function clears the physical display without affecting what
  648. X * the curses package thinks is there.  If the "cl" (clear screen)
  649. X * capability is defined, it uses that.  If that fails, it tries
  650. X * to move to 0,0 and use the "cd" (clear to end of display).
  651. X * Failing that, it goes to the bottom of the screen and scrolls
  652. X * it 24 times.
  653. X *----------------------------------------------------------------------
  654. X */
  655. X
  656. X#ifndef vaxc
  657. XPRIVATE PClearScreen()
  658. X{
  659. Xchar *s, *x, buf[80];
  660. X
  661. Xx = buf;
  662. Xif ( (s = tgetstr("cl",&x)) == NULL) {        /* no clear screen */
  663. X    if ( (s = tgetstr("cd",&x)) != NULL) {    /* do we have clr to end? */
  664. X        move(0,0);        /* yup, use it */
  665. X        refresh();
  666. X        fputs(s,stdout);
  667. X        }
  668. X    else {            /* well, do it the hard way */
  669. X        move(23,0);
  670. X        refresh();
  671. X        printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
  672. X        }
  673. X    }
  674. Xelse
  675. X    fputs(s,stdout);    /* send clear screen */
  676. Xfflush(stdout);            /* git along, li'l characters */
  677. X}
  678. X#endif
  679. X
  680. X
  681. X/*----------------------------------------------------------------------
  682. X *    FeGetComment -- prompt for a comment to send along with a move
  683. X *
  684. X * This function allows the user to enter a 2-line comment.  If the
  685. X * user types a non-empty string, it is stored in the mycmt/mycmt2
  686. X * fields of the game structure passed as an argument.  The previous comment,
  687. X * if any, is discarded, as is the last comment received from the opponent.
  688. X *----------------------------------------------------------------------
  689. X */
  690. X
  691. XFeGetComment(g)
  692. Xstruct game *g;
  693. X{
  694. Xchar buf[120];
  695. Xchar *lptrs[2];
  696. Xint n;
  697. X
  698. Xif (g->mycmt != NULL)        /* throw away old comment */
  699. X    free(g->mycmt);
  700. Xif (g->mycmt2 != NULL)
  701. X    free(g->mycmt2);
  702. Xif (g->opcmt != NULL) {        /* throw away opponent's old comment */
  703. X    free(g->opcmt);
  704. X    g->opcmt = NULL;
  705. X    }
  706. Xif (g->opcmt2 != NULL) {
  707. X    free(g->opcmt2);
  708. X    g->opcmt2 = NULL;
  709. X    }
  710. Xn = PGetString(buf,56,lptrs,2,19,6);    /* get new comment */
  711. Xg->mycmt = NULL;    /* mark comment as empty */
  712. Xg->mycmt2 = NULL;
  713. Xif (n > 0)
  714. X    g->mycmt = save(lptrs[0]);    /* save first line */
  715. Xif (n > 1)
  716. X    g->mycmt2 = save(lptrs[1]);    /* save second line */
  717. X}
  718. X
  719. X
  720. X
  721. X/*----------------------------------------------------------------------
  722. X *    PGetString -- read a multi-line string from the user
  723. X *
  724. X * This function allows the user to enter multiple lines of a fixed maximum
  725. X * length.  The normal line editing characters are recognized and
  726. X * processed.  These include:
  727. X *    DEL/BS        The character before the cursor is deleted.
  728. X *    ^X/^U        The entire line is erased.
  729. X *    ^L/^R        The screen is redrawn.
  730. X *    ^W/^B        The word before the cursor is erased.
  731. X * Typing past the end of a line automatically causes a word-
  732. X * wrap to the next line.  Words are delimited by spaces.  Typing
  733. X * a carriage return or line feed on the last line, or on an empty
  734. X * line, terminates PGetString; otherwise, it moves to the next line.
  735. X * ESC terminates PGetString regardless of the cursor position.
  736. X * Backspacing from the beginning of one line to the end of the previous
  737. X * is allowed.
  738. X *----------------------------------------------------------------------
  739. X */
  740. X
  741. XPRIVATE PGetString(buf,len,lines,nls,y,x)
  742. Xchar *buf, *lines[];
  743. Xint len, nls, y, x;
  744. X{
  745. Xchar c, *bp, *p;
  746. Xint cl, l;
  747. X
  748. Xfor (cl = 0; cl < nls; cl++) {
  749. X    lines[cl] = NULL;        /* clear line pointers */
  750. X    mvaddstr(y+cl,x,BLANKS(len));    /* clear line */
  751. X    }
  752. Xcl = 0;                    /* current line = 0 */
  753. Xl = 0;                /* length of current line */
  754. Xmove(y,x);            /* go to first location in field */
  755. Xbp = buf;            /* ptr to next storage location */
  756. Xlines[0] = buf;            /* init first line pointer */
  757. Xrefresh();
  758. Xwhile (1) {
  759. X    switch (c = PGetChr(0)) {
  760. X    case '\177':        /* DEL */
  761. X    case '\b':        /* BS */
  762. X        if (l <= 0) {    /* at beginning of line */
  763. X            if (cl <= 0)    /* on first line */
  764. X                break;        /* nothing to delete */
  765. X            cl--;        /* back up one line */
  766. X            *--bp = '\0';    /* back up buffer pointer */
  767. X            l = strlen(lines[cl]);    /* load line length */
  768. X            move(y+cl,x+l);    /* move cursor to end of prev line */
  769. X            }
  770. X        else {
  771. X            bp--;        /* back up buffer pointer */
  772. X            l--;        /* decrement length */
  773. X            move(y+cl,x+l);
  774. X            addch(' ');    /* erase the char from the screen */
  775. X            move(y+cl,x+l);
  776. X            }
  777. X        refresh();
  778. X        break;
  779. X    case '\2':        /* ^B -- erase previous character */
  780. X    case '\27':        /* ^W */
  781. X        if (l <= 0) {        /* beginning of line */
  782. X            if (cl <= 0)    /* on first line */
  783. X                break;        /* nothing to delete */
  784. X            cl--;        /* back up one line */
  785. X            *--bp = '\0';    /* back up buffer pointer */
  786. X            l = strlen(lines[cl]);    /* load line length */
  787. X            }
  788. X        while (l > 0) {        /* skip leading spaces, if any */
  789. X            if (*--bp != ' ') {
  790. X                bp++;
  791. X                break;
  792. X                }
  793. X            l--;
  794. X            *bp = '\0';
  795. X            }
  796. X        while (l > 0) {        /* delete to last space */
  797. X            if (*--bp == ' ') {
  798. X                bp++;
  799. X                break;
  800. X                }
  801. X            *bp = '\0';
  802. X            l--;
  803. X            mvaddch(y+cl,x+l,' ');
  804. X            }
  805. X        move(y+cl,x+l);
  806. X        refresh();
  807. X        break;
  808. X    case '\33':        /* ESC */
  809. X        *bp++ = '\0';        /* terminate the string */
  810. X        if (l <= 0)        /* empty line */
  811. X            return(cl);    /* don't include it in #lines */
  812. X        return(cl+1);    /* return number of lines */
  813. X    case '\r':        /* CR */
  814. X    case '\n':        /* NL */
  815. X        *bp++ = '\0';    /* terminate the string */
  816. X        if (l <= 0)        /* empty line */
  817. X            return(cl);    /* don't include it in #lines */
  818. X        if (cl >= nls-1)        /* last line */
  819. X            return(cl+1);    /* return number of lines */
  820. X        lines[++cl] = bp;    /* go to next line */
  821. X        l = 0;
  822. X        move(y+cl,x);
  823. X        refresh();
  824. X        break;
  825. X    case '\30':        /* ^X -- erase entire line & goto prev line */
  826. X    case '\25':        /* ^U */
  827. X        mvaddstr(y+cl,x,BLANKS(len));
  828. X        if (cl > 0) {    /* back up one line */
  829. X            bp = lines[cl--] - 1;
  830. X            l = strlen(lines[cl]);
  831. X            }
  832. X        else {        /* already on top line, go to beginning */
  833. X            bp = buf;
  834. X            l = 0;
  835. X            }
  836. X        move(y+cl,x+l);
  837. X        refresh();
  838. X        break;
  839. X    case '\t':            /* convert tab to a space */
  840. X        c = ' ';
  841. X        /* fall through */
  842. X    default:
  843. X        if (iscntrl(c)){        /* bad char */
  844. X            fputc('\7',stderr);    /* beep */
  845. X            fflush(stderr);
  846. X            break;            /* & ignore character */
  847. X            }
  848. X        if (l >= len) {        /* typed up to end of line */
  849. X            if (cl >= nls-1) {    /* last line, can't go on */
  850. X                fputc('\7',stderr);    /* beep */
  851. X                fflush(stderr);
  852. X                break;        /* & ignore character */
  853. X                }
  854. X            *bp++ = c;        /* store rcvd char */
  855. X            for (p = bp-1; (l > 0) && (! isspace(*p)); p--, l--);
  856. X            if ( (p <= buf) || (*p == '\0') ) {
  857. X                *bp++ = '\0';
  858. X                lines[++cl] = bp;    /* didn't find word */
  859. X                l = 0;
  860. X                }
  861. X            else {
  862. X                *p++ = '\0';    /* terminate previous line */
  863. X                mvaddstr(y+cl,x,BLANKS(len));    /* redraw */
  864. X                mvaddstr(y+cl,x,lines[cl]);    /* w/o word */
  865. X                lines[++cl] = p;    /* start new line */
  866. X                *bp = '\0';        /* terminate word */
  867. X                l = strlen(p);        /* set line len */
  868. X                mvaddstr(y+cl,x,p);    /* draw word */
  869. X                }
  870. X            move(y+cl,x+l);
  871. X            }
  872. X        else {
  873. X            *bp++ = c;        /* put char in string */
  874. X            l++;            /* bump length */
  875. X            addch(c);        /* echo char to screen */
  876. X            }
  877. X        refresh();
  878. X        break;
  879. X        }
  880. X    }
  881. X}
  882. X
  883. X
  884. X/*----------------------------------------------------------------------
  885. X *    FeDrawMenu -- draw menu choices in menu box
  886. X *
  887. X * This function takes an array of strings, terminated by a NULL
  888. X * pointer, and writes each string into successive lines of the
  889. X * menu box in the bottom right corner of the screen.  If there are
  890. X * more strings than will fit in the box, the extra strings are
  891. X * ignored.  If NULL is passed as the menu array, the menu box
  892. X * is cleared.
  893. X *----------------------------------------------------------------------
  894. X */
  895. X
  896. XFeDrawMenu(m)
  897. Xchar *m[];
  898. X{
  899. Xint i;
  900. X
  901. Xfor (i = 0; i < 5; i++) {        /* clear all lines in menu box */
  902. X    move(19+i,63);
  903. X    clrtoeol();
  904. X    }
  905. Xif (m == NULL)                /* no menu to display */
  906. X    return;
  907. Xfor (i = 0; (m[i] != NULL) && (i < 5); i++) {
  908. X    if (strlen(m[i]) > 15)        /* menu string is too long */
  909. X        m[15] = '\0';        /* so shorten it */
  910. X    mvaddstr(19+i,64,m[i]);        /* put string in menu area */
  911. X    }
  912. Xrefresh();
  913. X}
  914. X
  915. X
  916. X/*----------------------------------------------------------------------
  917. X *    FeMenu -- get menu choice from user
  918. X *
  919. X * This function accepts a menu choice from the user.  The menu choices
  920. X * are passed as an array of strings, terminated by a NULL pointer.
  921. X * Users select one of these strings by typing the first letter of the
  922. X * string, thus the first letter of the strings must be unique.
  923. X *
  924. X * FeMenu also handles two special cases:
  925. X *    1. The user types a number between 1 and 6 (a roll)
  926. X *    2. The user types some character that the caller wishes
  927. X *       to handle directly.
  928. X * If a roll entry is valid, the caller may pass up to two different
  929. X * rolls that are valid in the r1 and r2 arguments.  Any characters
  930. X * the caller wishes to handle are passed as a string in the
  931. X * "extra" argument.  These typically include space and newline.
  932. X *----------------------------------------------------------------------
  933. X */
  934. X
  935. Xchar FeMenu(m,r1,r2,extra)
  936. Xchar *m[];            /* array of menu choices */
  937. Xint r1, r2;            /* rolls (pass 0 if no roll valid) */
  938. Xchar *extra;            /* chars that caller wants to handle */
  939. X{
  940. Xint i;
  941. Xchar c, x;
  942. X
  943. Xwhile (1) {
  944. X    mvaddch(18,69,' ');
  945. X    move(18,69);            /* put cursor in its little box */
  946. X    refresh();
  947. X    c = PGetChr(1);            /* get a character */
  948. X    FeMessage(NULL);        /* clear message line */
  949. X    if ( (extra != NULL) && (strchr(extra,c) != NULL) )
  950. X        return(c);        /* these chars are handled by caller */
  951. X    if ( (c >= '1') && (c <= '6') ) {    /* handle digits differently */
  952. X        if (r1 <= 0) {
  953. X            FeMessage("Roll not valid here.");
  954. X            continue;
  955. X            }
  956. X        x = c - '0';        /* convert to number */
  957. X        if ( (x == r1) || (x == r2) )    /* is it a valid roll? */
  958. X            return(c);        /* yup, return it */
  959. X        FeMessage("No such roll.");
  960. X        continue;
  961. X        }
  962. X    if (islower(c))            /* ignore case */
  963. X        c = toupper(c);
  964. X    for (i = 0; m[i] != NULL; i++) {    /* search menu strings */
  965. X        x = *m[i];
  966. X        if (islower(x))            /* ignore case */
  967. X            x = toupper(x);
  968. X        if (c == x)            /* found it */
  969. X            return(c);
  970. X        }
  971. X    FeMessage("Invalid command.");
  972. X    }
  973. X}
  974. X
  975. X
  976. X/*----------------------------------------------------------------------
  977. X *    FeMessage -- print a highlighted message on bottom line
  978. X *
  979. X * This function prints a string in reverse video on line 23.
  980. X * The message length is restricted to 62 characters to avoid
  981. X * running into the menu box.  If NULL is passed as a message,
  982. X * the message line is cleared.
  983. X *----------------------------------------------------------------------
  984. X */
  985. X
  986. XFeMessage(s)
  987. Xchar *s;
  988. X{
  989. Xchar c = 0;
  990. X
  991. Xmvaddstr(23,0,BLANKS(62));        /* clear message line */
  992. Xif (s != NULL) {        /* if we have a message to print */
  993. X    if (strlen(s) > 62) {    /* check that it's not too long */
  994. X        c = s[62];    /* save char at this position */
  995. X        s[62] = '\0';    /* and end the string */
  996. X        }
  997. X    move(23,0);
  998. X    standout();
  999. X    addstr(s);        /* print the message */
  1000. X    standend();
  1001. X    if (c != '\0')        /* if we shortened it, restore it */
  1002. X        s[62] = c;
  1003. X    }
  1004. Xrefresh();
  1005. X}
  1006. X
  1007. X
  1008. X/*----------------------------------------------------------------------
  1009. X *    FeStatusLine -- draw string on status line
  1010. X *
  1011. X * This function puts a string on line 18 in reverse video.  It is
  1012. X * used to display blots hit, double offers, etc.
  1013. X *----------------------------------------------------------------------
  1014. X */
  1015. X
  1016. XFeStatusLine(s)
  1017. Xchar *s;
  1018. X{
  1019. Xchar c = 0;
  1020. Xint l;
  1021. X
  1022. Xmvaddstr(18,10,BLANKS(50));    /* clear status line */
  1023. Xif (s != NULL) {        /* if we have a message to print */
  1024. X    if ( (l = strlen(s)) > 50) {    /* check that it's not too long */
  1025. X        c = s[50];    /* save char at this position */
  1026. X        s[50] = '\0';    /* and end the string */
  1027. X        l = 50;
  1028. X        }
  1029. X    move(18,(50 - l)/2 + 10);
  1030. X    standout();
  1031. X    addstr(s);        /* print the message */
  1032. X    standend();
  1033. X    if (c != '\0')        /* if we shortened it, restore it */
  1034. X        s[50] = c;
  1035. X    }
  1036. Xrefresh();
  1037. X}
  1038. X
  1039. X
  1040. X/*----------------------------------------------------------------------
  1041. X *    FeDrawCube -- draw doubling cube
  1042. X *
  1043. X * This function draws the doubling cube.  The cube is displayed beside
  1044. X * the inner table of the player who owns in (i.e. the one who didn't
  1045. X * double last).  If neither player has doubled, the cube is drawn
  1046. X * in the middle of the board.
  1047. X *----------------------------------------------------------------------
  1048. X */
  1049. X
  1050. XFeDrawCube(g)
  1051. Xstruct game *g;
  1052. X{
  1053. Xint r, c;
  1054. Xchar buf[8];
  1055. X
  1056. Xmvaddstr(3,0,"    ");        /* clear all cube locations */
  1057. Xmvaddstr(10,0,"    ");
  1058. Xmvaddstr(17,0,"    ");
  1059. Xif (g->gameval == (1 << g->adcnt))    /* nobody has doubled */
  1060. X    r = 10;            /* cube is in the middle of the board */
  1061. Xelse {            /* assume I didn't double last, mydir is up, */
  1062. X    r = 0;        /* and board is not inverted */
  1063. X    if (g->flags & F_IDOUBLED)    /* if I did double last */
  1064. X        r = 1 - r;        /* switch rows */
  1065. X    if (g->mydir < 0)        /* if my direction is down */
  1066. X        r = 1 - r;        /* switch rows */
  1067. X    if (g->flags & F_INVERT)    /* if board is inverted */
  1068. X        r = 1 - r;        /* switch rows */
  1069. X    r = r ? 17 : 3;            /* which row am I left with? */
  1070. X    }
  1071. X
  1072. Xsprintf(buf,"%d",g->gameval);        /* generate the game value */
  1073. Xif ( (c = 4 - strlen(buf)) < 0) {    /* doubled past 4 digits? */
  1074. X    strcpy(buf,"****");        /* we are out of columns */
  1075. X    c = 0;
  1076. X    }
  1077. Xmove(r,c);
  1078. Xstandout();
  1079. Xmvaddstr(r,c,buf);        /* go there and draw game value */
  1080. Xstandend();
  1081. X}
  1082. X
  1083. X
  1084. X/*----------------------------------------------------------------------
  1085. X *    PDrawComment -- print a comment stored in a game
  1086. X *
  1087. X * This function takes a pointer to a game and draws the comment
  1088. X * strings to the screen.  If "who" is 0, the "mycmt" strings
  1089. X * are drawn on lines 19 and 20.  Otherwise, the "opcmt" strings
  1090. X * are drawn on lines 21 and 22.  Any unused space on these lines
  1091. X * is cleared.
  1092. X *----------------------------------------------------------------------
  1093. X */
  1094. X
  1095. XPRIVATE PDrawComment(who,g)
  1096. Xint who;
  1097. Xstruct game *g;
  1098. X{
  1099. Xint line;
  1100. Xchar *s1, *s2;
  1101. X
  1102. Xline = who ? 21 : 19;
  1103. Xs1 = who ? g->opcmt : g->mycmt;
  1104. Xs2 = who ? g->opcmt2 : g->mycmt2;
  1105. Xmvaddstr(line,6,BLANKS(56));
  1106. Xmvaddstr(line+1,6,BLANKS(56));
  1107. Xif (s1 != NULL) {
  1108. X    if (strlen(s1) > 56)
  1109. X        s1[56] = '\0';
  1110. X    mvaddstr(line,6,s1);
  1111. X    }
  1112. Xif (s2 != NULL) {
  1113. X    if (strlen(s2) > 56)
  1114. X        s2[56] = '\0';
  1115. X    mvaddstr(line+1,6,s2);
  1116. X    }
  1117. X}
  1118. END_OF_FILE
  1119. if test 33230 -ne `wc -c <'fe_curses.c'`; then
  1120.     echo shar: \"'fe_curses.c'\" unpacked with wrong size!
  1121. fi
  1122. chmod +x 'fe_curses.c'
  1123. # end of 'fe_curses.c'
  1124. fi
  1125. echo shar: End of archive 5 \(of 5\).
  1126. cp /dev/null ark5isdone
  1127. MISSING=""
  1128. for I in 1 2 3 4 5 ; do
  1129.     if test ! -f ark${I}isdone ; then
  1130.     MISSING="${MISSING} ${I}"
  1131.     fi
  1132. done
  1133. if test "${MISSING}" = "" ; then
  1134.     echo You have unpacked all 5 archives.
  1135.     rm -f ark[1-9]isdone
  1136. else
  1137.     echo You still need to unpack the following archives:
  1138.     echo "        " ${MISSING}
  1139. fi
  1140. ##  End of shell archive.
  1141. exit 0
  1142.  
  1143.  
  1144. exit 0 # Just in case...
  1145.