2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
23
#include "../qcommon/q_shared.h"
24
#include "../qcommon/qcommon.h"
25
#include "sys_local.h"
34
=============================================================
37
NOTE: if the user is editing a line when something gets printed to the early
38
console then it won't look good so we provide CON_Hide and CON_Show to be
39
called before and after a stdout or stderr output
40
=============================================================
43
// general flag to tell about tty console mode
44
static qboolean ttycon_on = qfalse;
45
static int ttycon_hide = 0;
47
// some key codes that the terminal may be using, initialised on start up
51
static struct termios TTY_tc;
53
static field_t TTY_con;
55
// This is somewhat of aduplicate of the graphical console history
56
// but it's safer more modular to have our own here
57
#define CON_HISTORY 32
58
static field_t ttyEditLines[ CON_HISTORY ];
59
static int hist_current = -1, hist_count = 0;
65
Flush stdin, I suspect some terminals are sending a LOT of shit
69
static void CON_FlushIn( void )
72
while (read(0, &key, 1)!=-1);
81
NOTE: it seems on some terminals just sending '\b' is not enough so instead we
83
(FIXME there may be a way to find out if '\b' alone would work though)
86
static void CON_Back( void )
101
Clear the display of the line currently edited
102
bring cursor back to beginning of line
105
static void CON_Hide( void )
115
if (TTY_con.cursor>0)
117
for (i=0; i<TTY_con.cursor; i++)
122
CON_Back(); // Delete "]"
131
Show the current line
132
FIXME need to position the cursor if needed?
135
static void CON_Show( void )
141
assert(ttycon_hide>0);
143
if (ttycon_hide == 0)
148
for (i=0; i<TTY_con.cursor; i++)
150
write(1, TTY_con.buffer+i, 1);
161
Never exit without calling this, or your terminal will be left in a pretty bad state
164
void CON_Shutdown( void )
168
CON_Back(); // Delete "]"
169
tcsetattr (0, TCSADRAIN, &TTY_tc);
172
// Restore blocking to stdin reads
173
fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) & ~O_NONBLOCK );
181
void Hist_Add(field_t *field)
184
assert(hist_count <= CON_HISTORY);
185
assert(hist_count >= 0);
186
assert(hist_current >= -1);
187
assert(hist_current <= hist_count);
189
for (i=CON_HISTORY-1; i>0; i--)
191
ttyEditLines[i] = ttyEditLines[i-1];
193
ttyEditLines[0] = *field;
194
if (hist_count<CON_HISTORY)
198
hist_current = -1; // re-init
206
field_t *Hist_Prev( void )
209
assert(hist_count <= CON_HISTORY);
210
assert(hist_count >= 0);
211
assert(hist_current >= -1);
212
assert(hist_current <= hist_count);
213
hist_prev = hist_current + 1;
214
if (hist_prev >= hist_count)
219
return &(ttyEditLines[hist_current]);
227
field_t *Hist_Next( void )
229
assert(hist_count <= CON_HISTORY);
230
assert(hist_count >= 0);
231
assert(hist_current >= -1);
232
assert(hist_current <= hist_count);
233
if (hist_current >= 0)
237
if (hist_current == -1)
241
return &(ttyEditLines[hist_current]);
248
Initialize the console input (tty mode if possible)
251
void CON_Init( void )
255
// If the process is backgrounded (running non interactively)
256
// then SIGTTIN or SIGTOU is emitted, if not caught, turns into a SIGSTP
257
signal(SIGTTIN, SIG_IGN);
258
signal(SIGTTOU, SIG_IGN);
260
// Make stdin reads non-blocking
261
fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) | O_NONBLOCK );
263
if (isatty(STDIN_FILENO)!=1)
265
Com_Printf( "stdin is not a tty, tty console mode disabled\n");
270
Field_Clear(&TTY_con);
271
tcgetattr (0, &TTY_tc);
272
TTY_erase = TTY_tc.c_cc[VERASE];
273
TTY_eof = TTY_tc.c_cc[VEOF];
277
ECHO: don't echo input characters
278
ICANON: enable canonical mode. This enables the special
279
characters EOF, EOL, EOL2, ERASE, KILL, REPRINT,
280
STATUS, and WERASE, and buffers by lines.
281
ISIG: when any of the characters INTR, QUIT, SUSP, or
282
DSUSP are received, generate the corresponding sig�
285
tc.c_lflag &= ~(ECHO | ICANON);
288
ISTRIP strip off bit 8
289
INPCK enable input parity checking
291
tc.c_iflag &= ~(ISTRIP | INPCK);
294
tcsetattr (0, TCSADRAIN, &tc);
303
char *CON_Input( void )
305
// we use this when sending back commands
306
static char text[256];
313
avail = read(0, &key, 1);
318
// NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
319
if ((key == TTY_erase) || (key == 127) || (key == 8))
321
if (TTY_con.cursor > 0)
324
TTY_con.buffer[TTY_con.cursor] = '\0';
329
// check if this is a control char
330
if ((key) && (key) < ' ')
334
// push it in history
336
strcpy(text, TTY_con.buffer);
337
Field_Clear(&TTY_con);
346
Field_AutoComplete( &TTY_con );
350
avail = read(0, &key, 1);
354
if (key == '[' || key == 'O')
356
avail = read(0, &key, 1);
362
history = Hist_Prev();
373
history = Hist_Next();
380
Field_Clear(&TTY_con);
394
Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase);
398
// push regular character
399
TTY_con.buffer[TTY_con.cursor] = key;
401
// print the current line (this is differential)
411
struct timeval timeout;
412
static qboolean stdin_active;
414
if (!com_dedicated || !com_dedicated->value)
421
FD_SET(0, &fdset); // stdin
424
if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
429
len = read (0, text, sizeof(text));
432
stdin_active = qfalse;
438
text[len-1] = 0; // rip off the /n and terminate
449
void CON_Print( const char *msg )
453
if( com_ansiColor && com_ansiColor->integer )
454
Sys_AnsiColorPrint( msg );
456
fputs( msg, stderr );