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


© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)