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