rts-curses.c

     
   1  //! @file rts-curses.c
   2  //! @author J. Marcel van der Veer
   3  //!
   4  //! @section Copyright
   5  //!
   6  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   7  //! Copyright 2001-2023 J. Marcel van der Veer [algol68g@xs4all.nl].
   8  //!
   9  //! @section License
  10  //!
  11  //! This program is free software; you can redistribute it and/or modify it 
  12  //! under the terms of the GNU General Public License as published by the 
  13  //! Free Software Foundation; either version 3 of the License, or 
  14  //! (at your option) any later version.
  15  //!
  16  //! This program is distributed in the hope that it will be useful, but 
  17  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  18  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  19  //! more details. You should have received a copy of the GNU General Public 
  20  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  21  
  22  //! @section Synopsis
  23  //!
  24  //! Curses interface. 
  25  
  26  #include "a68g.h"
  27  #include "a68g-genie.h"
  28  #include "a68g-prelude.h"
  29  
  30  // Some routines that interface Algol68G and the curses library.
  31  
  32  #if defined (HAVE_CURSES)
  33  
  34  #define CHECK_CURSES_RETVAL(f) {\
  35    if (!(f)) {\
  36      diagnostic (A68_RUNTIME_ERROR, p, ERROR_CURSES);\
  37      exit_genie (p, A68_RUNTIME_ERROR);\
  38    }}
  39  
  40  //! @brief Clean_curses.
  41  
  42  void clean_curses (void)
  43  {
  44    if (A68 (curses_mode) == A68_TRUE) {
  45      (void) wattrset (stdscr, A_NORMAL);
  46      (void) endwin ();
  47      A68 (curses_mode) = A68_FALSE;
  48    }
  49  }
  50  
  51  //! @brief Init_curses.
  52  
  53  void init_curses (void)
  54  {
  55    (void) initscr ();
  56    (void) cbreak ();             // raw () would cut off ctrl-c
  57    (void) noecho ();
  58    (void) nonl ();
  59    (void) curs_set (0);
  60    if (has_colors ()) {
  61      (void) start_color ();
  62    }
  63  }
  64  
  65  //! @brief Watch stdin for input, do not wait very long.
  66  
  67  int rgetchar (void)
  68  {
  69  #if defined (BUILD_WIN32)
  70    if (kbhit ()) {
  71      return getch ();
  72    } else {
  73      return NULL_CHAR;
  74    }
  75  #else
  76    int retval;
  77    struct timeval tv;
  78    fd_set rfds;
  79    TV_SEC (&tv) = 0;
  80    TV_USEC (&tv) = 100;
  81    FD_ZERO (&rfds);
  82    FD_SET (0, &rfds);
  83    retval = select (1, &rfds, NULL, NULL, &tv);
  84    if (retval) {
  85  // FD_ISSET(0, &rfds) will be true.  
  86      return getch ();
  87    } else {
  88      return NULL_CHAR;
  89    }
  90  #endif
  91  }
  92  
  93  //! @brief PROC curses start = VOID
  94  
  95  void genie_curses_start (NODE_T * p)
  96  {
  97    (void) p;
  98    init_curses ();
  99    A68 (curses_mode) = A68_TRUE;
 100  }
 101  
 102  //! @brief PROC curses end = VOID
 103  
 104  void genie_curses_end (NODE_T * p)
 105  {
 106    (void) p;
 107    clean_curses ();
 108  }
 109  
 110  //! @brief PROC curses clear = VOID
 111  
 112  void genie_curses_clear (NODE_T * p)
 113  {
 114    if (A68 (curses_mode) == A68_FALSE) {
 115      genie_curses_start (p);
 116    }
 117    CHECK_CURSES_RETVAL (clear () != ERR);
 118  }
 119  
 120  //! @brief PROC curses refresh = VOID
 121  
 122  void genie_curses_refresh (NODE_T * p)
 123  {
 124    if (A68 (curses_mode) == A68_FALSE) {
 125      genie_curses_start (p);
 126    }
 127    CHECK_CURSES_RETVAL (refresh () != ERR);
 128  }
 129  
 130  //! @brief PROC curses lines = INT
 131  
 132  void genie_curses_lines (NODE_T * p)
 133  {
 134    if (A68 (curses_mode) == A68_FALSE) {
 135      genie_curses_start (p);
 136    }
 137    PUSH_VALUE (p, LINES, A68_INT);
 138  }
 139  
 140  //! @brief PROC curses columns = INT
 141  
 142  void genie_curses_columns (NODE_T * p)
 143  {
 144    if (A68 (curses_mode) == A68_FALSE) {
 145      genie_curses_start (p);
 146    }
 147    PUSH_VALUE (p, COLS, A68_INT);
 148  }
 149  
 150  //! @brief PROC curses getchar = CHAR
 151  
 152  void genie_curses_getchar (NODE_T * p)
 153  {
 154    if (A68 (curses_mode) == A68_FALSE) {
 155      genie_curses_start (p);
 156    }
 157    PUSH_VALUE (p, (char) rgetchar (), A68_CHAR);
 158  }
 159  
 160  //! @brief PROC curses colour = VOID
 161  
 162  #define GENIE_COLOUR(f, n, fg, bg)\
 163  void f (NODE_T *p) {\
 164    (void) p;\
 165    if ((n) < COLOR_PAIRS) {\
 166      (void) init_pair (n, (fg), (bg));\
 167      wattrset (stdscr, COLOR_PAIR ((n)) | A_BOLD);\
 168    }\
 169  }\
 170  void f##_inverse (NODE_T *p) {\
 171    (void) p;\
 172    if ((n + 8) < COLOR_PAIRS) {\
 173      (void) init_pair ((n) + 8, (bg), (fg));\
 174      wattrset (stdscr, COLOR_PAIR (((n) + 8)));\
 175    }\
 176  }
 177  
 178  GENIE_COLOUR (genie_curses_blue, 1, COLOR_BLUE, COLOR_BLACK)
 179    GENIE_COLOUR (genie_curses_cyan, 2, COLOR_CYAN, COLOR_BLACK)
 180    GENIE_COLOUR (genie_curses_green, 3, COLOR_GREEN, COLOR_BLACK)
 181    GENIE_COLOUR (genie_curses_magenta, 4, COLOR_MAGENTA, COLOR_BLACK)
 182    GENIE_COLOUR (genie_curses_red, 5, COLOR_RED, COLOR_BLACK)
 183    GENIE_COLOUR (genie_curses_white, 6, COLOR_WHITE, COLOR_BLACK)
 184    GENIE_COLOUR (genie_curses_yellow, 7, COLOR_YELLOW, COLOR_BLACK)
 185  //! @brief PROC curses delchar = (CHAR) BOOL
 186       void genie_curses_del_char (NODE_T * p)
 187  {
 188    A68_CHAR ch;
 189    int v;
 190    POP_OBJECT (p, &ch, A68_CHAR);
 191    v = (int) VALUE (&ch);
 192    PUSH_VALUE (p, (BOOL_T) (v == 8 || v == 127 || v == KEY_BACKSPACE), A68_BOOL);
 193  }
 194  
 195  //! @brief PROC curses putchar = (CHAR) VOID
 196  
 197  void genie_curses_putchar (NODE_T * p)
 198  {
 199    A68_CHAR ch;
 200    if (A68 (curses_mode) == A68_FALSE) {
 201      genie_curses_start (p);
 202    }
 203    POP_OBJECT (p, &ch, A68_CHAR);
 204    (void) (addch ((chtype) (VALUE (&ch))));
 205  }
 206  
 207  //! @brief PROC curses move = (INT, INT) VOID
 208  
 209  void genie_curses_move (NODE_T * p)
 210  {
 211    A68_INT i, j;
 212    if (A68 (curses_mode) == A68_FALSE) {
 213      genie_curses_start (p);
 214    }
 215    POP_OBJECT (p, &j, A68_INT);
 216    POP_OBJECT (p, &i, A68_INT);
 217    if (VALUE (&i) < 0 || VALUE (&i) >= LINES) {
 218      diagnostic (A68_RUNTIME_ERROR, p, ERROR_CURSES_OFF_SCREEN);
 219      exit_genie (p, A68_RUNTIME_ERROR);
 220    }
 221    if (VALUE (&j) < 0 || VALUE (&j) >= COLS) {
 222      diagnostic (A68_RUNTIME_ERROR, p, ERROR_CURSES_OFF_SCREEN);
 223      exit_genie (p, A68_RUNTIME_ERROR);
 224    }
 225    CHECK_CURSES_RETVAL (move (VALUE (&i), VALUE (&j)) != ERR);
 226  }
 227  
 228  #endif