~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/sys/con_tty.c

  • Committer: Bazaar Package Importer
  • Author(s): Ansgar Burchardt
  • Date: 2008-09-05 21:14:51 UTC
  • mfrom: (1.2.1 upstream) (2.1.5 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080905211451-243bmbl6l6gdav7l
* Remove non-free code/tools/lcc (Closes: #496346)
  + Remove hunk from patch 10_fix_build_and_binary_on_alpha
  + debian/rules: Add BUILD_GAME_QVM=0 to $(MAKE) call
    (thanks to Peter De Wachter)
* Remove code/libs containing binary libraries for Mac OS X and Win32
* debian/copyright: Explain which parts of upstream's sources were removed
* debian/rules: replace ${source:Upstream-Version} by 0.7.7
  because the variable also contains the `+dfsg1' part
* Add -fsigned-char to compiler options (Closes: #487970)
  (thanks to Peter De Wachter)
* Add myself to Uploaders
* debian/control: Remove article from beginning of short description,
  don't start short description with a capital letter
* debian/openarena.6: Escape minus signs
  + fixes lintian warnings: hyphen-used-as-minus-sign

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
===========================================================================
 
3
Copyright (C) 1999-2005 Id Software, Inc.
 
4
 
 
5
This file is part of Quake III Arena source code.
 
6
 
 
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.
 
11
 
 
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.
 
16
 
 
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
===========================================================================
 
21
*/
 
22
 
 
23
#include "../qcommon/q_shared.h"
 
24
#include "../qcommon/qcommon.h"
 
25
#include "sys_local.h"
 
26
 
 
27
#include <unistd.h>
 
28
#include <signal.h>
 
29
#include <termios.h>
 
30
#include <fcntl.h>
 
31
#include <sys/time.h>
 
32
 
 
33
/*
 
34
=============================================================
 
35
tty console routines
 
36
 
 
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
=============================================================
 
41
*/
 
42
 
 
43
// general flag to tell about tty console mode
 
44
static qboolean ttycon_on = qfalse;
 
45
static int ttycon_hide = 0;
 
46
 
 
47
// some key codes that the terminal may be using, initialised on start up
 
48
static int TTY_erase;
 
49
static int TTY_eof;
 
50
 
 
51
static struct termios TTY_tc;
 
52
 
 
53
static field_t TTY_con;
 
54
 
 
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;
 
60
 
 
61
/*
 
62
==================
 
63
CON_FlushIn
 
64
 
 
65
Flush stdin, I suspect some terminals are sending a LOT of shit
 
66
FIXME relevant?
 
67
==================
 
68
*/
 
69
static void CON_FlushIn( void )
 
70
{
 
71
        char key;
 
72
        while (read(0, &key, 1)!=-1);
 
73
}
 
74
 
 
75
/*
 
76
==================
 
77
CON_Back
 
78
 
 
79
Output a backspace
 
80
 
 
81
NOTE: it seems on some terminals just sending '\b' is not enough so instead we
 
82
send "\b \b"
 
83
(FIXME there may be a way to find out if '\b' alone would work though)
 
84
==================
 
85
*/
 
86
static void CON_Back( void )
 
87
{
 
88
        char key;
 
89
        key = '\b';
 
90
        write(1, &key, 1);
 
91
        key = ' ';
 
92
        write(1, &key, 1);
 
93
        key = '\b';
 
94
        write(1, &key, 1);
 
95
}
 
96
 
 
97
/*
 
98
==================
 
99
CON_Hide
 
100
 
 
101
Clear the display of the line currently edited
 
102
bring cursor back to beginning of line
 
103
==================
 
104
*/
 
105
static void CON_Hide( void )
 
106
{
 
107
        if( ttycon_on )
 
108
        {
 
109
                int i;
 
110
                if (ttycon_hide)
 
111
                {
 
112
                        ttycon_hide++;
 
113
                        return;
 
114
                }
 
115
                if (TTY_con.cursor>0)
 
116
                {
 
117
                        for (i=0; i<TTY_con.cursor; i++)
 
118
                        {
 
119
                                CON_Back();
 
120
                        }
 
121
                }
 
122
                CON_Back(); // Delete "]"
 
123
                ttycon_hide++;
 
124
        }
 
125
}
 
126
 
 
127
/*
 
128
==================
 
129
CON_Show
 
130
 
 
131
Show the current line
 
132
FIXME need to position the cursor if needed?
 
133
==================
 
134
*/
 
135
static void CON_Show( void )
 
136
{
 
137
        if( ttycon_on )
 
138
        {
 
139
                int i;
 
140
 
 
141
                assert(ttycon_hide>0);
 
142
                ttycon_hide--;
 
143
                if (ttycon_hide == 0)
 
144
                {
 
145
                        write( 1, "]", 1 );
 
146
                        if (TTY_con.cursor)
 
147
                        {
 
148
                                for (i=0; i<TTY_con.cursor; i++)
 
149
                                {
 
150
                                        write(1, TTY_con.buffer+i, 1);
 
151
                                }
 
152
                        }
 
153
                }
 
154
        }
 
155
}
 
156
 
 
157
/*
 
158
==================
 
159
CON_Shutdown
 
160
 
 
161
Never exit without calling this, or your terminal will be left in a pretty bad state
 
162
==================
 
163
*/
 
164
void CON_Shutdown( void )
 
165
{
 
166
        if (ttycon_on)
 
167
        {
 
168
                CON_Back(); // Delete "]"
 
169
                tcsetattr (0, TCSADRAIN, &TTY_tc);
 
170
        }
 
171
 
 
172
  // Restore blocking to stdin reads
 
173
  fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) & ~O_NONBLOCK );
 
174
}
 
175
 
 
176
/*
 
177
==================
 
178
Hist_Add
 
179
==================
 
180
*/
 
181
void Hist_Add(field_t *field)
 
182
{
 
183
        int i;
 
184
        assert(hist_count <= CON_HISTORY);
 
185
        assert(hist_count >= 0);
 
186
        assert(hist_current >= -1);
 
187
        assert(hist_current <= hist_count);
 
188
        // make some room
 
189
        for (i=CON_HISTORY-1; i>0; i--)
 
190
        {
 
191
                ttyEditLines[i] = ttyEditLines[i-1];
 
192
        }
 
193
        ttyEditLines[0] = *field;
 
194
        if (hist_count<CON_HISTORY)
 
195
        {
 
196
                hist_count++;
 
197
        }
 
198
        hist_current = -1; // re-init
 
199
}
 
200
 
 
201
/*
 
202
==================
 
203
Hist_Prev
 
204
==================
 
205
*/
 
206
field_t *Hist_Prev( void )
 
207
{
 
208
        int hist_prev;
 
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)
 
215
        {
 
216
                return NULL;
 
217
        }
 
218
        hist_current++;
 
219
        return &(ttyEditLines[hist_current]);
 
220
}
 
221
 
 
222
/*
 
223
==================
 
224
Hist_Next
 
225
==================
 
226
*/
 
227
field_t *Hist_Next( void )
 
228
{
 
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)
 
234
        {
 
235
                hist_current--;
 
236
        }
 
237
        if (hist_current == -1)
 
238
        {
 
239
                return NULL;
 
240
        }
 
241
        return &(ttyEditLines[hist_current]);
 
242
}
 
243
 
 
244
/*
 
245
==================
 
246
CON_Init
 
247
 
 
248
Initialize the console input (tty mode if possible)
 
249
==================
 
250
*/
 
251
void CON_Init( void )
 
252
{
 
253
        struct termios tc;
 
254
 
 
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);
 
259
 
 
260
        // Make stdin reads non-blocking
 
261
        fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) | O_NONBLOCK );
 
262
 
 
263
        if (isatty(STDIN_FILENO)!=1)
 
264
        {
 
265
                Com_Printf( "stdin is not a tty, tty console mode disabled\n");
 
266
                ttycon_on = qfalse;
 
267
                return;
 
268
        }
 
269
 
 
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];
 
274
        tc = TTY_tc;
 
275
 
 
276
        /*
 
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�
 
283
        nal
 
284
        */
 
285
        tc.c_lflag &= ~(ECHO | ICANON);
 
286
 
 
287
        /*
 
288
        ISTRIP strip off bit 8
 
289
        INPCK enable input parity checking
 
290
        */
 
291
        tc.c_iflag &= ~(ISTRIP | INPCK);
 
292
        tc.c_cc[VMIN] = 1;
 
293
        tc.c_cc[VTIME] = 0;
 
294
        tcsetattr (0, TCSADRAIN, &tc);
 
295
        ttycon_on = qtrue;
 
296
}
 
297
 
 
298
/*
 
299
==================
 
300
CON_Input
 
301
==================
 
302
*/
 
303
char *CON_Input( void )
 
304
{
 
305
        // we use this when sending back commands
 
306
        static char text[256];
 
307
        int avail;
 
308
        char key;
 
309
        field_t *history;
 
310
 
 
311
        if( ttycon_on )
 
312
        {
 
313
                avail = read(0, &key, 1);
 
314
                if (avail != -1)
 
315
                {
 
316
                        // we have something
 
317
                        // backspace?
 
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))
 
320
                        {
 
321
                                if (TTY_con.cursor > 0)
 
322
                                {
 
323
                                        TTY_con.cursor--;
 
324
                                        TTY_con.buffer[TTY_con.cursor] = '\0';
 
325
                                        CON_Back();
 
326
                                }
 
327
                                return NULL;
 
328
                        }
 
329
                        // check if this is a control char
 
330
                        if ((key) && (key) < ' ')
 
331
                        {
 
332
                                if (key == '\n')
 
333
                                {
 
334
                                        // push it in history
 
335
                                        Hist_Add(&TTY_con);
 
336
                                        strcpy(text, TTY_con.buffer);
 
337
                                        Field_Clear(&TTY_con);
 
338
                                        key = '\n';
 
339
                                        write(1, &key, 1);
 
340
                                        write( 1, "]", 1 );
 
341
                                        return text;
 
342
                                }
 
343
                                if (key == '\t')
 
344
                                {
 
345
                                        CON_Hide();
 
346
                                        Field_AutoComplete( &TTY_con );
 
347
                                        CON_Show();
 
348
                                        return NULL;
 
349
                                }
 
350
                                avail = read(0, &key, 1);
 
351
                                if (avail != -1)
 
352
                                {
 
353
                                        // VT 100 keys
 
354
                                        if (key == '[' || key == 'O')
 
355
                                        {
 
356
                                                avail = read(0, &key, 1);
 
357
                                                if (avail != -1)
 
358
                                                {
 
359
                                                        switch (key)
 
360
                                                        {
 
361
                                                                case 'A':
 
362
                                                                        history = Hist_Prev();
 
363
                                                                        if (history)
 
364
                                                                        {
 
365
                                                                                CON_Hide();
 
366
                                                                                TTY_con = *history;
 
367
                                                                                CON_Show();
 
368
                                                                        }
 
369
                                                                        CON_FlushIn();
 
370
                                                                        return NULL;
 
371
                                                                        break;
 
372
                                                                case 'B':
 
373
                                                                        history = Hist_Next();
 
374
                                                                        CON_Hide();
 
375
                                                                        if (history)
 
376
                                                                        {
 
377
                                                                                TTY_con = *history;
 
378
                                                                        } else
 
379
                                                                        {
 
380
                                                                                Field_Clear(&TTY_con);
 
381
                                                                        }
 
382
                                                                        CON_Show();
 
383
                                                                        CON_FlushIn();
 
384
                                                                        return NULL;
 
385
                                                                        break;
 
386
                                                                case 'C':
 
387
                                                                        return NULL;
 
388
                                                                case 'D':
 
389
                                                                        return NULL;
 
390
                                                        }
 
391
                                                }
 
392
                                        }
 
393
                                }
 
394
                                Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase);
 
395
                                CON_FlushIn();
 
396
                                return NULL;
 
397
                        }
 
398
                        // push regular character
 
399
                        TTY_con.buffer[TTY_con.cursor] = key;
 
400
                        TTY_con.cursor++;
 
401
                        // print the current line (this is differential)
 
402
                        write(1, &key, 1);
 
403
                }
 
404
 
 
405
                return NULL;
 
406
        }
 
407
        else
 
408
        {
 
409
                int     len;
 
410
                fd_set  fdset;
 
411
                struct timeval timeout;
 
412
                static qboolean stdin_active;
 
413
 
 
414
                if (!com_dedicated || !com_dedicated->value)
 
415
                        return NULL;
 
416
 
 
417
                if (!stdin_active)
 
418
                        return NULL;
 
419
 
 
420
                FD_ZERO(&fdset);
 
421
                FD_SET(0, &fdset); // stdin
 
422
                timeout.tv_sec = 0;
 
423
                timeout.tv_usec = 0;
 
424
                if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
 
425
                {
 
426
                        return NULL;
 
427
                }
 
428
 
 
429
                len = read (0, text, sizeof(text));
 
430
                if (len == 0)
 
431
                { // eof!
 
432
                        stdin_active = qfalse;
 
433
                        return NULL;
 
434
                }
 
435
 
 
436
                if (len < 1)
 
437
                        return NULL;
 
438
                text[len-1] = 0;    // rip off the /n and terminate
 
439
 
 
440
                return text;
 
441
        }
 
442
}
 
443
 
 
444
/*
 
445
==================
 
446
CON_Print
 
447
==================
 
448
*/
 
449
void CON_Print( const char *msg )
 
450
{
 
451
        CON_Hide( );
 
452
 
 
453
        if( com_ansiColor && com_ansiColor->integer )
 
454
                Sys_AnsiColorPrint( msg );
 
455
        else
 
456
                fputs( msg, stderr );
 
457
 
 
458
        CON_Show( );
 
459
}