home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / games / rogue / curses.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-08  |  13.2 KB  |  695 lines

  1. /*
  2.  * Copyright (c) 1988 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Timothy C. Stoehr.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)curses.c    5.3 (Berkeley) 6/1/90";
  39. #endif /* not lint */
  40.  
  41. /*
  42.  * curses.c
  43.  *
  44.  * This source herein may be modified and/or distributed by anybody who
  45.  * so desires, with the following restrictions:
  46.  *    1.)  No portion of this notice shall be removed.
  47.  *    2.)  Credit shall not be taken for the creation of this source.
  48.  *    3.)  This code is not to be traded, sold, or used for personal
  49.  *         gain or profit.
  50.  *
  51.  */
  52.  
  53. #ifdef CURSES
  54.  
  55. /* The following is a curses emulation package suitable for the rogue program
  56.  * in which it is included.  No other suitability is claimed or suspected.
  57.  * Only those routines currently needed by this rogue program are included.
  58.  * This is being provided for those systems that don't have a suitable
  59.  * curses package and want to run this rogue program.
  60.  *
  61.  * Compile the entire program with -DCURSES to incorporate this package.
  62.  *
  63.  * The following is NOT supported:
  64.  *   "%D", "%B", "%n", or "%>" inside a cursor motion (cm) termcap string.
  65.  *   Terminals in which the cursor motion addresses the row differently from
  66.  *       the column, as in ":cm=\E%2,%3" or ":cm=\EY%+x;%+y"
  67.  *   Termcap database stored in the TERMCAP environ variable as returned
  68.  *       from md_getenv().  Only the termcap file name can be stored there.
  69.  *       See the comments for md_getenv() in machdep.c.
  70.  *   Terminals without non-destructive backspace.  Backspace (^H) is used
  71.  *       for cursor motion regardless of any termcap entries.
  72.  *   The ":tc=" termcap entry is ignored.
  73.  *
  74.  * Suggestions:
  75.  *   Use line-feed as your termcap "do" entry: ":do=^J", ":do=\012" or
  76.  *      ":do=\n"  This will help cursor motion optimization.  If line-feed
  77.  *      won't work, then a short escape sequence will do.
  78.  */
  79.  
  80. #include <stdio.h>
  81. #include "rogue.h"
  82.  
  83. boolean tc_tname();
  84.  
  85. #define BS 010
  86. #define LF 012
  87. #define CR 015
  88. #define ESC '\033'
  89. #define TAB '\011'
  90.  
  91. #define ST_MASK 0x80
  92. #define BUFLEN 256
  93.  
  94. char terminal[DROWS][DCOLS];
  95. char buffer[DROWS][DCOLS];
  96. char *tc_file;
  97.  
  98. char cm_esc[16];
  99. char cm_sep[16];
  100. char cm_end[16];
  101. boolean cm_reverse = 0;
  102. boolean cm_two = 0;
  103. boolean cm_three = 0;
  104. boolean cm_char = 0;
  105. short cm_inc = 0;
  106.  
  107. boolean screen_dirty;
  108. boolean lines_dirty[DROWS];
  109. boolean buf_stand_out = 0;
  110. boolean term_stand_out = 0;
  111.  
  112. int LINES = DROWS;
  113. int COLS = DCOLS;
  114. WINDOW scr_buf;
  115. WINDOW *curscr = &scr_buf;
  116.  
  117. char *CL = (char *) 0;
  118. char *CM = (char *) 0;
  119. char *UC = (char *) 0;    /* UP */
  120. char *DO = (char *) 0;
  121. char *VS = "";
  122. char *VE = "";
  123. char *TI = "";
  124. char *TE = "";
  125. char *SO = "";
  126. char *SE = "";
  127.  
  128. short cur_row;
  129. short cur_col;
  130.  
  131. initscr()
  132. {
  133.     clear();
  134.     get_term_info();
  135.     printf("%s%s", TI, VS);
  136. }
  137.  
  138. endwin()
  139. {
  140.     printf("%s%s", TE, VE);
  141.     md_cbreak_no_echo_nonl(0);
  142. }
  143.  
  144. move(row, col)
  145. short row, col;
  146. {
  147.     curscr->_cury = row;
  148.     curscr->_curx = col;
  149.     screen_dirty = 1;
  150. }
  151.  
  152. mvaddstr(row, col, str)
  153. short row, col;
  154. char *str;
  155. {
  156.     move(row, col);
  157.     addstr(str);
  158. }
  159.  
  160. addstr(str)
  161. char *str;
  162. {
  163.     while (*str) {
  164.         addch((int) *str++);
  165.     }
  166. }
  167.  
  168. addch(ch)
  169. register int ch;
  170. {
  171.     short row, col;
  172.  
  173.     row = curscr->_cury;
  174.     col = curscr->_curx++;
  175.  
  176.     if (buf_stand_out) {
  177.         ch |= ST_MASK;
  178.     }
  179.     buffer[row][col] = (char) ch;
  180.     lines_dirty[row] = 1;
  181.     screen_dirty = 1;
  182. }
  183.  
  184. mvaddch(row, col, ch)
  185. short row, col;
  186. int ch;
  187. {
  188.     move(row, col);
  189.     addch(ch);
  190. }
  191.  
  192. refresh()
  193. {
  194.     register i, j, line;
  195.     short old_row, old_col, first_row;
  196.  
  197.     if (screen_dirty) {
  198.  
  199.         old_row = curscr->_cury;
  200.         old_col = curscr->_curx;
  201.         first_row = cur_row;
  202.  
  203.         for (i = 0; i < DROWS; i++) {
  204.             line = (first_row + i) % DROWS;
  205.             if (lines_dirty[line]) {
  206.                 for (j = 0; j < DCOLS; j++) {
  207.                     if (buffer[line][j] != terminal[line][j]) {
  208.                         put_char_at(line, j, buffer[line][j]);
  209.                     }
  210.                 }
  211.                 lines_dirty[line] = 0;
  212.             }
  213.         }
  214.         put_cursor(old_row, old_col);
  215.         screen_dirty = 0;
  216.         fflush(stdout);
  217.     }
  218. }
  219.  
  220. wrefresh(scr)
  221. WINDOW *scr;
  222. {
  223.     short i, col;
  224.  
  225.     printf("%s", CL);
  226.     cur_row = cur_col = 0;
  227.  
  228.     for (i = 0; i < DROWS; i++) {
  229.         col = 0;
  230.         while (col < DCOLS) {
  231.             while ((col < DCOLS) && (buffer[i][col] == ' ')) {
  232.                 col++;
  233.             }
  234.             if (col < DCOLS) {
  235.                 put_cursor(i, col);
  236.             }
  237.             while ((col < DCOLS) && (buffer[i][col] != ' ')) {
  238.                 put_st_char((int) buffer[i][col]);
  239.                 cur_col++;
  240.                 col++;
  241.             }
  242.         }
  243.     }
  244.     put_cursor(curscr->_cury, curscr->_curx);
  245.     fflush(stdout);
  246.     scr = scr;        /* make lint happy */
  247. }
  248.  
  249. mvinch(row, col)
  250. short row, col;
  251. {
  252.     move(row, col);
  253.     return((int) buffer[row][col]);
  254. }
  255.  
  256. clear()
  257. {
  258.     printf("%s", CL);
  259.     fflush(stdout);
  260.     cur_row = cur_col = 0;
  261.     move(0, 0);
  262.     clear_buffers();
  263. }
  264.  
  265. clrtoeol()
  266. {
  267.     short row, col;
  268.  
  269.     row = curscr->_cury;
  270.  
  271.     for (col = curscr->_curx; col < DCOLS; col++) {
  272.         buffer[row][col] = ' ';
  273.     }
  274.     lines_dirty[row] = 1;
  275. }
  276.  
  277. standout()
  278. {
  279.     buf_stand_out = 1;
  280. }
  281.  
  282. standend()
  283. {
  284.     buf_stand_out = 0;
  285. }
  286.  
  287. crmode()
  288. {
  289.     md_cbreak_no_echo_nonl(1);
  290. }
  291.  
  292. noecho()
  293. {
  294.     /* crmode() takes care of this */
  295. }
  296.  
  297. nonl()
  298. {
  299.     /* crmode() takes care of this */
  300. }
  301.  
  302. clear_buffers()
  303. {
  304.     register i, j;
  305.  
  306.     screen_dirty = 0;
  307.  
  308.     for (i = 0; i < DROWS; i++) {
  309.         lines_dirty[i] = 0;
  310.         for (j = 0; j < DCOLS; j++) {
  311.             terminal[i][j] = ' ';
  312.             buffer[i][j] = ' ';
  313.         }
  314.     }
  315. }
  316.  
  317. put_char_at(row, col, ch)
  318. register row, col, ch;
  319. {
  320.     put_cursor(row, col);
  321.     put_st_char(ch);
  322.     terminal[row][col] = (char) ch;
  323.     cur_col++;
  324. }
  325.  
  326. put_cursor(row, col)
  327. register row, col;
  328. {
  329.     register i, rdif, cdif;
  330.     short ch, t;
  331.  
  332.     rdif = (row > cur_row) ? row - cur_row : cur_row - row;
  333.     cdif = (col > cur_col) ? col - cur_col : cur_col - col;
  334.  
  335.     if (((row > cur_row) && DO) || ((cur_row > row) && UC)) {
  336.         if ((rdif < 4) && (cdif < 4)) {
  337.             for (i = 0; i < rdif; i++) {
  338.                 printf("%s", ((row < cur_row) ? UC : DO));
  339.             }
  340.             cur_row = row;
  341.             if (col == cur_col) {
  342.                 return;
  343.             }
  344.         }
  345.     }
  346.     if (row == cur_row) {
  347.         if (cdif <= 6) {
  348.         for (i = 0; i < cdif; i++) {
  349.                 ch = (col < cur_col) ? BS :
  350.                         terminal[row][cur_col + i];
  351.                 put_st_char((int) ch);
  352.             }
  353.             cur_row = row;
  354.             cur_col = col;
  355.             return;
  356.         }
  357.     }
  358.     cur_row = row;
  359.     cur_col = col;
  360.  
  361.     row += cm_inc;
  362.     col += cm_inc;
  363.  
  364.     if (cm_reverse) {
  365.         t = row;
  366.         row = col;
  367.         col = t;
  368.     }
  369.     if (cm_two) {
  370.         printf("%s%02d%s%02d%s", cm_esc, row, cm_sep, col, cm_end);
  371.     } else if (cm_three) {
  372.         printf("%s%03d%s%03d%s", cm_esc, row, cm_sep, col, cm_end);
  373.     } else if (cm_char) {
  374.         printf("%s%c%s%c%s", cm_esc, row, cm_sep, col, cm_end);
  375.     } else {
  376.         printf("%s%d%s%d%s", cm_esc, row, cm_sep, col, cm_end);
  377.     }
  378. }
  379.  
  380. put_st_char(ch)
  381. register ch;
  382. {
  383.     if ((ch & ST_MASK) && (!term_stand_out)) {
  384.         ch &= ~ST_MASK;
  385.         printf("%s%c", SO, ch);
  386.         term_stand_out = 1;
  387.     } else if ((!(ch & ST_MASK)) && term_stand_out) {
  388.         printf("%s%c", SE, ch);
  389.         term_stand_out = 0;
  390.     } else {
  391.         ch &= ~ST_MASK;
  392.         putchar(ch);
  393.     }
  394. }
  395.  
  396. get_term_info()
  397. {
  398.     FILE *fp;
  399.     char *term, *tcf;
  400.     char buf[BUFLEN];
  401.  
  402.     if (tcf = md_getenv("TERMCAP")) {
  403.         if (strlen(tcf) > 40) {
  404.             clean_up("TERMCAP file name too long");
  405.         }
  406.         tc_file = tcf;
  407.     } else {
  408.         if (!(tc_file = md_gdtcf())) {
  409.             clean_up("I need a termcap file");
  410.         }
  411.     }
  412.  
  413.     if (!(term = md_getenv("TERM"))) {
  414.         clean_up("Cannot find TERM variable in environ");
  415.     }
  416.     if ((fp = fopen(tc_file, "r")) == NULL) {
  417.         sprintf(buf, "Cannot open TERMCAP file: %s", tc_file);
  418.         clean_up(buf);
  419.     }
  420.  
  421.     if (!tc_tname(fp, term, buf)) {
  422.         sprintf(buf, "Cannot find TERM type: %s in TERMCAP file: %s", term,
  423.             tc_file);
  424.         clean_up(buf);
  425.     }
  426.     tc_gtdata(fp, buf);
  427.     fclose(fp);
  428. }
  429.  
  430. boolean
  431. tc_tname(fp, term, buf)
  432. FILE *fp;
  433. char *term;
  434. char *buf;
  435. {
  436.     short i, j;
  437.     boolean found = 0;
  438.     char *fg;
  439.  
  440.     while (!found) {
  441.         i = 0;
  442.         fg = fgets(buf, BUFLEN, fp);
  443.         if (fg != NULL) {
  444.             if (    (buf[0] != '#') && (buf[0] != ' ') && (buf[0] != TAB) &&
  445.                     (buf[0] != CR) && (buf[0] != LF)) {
  446.                 while (buf[i] && (!found)) {
  447.                     j = 0;
  448.                     while (buf[i] == term[j]) {
  449.                         i++;
  450.                         j++;
  451.                     }
  452.                     if ((!term[j]) && ((buf[i] == '|') || (buf[i] == ':'))) {
  453.                         found = 1;
  454.                     } else {
  455.                         while (buf[i] && (buf[i] != '|') && (buf[i] != ':')) {
  456.                             i++;
  457.                         }
  458.                         if (buf[i]) {
  459.                             i++;
  460.                         }
  461.                     }
  462.                 }
  463.             }
  464.         } else {
  465.             break;
  466.         }
  467.     }
  468.     return(found);
  469. }
  470.  
  471. tc_gtdata(fp, buf)
  472. FILE *fp;
  473. char *buf;
  474. {
  475.     short i;
  476.     boolean first = 1;
  477.  
  478.     do {
  479.         if (!first) {
  480.             if ((buf[0] != TAB) && (buf[0] != ' ')) {
  481.                 break;
  482.             }
  483.         }
  484.         first = 0;
  485.         i = 0;
  486.         while (buf[i]) {
  487.             while (buf[i] && (buf[i] != ':')) {
  488.                 i++;
  489.             }
  490.             if (buf[i] == ':') {
  491.                 if (!strncmp(buf + i, ":cl=", 4)) {
  492.                     tc_gets(buf + i, &CL);
  493.                 } else if (!strncmp(buf + i, ":cm=", 4)) {
  494.                     tc_gets(buf + i, &CM);
  495.                 } else if (!strncmp(buf + i, ":up=", 4)) {
  496.                     tc_gets(buf + i, &UC);
  497.                 } else if (!strncmp(buf + i, ":do=", 4)) {
  498.                     tc_gets(buf + i, &DO);
  499.                 } else if (!strncmp(buf + i, ":vs=", 4)) {
  500.                     tc_gets(buf + i, &VS);
  501.                 } else if (!strncmp(buf + i, ":ve=", 4)) {
  502.                     tc_gets(buf + i, &VE);
  503.                 } else if (!strncmp(buf + i, ":ti=", 4)) {
  504.                     tc_gets(buf + i, &TI);
  505.                 } else if (!strncmp(buf + i, ":te=", 4)) {
  506.                     tc_gets(buf + i, &TE);
  507.                 } else if (!strncmp(buf + i, ":vs=", 4)) {
  508.                     tc_gets(buf + i, &VS);
  509.                 } else if (!strncmp(buf + i, ":ve=", 4)) {
  510.                     tc_gets(buf + i, &VE);
  511.                 } else if (!strncmp(buf + i, ":so=", 4)) {
  512.                     tc_gets(buf + i, &SO);
  513.                 } else if (!strncmp(buf + i, ":se=", 4)) {
  514.                     tc_gets(buf + i, &SE);
  515.                 } else if (!strncmp(buf + i, ":li#", 4)) {
  516.                     tc_gnum(buf + i, &LINES);
  517.                 } else if (!strncmp(buf + i, ":co#", 4)) {
  518.                     tc_gnum(buf + i, &COLS);
  519.                 }
  520.                 i++;
  521.             }
  522.         }
  523.     } while (fgets(buf, BUFLEN, fp) != NULL);
  524.  
  525.     if ((!CM) || (!CL)) {
  526.         clean_up("Terminal and termcap must have cm and cl");
  527.     }
  528.     tc_cmget();
  529. }
  530.  
  531. tc_gets(ibuf, tcstr)
  532. char *ibuf;
  533. char **tcstr;
  534. {
  535.     short i, j, k, n;
  536.     char obuf[BUFLEN];
  537.  
  538.     i = 4;
  539.     j = 0;
  540.  
  541.     while (ibuf[i] && is_digit(ibuf[i])) {
  542.         i++;
  543.     }
  544.  
  545.     while (ibuf[i] && (ibuf[i] != ':')) {
  546.         if (ibuf[i] == '\\') {
  547.             i++;
  548.             switch(ibuf[i]) {
  549.             case 'E':
  550.                 obuf[j] = ESC;
  551.                 i++;
  552.                 break;
  553.             case 'n':
  554.                 obuf[j] = LF;
  555.                 i++;
  556.                 break;
  557.             case 'r':
  558.                 obuf[j] = CR;
  559.                 i++;
  560.                 break;
  561.             case 'b':
  562.                 obuf[j] = BS;
  563.                 i++;
  564.                 break;
  565.             case 't':
  566.                 obuf[j] = TAB;
  567.                 i++;
  568.                 break;
  569.             case '0':
  570.             case '1':
  571.             case '2':
  572.             case '3':
  573.             case '4':
  574.             case '5':
  575.             case '6':
  576.             case '7':
  577.             case '8':
  578.             case '9':
  579.                 n = 0;
  580.                 k = 0;
  581.                 while (k < 3 && ibuf[i] && is_digit(ibuf[i])) {
  582.                     n = (8 * n) + (ibuf[i] - '0');
  583.                     i++;
  584.                     k++;
  585.                 }
  586.                 obuf[j] = (char) n;
  587.                 break;
  588.             default:
  589.                 obuf[j] = ibuf[i];
  590.                 i++;
  591.             }
  592.         } else if (ibuf[i] == '^') {
  593.             obuf[j] = ibuf[i+1] - 64;
  594.             i += 2;
  595.         } else {
  596.             obuf[j] = ibuf[i++];
  597.         }
  598.         j++;
  599.     }
  600.     obuf[j] = 0;
  601.     if (!(*tcstr = md_malloc(j + 1))) {
  602.         clean_up("cannot alloc() memory");
  603.     }
  604.     (void) strcpy(*tcstr, obuf);
  605. }
  606.  
  607. tc_gnum(ibuf, n)
  608. char *ibuf;
  609. int *n;
  610. {
  611.     short i;
  612.     int r = 0;
  613.  
  614.     i = 4;
  615.  
  616.     while (is_digit(ibuf[i])) {
  617.         r = (r * 10) + (ibuf[i] - '0');
  618.         i++;
  619.     }
  620.     *n = r;
  621. }
  622.  
  623. tstp()
  624. {
  625.     endwin();
  626.     md_tstp();
  627.  
  628.     start_window();
  629.     printf("%s%s", TI, VS);
  630.     wrefresh(curscr);
  631.     md_slurp();
  632. }
  633.  
  634. tc_cmget()
  635. {
  636.     short i = 0, j = 0, rc_spec = 0;
  637.  
  638.     while (CM[i] && (CM[i] != '%') && (j < 15)) {
  639.         cm_esc[j++] = CM[i++];
  640.     }
  641.     cm_esc[j] = 0;
  642.  
  643.     while (CM[i] && (rc_spec < 2)) {
  644.         if (CM[i] == '%') {
  645.             i++;
  646.             switch(CM[i]) {
  647.             case 'd':
  648.                 rc_spec++;
  649.                 break;
  650.             case 'i':
  651.                 cm_inc = 1;
  652.                 break;
  653.             case '2':
  654.                 cm_two = 1;
  655.                 rc_spec++;
  656.                 break;
  657.             case '3':
  658.                 cm_three = 1;
  659.                 rc_spec++;
  660.                 break;
  661.             case '.':
  662.                 cm_char = 1;
  663.                 rc_spec++;
  664.                 break;
  665.             case 'r':
  666.                 cm_reverse = 1;
  667.                 break;
  668.             case '+':
  669.                 i++;
  670.                 cm_inc = CM[i];
  671.                 cm_char = 1;
  672.                 rc_spec++;
  673.                 break;
  674.             }
  675.             i++;
  676.         } else {
  677.             j = 0;
  678.             while (CM[i] && (CM[i] != '%')) {
  679.                 cm_sep[j++] = CM[i++];
  680.             }
  681.             cm_sep[j] = 0;
  682.         }
  683.     }
  684.  
  685.     j = 0;
  686.     if (rc_spec == 2) {
  687.         while (CM[i] && (j < 15)) {
  688.             cm_end[j++] = CM[i++];
  689.         }
  690.     }
  691.     cm_end[j] = 0;
  692. }
  693.  
  694. #endif
  695.