1 /***************************************************************************
2 terminfo.cpp - get information about the terminal
3 -------------------
4 begin : July 22 2002
5 copyright : (C) 2002 by Marc Schellens
6 email : m_schellens@users.sf.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 /*
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21 */
22
23 #include "includefirst.hpp"
24 #include "stdio.h"
25 #include <iostream>
26
27 #include "terminfo.hpp"
28
29 #ifndef _WIN32
30 #include <termios.h>
31 #include <unistd.h>
32 #endif
33
34 #if defined(HAVE_LIBREADLINE)
35 #include <readline/readline.h>
36 #endif
37
38 /* AC 2020 mai : it is useful ?!
39 // used to defined GDL_TMPDIR: may have trouble on MSwin, help welcome
40 #ifndef _WIN32
41 #include <paths.h>
42 #endif
43 */
44
45 #if defined(_WIN32) && !defined(__CYGWIN__)
TermWidth()46 int TermWidth()
47 {
48 HANDLE consh = GetStdHandle(STD_OUTPUT_HANDLE);
49
50 CONSOLE_SCREEN_BUFFER_INFO bufinfo;
51 GetConsoleScreenBufferInfo(consh, &bufinfo);
52 return bufinfo.srWindow.Right + 1;
53 }
TermHeight()54 int TermHeight()
55 {
56 HANDLE consh = GetStdHandle(STD_OUTPUT_HANDLE);
57
58 CONSOLE_SCREEN_BUFFER_INFO bufinfo;
59 GetConsoleScreenBufferInfo(consh, &bufinfo);
60 return bufinfo.srWindow.Bottom + 1;
61 }
62
63 #elif defined(HAVE_LIBREADLINE) && defined(RL_GET_SCREEN_SIZE)
64
TermWidth()65 int TermWidth()
66 {
67 int cols;
68 int rows;
69 rl_get_screen_size(&rows, &cols);
70 return cols;
71 }
72
TermHeight()73 int TermHeight()
74 {
75 int cols;
76 int rows;
77 rl_get_screen_size(&rows, &cols);
78 return rows;
79 }
80
81 #elif defined(HAVE_LIBNCURSES) || defined(HAVE_LIBCURSES)
82
83 #ifdef HAVE_LIBNCURSES
84 #include <ncurses.h>
85 #elif defined(HAVE_LIBCURSES)
86 #include <curses.h>
87 #endif
88
TermWidth()89 int TermWidth()
90 {
91 int cols = 0;
92 SCREEN *screen;
93
94 if( cols != 0) return cols;
95
96 screen = newterm((char *) NULL, stdout, stdin);
97 if((void *)screen == NULL)
98 cols = 80;
99 else
100 cols = COLS;
101
102 endwin();
103
104 return cols;
105 }
106
TermHeight()107 int TermHeight()
108 {
109 int lines = 0;
110 SCREEN *screen;
111
112 if( lines != 0) return lines;
113
114 // original line follows:
115 // initscr();
116
117 screen = newterm((char *) NULL, stdout, stdin);
118 if((void *)screen == NULL)
119 lines = 24;
120 else
121 lines = LINES;
122
123 endwin();
124
125 return lines;
126 }
127
128 #else
129
130 // default
131
TermWidth()132 int TermWidth()
133 {
134 return 80;
135 }
136
TermHeight()137 int TermHeight()
138 {
139 return 24;
140 }
141
142 #endif
143
144 // AC 2020-05-05 : <<found on the Internet>> Unclear for me :((
145 #if defined(HAVE_LIBREADLINE) && defined(RL_GET_SCREEN_SIZE)
146
SetTermSize(int rows,int cols)147 void SetTermSize(int rows, int cols)
148 {
149 rl_set_screen_size (rows, cols);
150 #if defined(RL_ISSTATE) && defined(RL_INITIALIZED)
151 if (RL_ISSTATE(RL_INITIALIZED)) {
152 rl_resize_terminal();
153 } else {
154 std::cout << "Please report" << std::endl;
155 }
156 #else
157 std::cout << "Not ready due to RL_ISSTATE/RL_INITIALIZED (please report)" << std::endl;
158 #endif
159 }
160
161 #endif
162
163 namespace lib {
164 using namespace std;
165
166 #ifdef _WIN32
get_kbrd(EnvT * e)167 BaseGDL* get_kbrd( EnvT* e)
168 {
169
170 SizeT nParam=e->NParam();
171
172 bool doWait = true;
173 if( nParam > 0) {
174 doWait = false;
175 DLong waitArg = 0;
176 e->AssureLongScalarPar( 0, waitArg);
177 if( waitArg != 0)
178 doWait = true;
179 }
180
181 char c='\0';
182
183 if (doWait) {
184 cin.get(c);
185 }
186 else {
187 c=std::fgetc(stdin);
188 if(c==EOF) c='\0';
189 }
190
191 DStringGDL* res = new DStringGDL( DString( i2s( c)));
192 return res;
193 }
194
195 #else
196 // get_kbrd patch
197 // http://sourceforge.net/forum/forum.php?thread_id=3292183&forum_id=338691
get_kbrd(EnvT * e)198 BaseGDL* get_kbrd( EnvT* e)
199 {
200 #if defined(HAVE_LIBREADLINE)
201 rl_prep_terminal (0);
202 #endif
203
204 SizeT nParam=e->NParam();
205
206 bool doWait = true;
207 if (nParam > 0)
208 {
209 doWait = false;
210 DLong waitArg = 0;
211 e->AssureLongScalarPar( 0, waitArg);
212 if (waitArg != 0)
213 {
214 doWait = true;
215 }
216 }
217
218 // https://sourceforge.net/forum/forum.php?thread_id=3292183&forum_id=338691
219 // DONE: Implement proper SCALAR parameter handling (doWait variable)
220 // which is/was not blocking in the original program.
221 // note: multi-byte input is not supported here.
222
223 char c='\0'; //initialize is never a bad idea...
224
225 int fd=fileno(stdin);
226
227 struct termios orig, get;
228
229 // Get terminal setup to revert to it at end.
230
231 (void)tcgetattr(fd, &orig);
232 // New terminal setup, non-canonical.
233 get.c_lflag = ISIG;
234
235 if (doWait)
236 {
237 // will wait for a character
238 get.c_cc[VTIME]=0;
239 get.c_cc[VMIN]=1;
240 (void)tcsetattr(fd, TCSANOW, &get);
241
242 cin.get(c);
243 }
244 else
245 {
246 // will not wait, but return EOF or next character in terminal buffer if present
247
248 get.c_cc[VTIME]=0;
249 get.c_cc[VMIN]=0;
250 (void)tcsetattr(fd, TCSANOW, &get);
251
252 //the trick is *not to use C++ functions here. cin.get would wait.*
253 c=std::fgetc(stdin);
254 //and to convert EOF to null (otherwise GDL may exit if not compiled with
255 //[lib][n]curses)
256 if(c==EOF) c='\0';
257 }
258
259 // Restore original terminal settings.
260
261 (void)tcsetattr(fd, TCSANOW, &orig);
262
263 #if defined(HAVE_LIBREADLINE)
264 rl_deprep_terminal ();
265 #endif
266
267 DStringGDL* res = new DStringGDL( DString( i2s( c)));
268 return res;
269 }
270 #endif
271
terminal_size_fun(EnvT * e)272 BaseGDL* terminal_size_fun( EnvT* e ) {
273
274 SizeT nParam = e->NParam();
275 // cout << nParam << endl;
276
277 // Just returning the size of the Terminal
278 if (nParam == 0) {
279 DLongGDL* ret = new DLongGDL(dimension(2));
280 (*ret)[0] = TermWidth();
281 (*ret)[1] = TermHeight();
282 return ret;
283 }
284
285 DLong nb_lines = -1, nb_cols = -1;
286
287 if (nParam == 1) {
288 e->AssureLongScalarPar( 0, nb_cols);
289 }
290 if (nParam == 2) {
291 e->AssureLongScalarPar( 0, nb_cols);
292 e->AssureLongScalarPar( 1, nb_lines);
293 }
294 if (nb_lines <= 0) nb_lines = TermHeight();
295 if (nb_cols <= 0) nb_cols = TermWidth();
296
297 // cout << nb_lines << " "<< nb_cols << endl;
298
299 #if defined(HAVE_LIBREADLINE) && defined(RL_GET_SCREEN_SIZE)
300 SetTermSize(nb_lines, nb_cols);
301 #else
302 Message("Setting Terminal Size not ready (OK only with recent Readline (5.2+))");
303 #endif
304
305 // reading again the new size
306 DLongGDL* ret = new DLongGDL( dimension(2) );
307 (*ret)[0] = TermWidth();
308 (*ret)[1] = TermHeight();
309 return ret;
310 }
311
312 } // namespace
313
314