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-2024 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    struct timeval tv;
  77    TV_SEC (&tv) = 0;
  78    TV_USEC (&tv) = 100;
  79    fd_set fd;
  80    FD_ZERO (&fd);
  81    FD_SET (0, &fd);
  82    if (select (1, &fd, NULL, NULL, &tv)) {
  83  // FD_ISSET(0, &fd) will be true.  
  84      return getch ();
  85    } else {
  86      return NULL_CHAR;
  87    }
  88  #endif
  89  }
  90  
  91  //! @brief PROC curses start = VOID
  92  
  93  void genie_curses_start (NODE_T * p)
  94  {
  95    (void) p;
  96    init_curses ();
  97    A68 (curses_mode) = A68_TRUE;
  98  }
  99  
 100  //! @brief PROC curses end = VOID
 101  
 102  void genie_curses_end (NODE_T * p)
 103  {
 104    (void) p;
 105    clean_curses ();
 106  }
 107  
 108  //! @brief PROC curses clear = VOID
 109  
 110  void genie_curses_clear (NODE_T * p)
 111  {
 112    if (A68 (curses_mode) == A68_FALSE) {
 113      genie_curses_start (p);
 114    }
 115    CHECK_CURSES_RETVAL (clear () != ERR);
 116  }
 117  
 118  //! @brief PROC curses refresh = VOID
 119  
 120  void genie_curses_refresh (NODE_T * p)
 121  {
 122    if (A68 (curses_mode) == A68_FALSE) {
 123      genie_curses_start (p);
 124    }
 125    CHECK_CURSES_RETVAL (refresh () != ERR);
 126  }
 127  
 128  //! @brief PROC curses lines = INT
 129  
 130  void genie_curses_lines (NODE_T * p)
 131  {
 132    if (A68 (curses_mode) == A68_FALSE) {
 133      genie_curses_start (p);
 134    }
 135    PUSH_VALUE (p, LINES, A68_INT);
 136  }
 137  
 138  //! @brief PROC curses columns = INT
 139  
 140  void genie_curses_columns (NODE_T * p)
 141  {
 142    if (A68 (curses_mode) == A68_FALSE) {
 143      genie_curses_start (p);
 144    }
 145    PUSH_VALUE (p, COLS, A68_INT);
 146  }
 147  
 148  //! @brief PROC curses getchar = CHAR
 149  
 150  void genie_curses_getchar (NODE_T * p)
 151  {
 152    if (A68 (curses_mode) == A68_FALSE) {
 153      genie_curses_start (p);
 154    }
 155    PUSH_VALUE (p, (char) rgetchar (), A68_CHAR);
 156  }
 157  
 158  //! @brief PROC curses colour = VOID
 159  
 160  #define GENIE_COLOUR(f, n, fg, bg)\
 161  void f (NODE_T *p) {\
 162    (void) p;\
 163    if ((n) < COLOR_PAIRS) {\
 164      (void) init_pair (n, (fg), (bg));\
 165      wattrset (stdscr, COLOR_PAIR ((n)) | A_BOLD);\
 166    }\
 167  }\
 168  void f##_inverse (NODE_T *p) {\
 169    (void) p;\
 170    if ((n + 8) < COLOR_PAIRS) {\
 171      (void) init_pair ((n) + 8, (bg), (fg));\
 172      wattrset (stdscr, COLOR_PAIR (((n) + 8)));\
 173    }\
 174  }
 175  
 176  GENIE_COLOUR (genie_curses_blue, 1, COLOR_BLUE, COLOR_BLACK);
 177  GENIE_COLOUR (genie_curses_cyan, 2, COLOR_CYAN, COLOR_BLACK);
 178  GENIE_COLOUR (genie_curses_green, 3, COLOR_GREEN, COLOR_BLACK);
 179  GENIE_COLOUR (genie_curses_magenta, 4, COLOR_MAGENTA, COLOR_BLACK);
 180  GENIE_COLOUR (genie_curses_red, 5, COLOR_RED, COLOR_BLACK);
 181  GENIE_COLOUR (genie_curses_white, 6, COLOR_WHITE, COLOR_BLACK);
 182  GENIE_COLOUR (genie_curses_yellow, 7, COLOR_YELLOW, COLOR_BLACK);
 183  
 184  //! @brief PROC curses delchar = (CHAR) BOOL
 185  
 186  void genie_curses_del_char (NODE_T * p)
 187  {
 188    A68_CHAR ch;
 189    POP_OBJECT (p, &ch, A68_CHAR);
 190    int v = (int) VALUE (&ch);
 191    PUSH_VALUE (p, (BOOL_T) (v == 8 || v == 127 || v == KEY_BACKSPACE), A68_BOOL);
 192  }
 193  
 194  //! @brief PROC curses putchar = (CHAR) VOID
 195  
 196  void genie_curses_putchar (NODE_T * p)
 197  {
 198    if (A68 (curses_mode) == A68_FALSE) {
 199      genie_curses_start (p);
 200    }
 201    A68_CHAR ch;
 202    POP_OBJECT (p, &ch, A68_CHAR);
 203    (void) (addch ((chtype) (VALUE (&ch))));
 204  }
 205  
 206  //! @brief PROC curses move = (INT, INT) VOID
 207  
 208  void genie_curses_move (NODE_T * p)
 209  {
 210    if (A68 (curses_mode) == A68_FALSE) {
 211      genie_curses_start (p);
 212    }
 213    A68_INT i, j;
 214    POP_OBJECT (p, &j, A68_INT);
 215    POP_OBJECT (p, &i, A68_INT);
 216    if (VALUE (&i) < 0 || VALUE (&i) >= LINES) {
 217      diagnostic (A68_RUNTIME_ERROR, p, ERROR_CURSES_OFF_SCREEN);
 218      exit_genie (p, A68_RUNTIME_ERROR);
 219    }
 220    if (VALUE (&j) < 0 || VALUE (&j) >= COLS) {
 221      diagnostic (A68_RUNTIME_ERROR, p, ERROR_CURSES_OFF_SCREEN);
 222      exit_genie (p, A68_RUNTIME_ERROR);
 223    }
 224    CHECK_CURSES_RETVAL (move (VALUE (&i), VALUE (&j)) != ERR);
 225  }
 226  
 227  #endif