doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
posix_main.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 #include "../../idlib/precompiled.h"
29 #include "../sys_local.h"
30 
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <errno.h>
34 #include <dirent.h>
35 #include <unistd.h>
36 #include <sys/mman.h>
37 #include <sys/time.h>
38 #include <pwd.h>
39 #include <pthread.h>
40 #include <dlfcn.h>
41 #include <termios.h>
42 #include <signal.h>
43 #include <fcntl.h>
44 
45 #include "posix_public.h"
46 
47 #define MAX_OSPATH 256
48 #define COMMAND_HISTORY 64
49 
50 static int input_hide = 0;
51 
53 static char input_ret[256];
54 
55 static idStr history[ COMMAND_HISTORY ]; // cycle buffer
56 static int history_count = 0; // buffer fill up
57 static int history_start = 0; // current history start
58 static int history_current = 0; // goes back in history
59 idEditField history_backup; // the base edit line
60 
61 // terminal support
62 idCVar in_tty( "in_tty", "1", CVAR_BOOL | CVAR_INIT | CVAR_SYSTEM, "terminal tab-completion and history" );
63 
64 static bool tty_enabled = false;
65 static struct termios tty_tc;
66 
67 // pid - useful when you attach to gdb..
68 idCVar com_pid( "com_pid", "0", CVAR_INTEGER | CVAR_INIT | CVAR_SYSTEM, "process id" );
69 
70 // exit - quit - error --------------------------------------------------------
71 
72 static int set_exit = 0;
73 static char exit_spawn[ 1024 ];
74 
75 /*
76 ================
77 Posix_Exit
78 ================
79 */
80 void Posix_Exit(int ret) {
81  if ( tty_enabled ) {
82  Sys_Printf( "shutdown terminal support\n" );
83  if ( tcsetattr( 0, TCSADRAIN, &tty_tc ) == -1 ) {
84  Sys_Printf( "tcsetattr failed: %s\n", strerror( errno ) );
85  }
86  }
87  // at this point, too late to catch signals
89  if ( asyncThread.threadHandle ) {
91  }
92  // process spawning. it's best when it happens after everything has shut down
93  if ( exit_spawn[0] ) {
94  Sys_DoStartProcess( exit_spawn, false );
95  }
96  // in case of signal, handler tries a common->Quit
97  // we use set_exit to maintain a correct exit code
98  if ( set_exit ) {
99  exit( set_exit );
100  }
101  exit( ret );
102 }
103 
104 /*
105 ================
106 Posix_SetExit
107 ================
108 */
109 void Posix_SetExit(int ret) {
110  set_exit = 0;
111 }
112 
113 /*
114 ===============
115 Posix_SetExitSpawn
116 set the process to be spawned when we quit
117 ===============
118 */
119 void Posix_SetExitSpawn( const char *exeName ) {
120  idStr::Copynz( exit_spawn, exeName, 1024 );
121 }
122 
123 /*
124 ==================
125 idSysLocal::StartProcess
126 if !quit, start the process asap
127 otherwise, push it for execution at exit
128 (i.e. let complete shutdown of the game and freeing of resources happen)
129 NOTE: might even want to add a small delay?
130 ==================
131 */
132 void idSysLocal::StartProcess( const char *exeName, bool quit ) {
133  if ( quit ) {
134  common->DPrintf( "Sys_StartProcess %s (delaying until final exit)\n", exeName );
135  Posix_SetExitSpawn( exeName );
137  return;
138  }
139 
140  common->DPrintf( "Sys_StartProcess %s\n", exeName );
141  Sys_DoStartProcess( exeName );
142 }
143 
144 /*
145 ================
146 Sys_Quit
147 ================
148 */
149 void Sys_Quit(void) {
150  Posix_Exit( EXIT_SUCCESS );
151 }
152 
153 /*
154 ================
155 Sys_Milliseconds
156 ================
157 */
158 /* base time in seconds, that's our origin
159  timeval:tv_sec is an int:
160  assuming this wraps every 0x7fffffff - ~68 years since the Epoch (1970) - we're safe till 2038
161  using unsigned long data type to work right with Sys_XTimeToSysTime */
162 unsigned long sys_timeBase = 0;
163 /* current time in ms, using sys_timeBase as origin
164  NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch
165  0x7fffffff ms - ~24 days
166  or is it 48 days? the specs say int, but maybe it's casted from unsigned int?
167 */
168 int Sys_Milliseconds( void ) {
169  int curtime;
170  struct timeval tp;
171 
172  gettimeofday(&tp, NULL);
173 
174  if (!sys_timeBase) {
175  sys_timeBase = tp.tv_sec;
176  return tp.tv_usec / 1000;
177  }
178 
179  curtime = (tp.tv_sec - sys_timeBase) * 1000 + tp.tv_usec / 1000;
180 
181  return curtime;
182 }
183 
184 /*
185 ================
186 Sys_Mkdir
187 ================
188 */
189 void Sys_Mkdir( const char *path ) {
190  mkdir(path, 0777);
191 }
192 
193 /*
194 ================
195 Sys_ListFiles
196 ================
197 */
198 int Sys_ListFiles( const char *directory, const char *extension, idStrList &list ) {
199  struct dirent *d;
200  DIR *fdir;
201  bool dironly = false;
202  char search[MAX_OSPATH];
203  struct stat st;
204  bool debug;
205 
206  list.Clear();
207 
208  debug = cvarSystem->GetCVarBool( "fs_debug" );
209 
210  if (!extension)
211  extension = "";
212 
213  // passing a slash as extension will find directories
214  if (extension[0] == '/' && extension[1] == 0) {
215  extension = "";
216  dironly = true;
217  }
218 
219  // search
220  // NOTE: case sensitivity of directory path can screw us up here
221  if ((fdir = opendir(directory)) == NULL) {
222  if (debug) {
223  common->Printf("Sys_ListFiles: opendir %s failed\n", directory);
224  }
225  return -1;
226  }
227 
228  while ((d = readdir(fdir)) != NULL) {
229  idStr::snPrintf(search, sizeof(search), "%s/%s", directory, d->d_name);
230  if (stat(search, &st) == -1)
231  continue;
232  if (!dironly) {
233  idStr look(search);
234  idStr ext;
235  look.ExtractFileExtension(ext);
236  if (extension[0] != '\0' && ext.Icmp(&extension[1]) != 0) {
237  continue;
238  }
239  }
240  if ((dironly && !(st.st_mode & S_IFDIR)) ||
241  (!dironly && (st.st_mode & S_IFDIR)))
242  continue;
243 
244  list.Append(d->d_name);
245  }
246 
247  closedir(fdir);
248 
249  if ( debug ) {
250  common->Printf( "Sys_ListFiles: %d entries in %s\n", list.Num(), directory );
251  }
252 
253  return list.Num();
254 }
255 
256 /*
257 ============================================================================
258 EVENT LOOP
259 ============================================================================
260 */
261 
262 #define MAX_QUED_EVENTS 256
263 #define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 )
264 
266 static int eventHead, eventTail;
267 
268 /*
269 ================
270 Posix_QueEvent
271 
272 ptr should either be null, or point to a block of data that can be freed later
273 ================
274 */
275 void Posix_QueEvent( sysEventType_t type, int value, int value2,
276  int ptrLength, void *ptr ) {
277  sysEvent_t *ev;
278 
279  ev = &eventQue[eventHead & MASK_QUED_EVENTS];
281  common->Printf( "Posix_QueEvent: overflow\n" );
282  // we are discarding an event, but don't leak memory
283  // TTimo: verbose dropped event types?
284  if (ev->evPtr) {
285  Mem_Free(ev->evPtr);
286  ev->evPtr = NULL;
287  }
288  eventTail++;
289  }
290 
291  eventHead++;
292 
293  ev->evType = type;
294  ev->evValue = value;
295  ev->evValue2 = value2;
296  ev->evPtrLength = ptrLength;
297  ev->evPtr = ptr;
298 
299 #if 0
300  common->Printf( "Event %d: %d %d\n", ev->evType, ev->evValue, ev->evValue2 );
301 #endif
302 }
303 
304 /*
305 ================
306 Sys_GetEvent
307 ================
308 */
310  static sysEvent_t ev;
311 
312  // return if we have data
313  if (eventHead > eventTail) {
314  eventTail++;
315  return eventQue[(eventTail - 1) & MASK_QUED_EVENTS];
316  }
317  // return the empty event with the current time
318  memset(&ev, 0, sizeof(ev));
319 
320  return ev;
321 }
322 
323 /*
324 ================
325 Sys_ClearEvents
326 ================
327 */
328 void Sys_ClearEvents( void ) {
329  eventHead = eventTail = 0;
330 }
331 
332 /*
333 ================
334 Posix_Cwd
335 ================
336 */
337 const char *Posix_Cwd( void ) {
338  static char cwd[MAX_OSPATH];
339 
340  getcwd( cwd, sizeof( cwd ) - 1 );
341  cwd[MAX_OSPATH-1] = 0;
342 
343  return cwd;
344 }
345 
346 /*
347 =================
348 Sys_GetMemoryStatus
349 =================
350 */
352  common->Printf( "FIXME: Sys_GetMemoryStatus stub\n" );
353 }
354 
356  common->Printf( "FIXME: Sys_GetCurrentMemoryStatus\n" );
357 }
358 
360  common->Printf( "FIXME: Sys_GetExeLaunchMemoryStatus\n" );
361 }
362 
363 /*
364 =================
365 Sys_Init
366 Posix_EarlyInit/Posix_LateInit is better
367 =================
368 */
369 void Sys_Init( void ) { }
370 
371 /*
372 =================
373 Posix_Shutdown
374 =================
375 */
376 void Posix_Shutdown( void ) {
377  for ( int i = 0; i < COMMAND_HISTORY; i++ ) {
378  history[ i ].Clear();
379  }
380 }
381 
382 /*
383 =================
384 Sys_DLL_Load
385 TODO: OSX - use the native API instead? NSModule
386 =================
387 */
388 int Sys_DLL_Load( const char *path ) {
389  void *handle = dlopen( path, RTLD_NOW );
390  if ( !handle ) {
391  Sys_Printf( "dlopen '%s' failed: %s\n", path, dlerror() );
392  }
393  return (int)handle;
394 }
395 
396 /*
397 =================
398 Sys_DLL_GetProcAddress
399 =================
400 */
401 void* Sys_DLL_GetProcAddress( int handle, const char *sym ) {
402  const char *error;
403  void *ret = dlsym( (void *)handle, sym );
404  if ((error = dlerror()) != NULL) {
405  Sys_Printf( "dlsym '%s' failed: %s\n", sym, error );
406  }
407  return ret;
408 }
409 
410 /*
411 =================
412 Sys_DLL_Unload
413 =================
414 */
415 void Sys_DLL_Unload( int handle ) {
416  dlclose( (void *)handle );
417 }
418 
419 /*
420 ================
421 Sys_ShowConsole
422 ================
423 */
424 void Sys_ShowConsole( int visLevel, bool quitOnClose ) { }
425 
426 // ---------------------------------------------------------------------------
427 
428 // only relevant when specified on command line
429 const char *Sys_DefaultCDPath( void ) {
430  return "";
431 }
432 
433 long Sys_FileTimeStamp(FILE * fp) {
434  struct stat st;
435  fstat(fileno(fp), &st);
436  return st.st_mtime;
437 }
438 
439 void Sys_Sleep(int msec) {
440  if ( msec < 20 ) {
441  static int last = 0;
442  int now = Sys_Milliseconds();
443  if ( now - last > 1000 ) {
444  Sys_Printf("WARNING: Sys_Sleep - %d < 20 msec is not portable\n", msec);
445  last = now;
446  }
447  // ignore that sleep call, keep going
448  return;
449  }
450  // use nanosleep? keep sleeping if signal interrupt?
451  if (usleep(msec * 1000) == -1)
452  Sys_Printf("usleep: %s\n", strerror(errno));
453 }
454 
455 char *Sys_GetClipboardData(void) {
456  Sys_Printf( "TODO: Sys_GetClipboardData\n" );
457  return NULL;
458 }
459 
460 void Sys_SetClipboardData( const char *string ) {
461  Sys_Printf( "TODO: Sys_SetClipboardData\n" );
462 }
463 
464 
465 // stub pretty much everywhere - heavy calling
466 void Sys_FlushCacheMemory(void *base, int bytes)
467 {
468 // Sys_Printf("Sys_FlushCacheMemory stub\n");
469 }
470 
471 bool Sys_FPU_StackIsEmpty( void ) {
472  return true;
473 }
474 
475 void Sys_FPU_ClearStack( void ) {
476 }
477 
478 const char *Sys_FPU_GetState( void ) {
479  return "";
480 }
481 
482 void Sys_FPU_SetPrecision( int precision ) {
483 }
484 
485 /*
486 ================
487 Sys_LockMemory
488 ================
489 */
490 bool Sys_LockMemory( void *ptr, int bytes ) {
491  return true;
492 }
493 
494 /*
495 ================
496 Sys_UnlockMemory
497 ================
498 */
499 bool Sys_UnlockMemory( void *ptr, int bytes ) {
500  return true;
501 }
502 
503 /*
504 ================
505 Sys_SetPhysicalWorkMemory
506 ================
507 */
508 void Sys_SetPhysicalWorkMemory( int minBytes, int maxBytes ) {
509  common->DPrintf( "TODO: Sys_SetPhysicalWorkMemory\n" );
510 }
511 
512 /*
513 ===========
514 Sys_GetDriveFreeSpace
515 return in MegaBytes
516 ===========
517 */
518 int Sys_GetDriveFreeSpace( const char *path ) {
519  common->DPrintf( "TODO: Sys_GetDriveFreeSpace\n" );
520  return 1000 * 1024;
521 }
522 
523 /*
524 ================
525 Sys_AlreadyRunning
526 return true if there is a copy of D3 running already
527 ================
528 */
529 bool Sys_AlreadyRunning( void ) {
530  return false;
531 }
532 
533 /*
534 ===============
535 Posix_EarlyInit
536 ===============
537 */
538 void Posix_EarlyInit( void ) {
539  memset( &asyncThread, 0, sizeof( asyncThread ) );
540  exit_spawn[0] = '\0';
541  Posix_InitSigs();
542  // set the base time
545 }
546 
547 /*
548 ===============
549 Posix_LateInit
550 ===============
551 */
552 void Posix_LateInit( void ) {
554  com_pid.SetInteger( getpid() );
555  common->Printf( "pid: %d\n", com_pid.GetInteger() );
556  common->Printf( "%d MB System Memory\n", Sys_GetSystemRam() );
557 #ifndef ID_DEDICATED
558  common->Printf( "%d MB Video Memory\n", Sys_GetVideoRam() );
559 #endif
561 }
562 
563 /*
564 ===============
565 Posix_InitConsoleInput
566 ===============
567 */
569  struct termios tc;
570 
571  if ( in_tty.GetBool() ) {
572  if ( isatty( STDIN_FILENO ) != 1 ) {
573  Sys_Printf( "terminal support disabled: stdin is not a tty\n" );
574  in_tty.SetBool( false );
575  return;
576  }
577  if ( tcgetattr( 0, &tty_tc ) == -1 ) {
578  Sys_Printf( "tcgetattr failed. disabling terminal support: %s\n", strerror( errno ) );
579  in_tty.SetBool( false );
580  return;
581  }
582  // make the input non blocking
583  if ( fcntl( STDIN_FILENO, F_SETFL, fcntl( STDIN_FILENO, F_GETFL, 0 ) | O_NONBLOCK ) == -1 ) {
584  Sys_Printf( "fcntl STDIN non blocking failed. disabling terminal support: %s\n", strerror( errno ) );
585  in_tty.SetBool( false );
586  return;
587  }
588  tc = tty_tc;
589  /*
590  ECHO: don't echo input characters
591  ICANON: enable canonical mode. This enables the special
592  characters EOF, EOL, EOL2, ERASE, KILL, REPRINT,
593  STATUS, and WERASE, and buffers by lines.
594  ISIG: when any of the characters INTR, QUIT, SUSP, or
595  DSUSP are received, generate the corresponding signal
596  */
597  tc.c_lflag &= ~(ECHO | ICANON);
598  /*
599  ISTRIP strip off bit 8
600  INPCK enable input parity checking
601  */
602  tc.c_iflag &= ~(ISTRIP | INPCK);
603  tc.c_cc[VMIN] = 1;
604  tc.c_cc[VTIME] = 0;
605  if ( tcsetattr( 0, TCSADRAIN, &tc ) == -1 ) {
606  Sys_Printf( "tcsetattr failed: %s\n", strerror( errno ) );
607  Sys_Printf( "terminal support may not work correctly. Use +set in_tty 0 to disable it\n" );
608  }
609 #if 0
610  // make the output non blocking
611  if ( fcntl( STDOUT_FILENO, F_SETFL, fcntl( STDOUT_FILENO, F_GETFL, 0 ) | O_NONBLOCK ) == -1 ) {
612  Sys_Printf( "fcntl STDOUT non blocking failed: %s\n", strerror( errno ) );
613  }
614 #endif
615  tty_enabled = true;
616  // check the terminal type for the supported ones
617  char *term = getenv( "TERM" );
618  if ( term ) {
619  if ( strcmp( term, "linux" ) && strcmp( term, "xterm" ) && strcmp( term, "xterm-color" ) && strcmp( term, "screen" ) ) {
620  Sys_Printf( "WARNING: terminal type '%s' is unknown. terminal support may not work correctly\n", term );
621  }
622  }
623  Sys_Printf( "terminal support enabled ( use +set in_tty 0 to disabled )\n" );
624  } else {
625  Sys_Printf( "terminal support disabled\n" );
626  }
627 }
628 
629 /*
630 ================
631 terminal support utilities
632 ================
633 */
634 
635 void tty_Del() {
636  char key;
637  key = '\b';
638  write( STDOUT_FILENO, &key, 1 );
639  key = ' ';
640  write( STDOUT_FILENO, &key, 1 );
641  key = '\b';
642  write( STDOUT_FILENO, &key, 1 );
643 }
644 
645 void tty_Left() {
646  char key = '\b';
647  write( STDOUT_FILENO, &key, 1 );
648 }
649 
650 void tty_Right() {
651  char key = 27;
652  write( STDOUT_FILENO, &key, 1 );
653  write( STDOUT_FILENO, "[C", 2 );
654 }
655 
656 // clear the display of the line currently edited
657 // bring cursor back to beginning of line
658 void tty_Hide() {
659  int len, buf_len;
660  if ( !tty_enabled ) {
661  return;
662  }
663  if ( input_hide ) {
664  input_hide++;
665  return;
666  }
667  // clear after cursor
668  len = strlen( input_field.GetBuffer() ) - input_field.GetCursor();
669  while ( len > 0 ) {
670  tty_Right();
671  len--;
672  }
673  buf_len = strlen( input_field.GetBuffer() );
674  while ( buf_len > 0 ) {
675  tty_Del();
676  buf_len--;
677  }
678  input_hide++;
679 }
680 
681 // show the current line
682 void tty_Show() {
683  // int i;
684  if ( !tty_enabled ) {
685  return;
686  }
687  assert( input_hide > 0 );
688  input_hide--;
689  if ( input_hide == 0 ) {
690  char *buf = input_field.GetBuffer();
691  if ( buf[0] ) {
692  write( STDOUT_FILENO, buf, strlen( buf ) );
693  int back = strlen( buf ) - input_field.GetCursor();
694  while ( back > 0 ) {
695  tty_Left();
696  back--;
697  }
698  }
699  }
700 }
701 
702 void tty_FlushIn() {
703  char key;
704  while ( read(0, &key, 1) != -1 ) {
705  Sys_Printf( "'%d' ", key );
706  }
707  Sys_Printf( "\n" );
708 }
709 
710 /*
711 ================
712 Posix_ConsoleInput
713 Checks for a complete line of text typed in at the console.
714 Return NULL if a complete line is not ready.
715 ================
716 */
717 char *Posix_ConsoleInput( void ) {
718  if ( tty_enabled ) {
719  int ret;
720  char key;
721  bool hidden = false;
722  while ( ( ret = read( STDIN_FILENO, &key, 1 ) ) > 0 ) {
723  if ( !hidden ) {
724  tty_Hide();
725  hidden = true;
726  }
727  switch ( key ) {
728  case 1:
729  input_field.SetCursor( 0 );
730  break;
731  case 5:
732  input_field.SetCursor( strlen( input_field.GetBuffer() ) );
733  break;
734  case 127:
735  case 8:
736  input_field.CharEvent( K_BACKSPACE );
737  break;
738  case '\n':
739  idStr::Copynz( input_ret, input_field.GetBuffer(), sizeof( input_ret ) );
740  assert( hidden );
741  tty_Show();
742  write( STDOUT_FILENO, &key, 1 );
743  input_field.Clear();
744  if ( history_count < COMMAND_HISTORY ) {
745  history[ history_count ] = input_ret;
746  history_count++;
747  } else {
748  history[ history_start ] = input_ret;
749  history_start++;
750  history_start %= COMMAND_HISTORY;
751  }
752  history_current = 0;
753  return input_ret;
754  case '\t':
755  input_field.AutoComplete();
756  break;
757  case 27: {
758  // enter escape sequence mode
759  ret = read( STDIN_FILENO, &key, 1 );
760  if ( ret <= 0 ) {
761  Sys_Printf( "dropping sequence: '27' " );
762  tty_FlushIn();
763  assert( hidden );
764  tty_Show();
765  return NULL;
766  }
767  switch ( key ) {
768  case 79:
769  ret = read( STDIN_FILENO, &key, 1 );
770  if ( ret <= 0 ) {
771  Sys_Printf( "dropping sequence: '27' '79' " );
772  tty_FlushIn();
773  assert( hidden );
774  tty_Show();
775  return NULL;
776  }
777  switch ( key ) {
778  case 72:
779  // xterm only
780  input_field.SetCursor( 0 );
781  break;
782  case 70:
783  // xterm only
784  input_field.SetCursor( strlen( input_field.GetBuffer() ) );
785  break;
786  default:
787  Sys_Printf( "dropping sequence: '27' '79' '%d' ", key );
788  tty_FlushIn();
789  assert( hidden );
790  tty_Show();
791  return NULL;
792  }
793  break;
794  case 91: {
795  ret = read( STDIN_FILENO, &key, 1 );
796  if ( ret <= 0 ) {
797  Sys_Printf( "dropping sequence: '27' '91' " );
798  tty_FlushIn();
799  assert( hidden );
800  tty_Show();
801  return NULL;
802  }
803  switch ( key ) {
804  case 49: {
805  ret = read( STDIN_FILENO, &key, 1 );
806  if ( ret <= 0 || key != 126 ) {
807  Sys_Printf( "dropping sequence: '27' '91' '49' '%d' ", key );
808  tty_FlushIn();
809  assert( hidden );
810  tty_Show();
811  return NULL;
812  }
813  // only screen and linux terms
814  input_field.SetCursor( 0 );
815  break;
816  }
817  case 50: {
818  ret = read( STDIN_FILENO, &key, 1 );
819  if ( ret <= 0 || key != 126 ) {
820  Sys_Printf( "dropping sequence: '27' '91' '50' '%d' ", key );
821  tty_FlushIn();
822  assert( hidden );
823  tty_Show();
824  return NULL;
825  }
826  // all terms
827  input_field.KeyDownEvent( K_INS );
828  break;
829  }
830  case 52: {
831  ret = read( STDIN_FILENO, &key, 1 );
832  if ( ret <= 0 || key != 126 ) {
833  Sys_Printf( "dropping sequence: '27' '91' '52' '%d' ", key );
834  tty_FlushIn();
835  assert( hidden );
836  tty_Show();
837  return NULL;
838  }
839  // only screen and linux terms
840  input_field.SetCursor( strlen( input_field.GetBuffer() ) );
841  break;
842  }
843  case 51: {
844  ret = read( STDIN_FILENO, &key, 1 );
845  if ( ret <= 0 ) {
846  Sys_Printf( "dropping sequence: '27' '91' '51' " );
847  tty_FlushIn();
848  assert( hidden );
849  tty_Show();
850  return NULL;
851  }
852  if ( key == 126 ) {
853  input_field.KeyDownEvent( K_DEL );
854  break;
855  }
856  Sys_Printf( "dropping sequence: '27' '91' '51' '%d'", key );
857  tty_FlushIn();
858  assert( hidden );
859  tty_Show();
860  return NULL;
861  }
862  case 65:
863  case 66: {
864  // history
865  if ( history_current == 0 ) {
866  history_backup = input_field;
867  }
868  if ( key == 65 ) {
869  // up
870  history_current++;
871  } else {
872  // down
873  history_current--;
874  }
875  // history_current cycle:
876  // 0: current edit
877  // 1 .. Min( COMMAND_HISTORY, history_count ): back in history
878  if ( history_current < 0 ) {
879  history_current = Min( COMMAND_HISTORY, history_count );
880  } else {
881  history_current %= Min( COMMAND_HISTORY, history_count ) + 1;
882  }
883  int index = -1;
884  if ( history_current == 0 ) {
885  input_field = history_backup;
886  } else {
887  index = history_start + Min( COMMAND_HISTORY, history_count ) - history_current;
888  index %= COMMAND_HISTORY;
889  assert( index >= 0 && index < COMMAND_HISTORY );
890  input_field.SetBuffer( history[ index ] );
891  }
892  assert( hidden );
893  tty_Show();
894  return NULL;
895  }
896  case 67:
897  input_field.KeyDownEvent( K_RIGHTARROW );
898  break;
899  case 68:
900  input_field.KeyDownEvent( K_LEFTARROW );
901  break;
902  default:
903  Sys_Printf( "dropping sequence: '27' '91' '%d' ", key );
904  tty_FlushIn();
905  assert( hidden );
906  tty_Show();
907  return NULL;
908  }
909  break;
910  }
911  default:
912  Sys_Printf( "dropping sequence: '27' '%d' ", key );
913  tty_FlushIn();
914  assert( hidden );
915  tty_Show();
916  return NULL;
917  }
918  break;
919  }
920  default:
921  if ( key >= ' ' ) {
922  input_field.CharEvent( key );
923  break;
924  }
925  Sys_Printf( "dropping sequence: '%d' ", key );
926  tty_FlushIn();
927  assert( hidden );
928  tty_Show();
929  return NULL;
930  }
931  }
932  if ( hidden ) {
933  tty_Show();
934  }
935  return NULL;
936  } else {
937  // disabled on OSX. works fine from a terminal, but launching from Finder is causing trouble
938  // I'm pretty sure it could be re-enabled if needed, and just handling the Finder failure case right (TTimo)
939 #ifndef MACOS_X
940  // no terminal support - read only complete lines
941  int len;
942  fd_set fdset;
943  struct timeval timeout;
944 
945  FD_ZERO( &fdset );
946  FD_SET( STDIN_FILENO, &fdset );
947  timeout.tv_sec = 0;
948  timeout.tv_usec = 0;
949  if ( select( 1, &fdset, NULL, NULL, &timeout ) == -1 || !FD_ISSET( 0, &fdset ) ) {
950  return NULL;
951  }
952 
953  len = read( 0, input_ret, sizeof( input_ret ) );
954  if ( len == 0 ) {
955  // EOF
956  return NULL;
957  }
958 
959  if ( len < 1 ) {
960  Sys_Printf( "read failed: %s\n", strerror( errno ) ); // something bad happened, cancel this line and print an error
961  return NULL;
962  }
963 
964  if ( len == sizeof( input_ret ) ) {
965  Sys_Printf( "read overflow\n" ); // things are likely to break, as input will be cut into pieces
966  }
967 
968  input_ret[ len-1 ] = '\0'; // rip off the \n and terminate
969  return input_ret;
970 #endif
971  }
972  return NULL;
973 }
974 
975 /*
976 called during frame loops, pacifier updates etc.
977 this is only for console input polling and misc mouse grab tasks
978 the actual mouse and keyboard input is in the Sys_Poll logic
979 */
980 void Sys_GenerateEvents( void ) {
981  char *s;
982  if ( ( s = Posix_ConsoleInput() ) ) {
983  char *b;
984  int len;
985 
986  len = strlen( s ) + 1;
987  b = (char *)Mem_Alloc( len );
988  strcpy( b, s );
989  Posix_QueEvent( SE_CONSOLE, 0, 0, len, b );
990  }
991 }
992 
993 /*
994 ===============
995 low level output
996 ===============
997 */
998 
999 void Sys_DebugPrintf( const char *fmt, ... ) {
1000  va_list argptr;
1001 
1002  tty_Hide();
1003  va_start( argptr, fmt );
1004  vprintf( fmt, argptr );
1005  va_end( argptr );
1006  tty_Show();
1007 }
1008 
1009 void Sys_DebugVPrintf( const char *fmt, va_list arg ) {
1010  tty_Hide();
1011  vprintf( fmt, arg );
1012  tty_Show();
1013 }
1014 
1015 void Sys_Printf(const char *msg, ...) {
1016  va_list argptr;
1017 
1018  tty_Hide();
1019  va_start( argptr, msg );
1020  vprintf( msg, argptr );
1021  va_end( argptr );
1022  tty_Show();
1023 }
1024 
1025 void Sys_VPrintf(const char *msg, va_list arg) {
1026  tty_Hide();
1027  vprintf(msg, arg);
1028  tty_Show();
1029 }
1030 
1031 /*
1032 ================
1033 Sys_Error
1034 ================
1035 */
1036 void Sys_Error(const char *error, ...) {
1037  va_list argptr;
1038 
1039  Sys_Printf( "Sys_Error: " );
1040  va_start( argptr, error );
1041  Sys_DebugVPrintf( error, argptr );
1042  va_end( argptr );
1043  Sys_Printf( "\n" );
1044 
1046 }
1047 
1048 /*
1049 ===============
1050 Sys_FreeOpenAL
1051 ===============
1052 */
1053 void Sys_FreeOpenAL( void ) { }
void Sys_Mkdir(const char *path)
Definition: posix_main.cpp:189
#define strcmp
Definition: Str.h:41
static int snPrintf(char *dest, int size, const char *fmt,...) id_attribute((format(printf
Definition: Str.cpp:1465
GLsizei const GLfloat * value
Definition: glext.h:3614
int evPtrLength
Definition: sys_public.h:219
assert(prefInfo.fullscreenBtn)
idCVarSystem * cvarSystem
Definition: CVarSystem.cpp:487
void Posix_SetExitSpawn(const char *exeName)
Definition: posix_main.cpp:119
void Sys_Sleep(int msec)
Definition: posix_main.cpp:439
void Sys_GetExeLaunchMemoryStatus(sysMemoryStats_t &stats)
Definition: posix_main.cpp:359
void Sys_FlushCacheMemory(void *base, int bytes)
Definition: posix_main.cpp:466
int GetCursor(void) const
Definition: EditField.cpp:157
void tty_Right()
Definition: posix_main.cpp:650
Definition: KeyInput.h:74
void Sys_FreeOpenAL(void)
long tv_sec
Definition: timeval.h:37
void Sys_Printf(const char *msg,...)
void AutoComplete(void)
Definition: EditField.cpp:191
void Posix_InitSigs()
unsigned long sys_timeBase
Definition: posix_main.cpp:162
void Sys_DLL_Unload(int handle)
Definition: posix_main.cpp:415
xthreadInfo asyncThread
void tty_Left()
Definition: posix_main.cpp:645
int fileno(FILE *stream)
char * GetBuffer(void)
Definition: EditField.cpp:511
void tty_Hide()
Definition: posix_main.cpp:658
void Sys_DebugPrintf(const char *fmt,...)
Definition: posix_main.cpp:999
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
void CharEvent(int c)
Definition: EditField.cpp:298
GLdouble s
Definition: glext.h:2935
GLenum GLsizei len
Definition: glext.h:3472
void Sys_GenerateEvents(void)
Definition: posix_main.cpp:980
int i
Definition: process.py:33
void Posix_StartAsyncThread(void)
void SetCursor(int c)
Definition: EditField.cpp:147
const char * Sys_FPU_GetState(void)
Definition: posix_main.cpp:478
#define MASK_QUED_EVENTS
Definition: posix_main.cpp:263
void Posix_Exit(int ret)
Definition: posix_main.cpp:80
int Icmp(const char *text) const
Definition: Str.h:667
bool Sys_UnlockMemory(void *ptr, int bytes)
Definition: posix_main.cpp:499
int Sys_DLL_Load(const char *path)
Definition: posix_main.cpp:388
long Sys_FileTimeStamp(FILE *fp)
Definition: posix_main.cpp:433
void * evPtr
Definition: sys_public.h:220
void Sys_Quit(void)
Definition: posix_main.cpp:149
void Posix_InitPThreads()
void Sys_FPU_ClearStack(void)
Definition: posix_main.cpp:475
virtual void BufferCommandText(cmdExecution_t exec, const char *text)=0
int Sys_GetDriveFreeSpace(const char *path)
Definition: posix_main.cpp:518
int Sys_ListFiles(const char *directory, const char *extension, idStrList &list)
Definition: posix_main.cpp:198
long tv_usec
Definition: timeval.h:38
bool Sys_FPU_StackIsEmpty(void)
Definition: posix_main.cpp:471
sysEventType_t
Definition: sys_public.h:192
idCVar in_tty("in_tty","1", CVAR_BOOL|CVAR_INIT|CVAR_SYSTEM,"terminal tab-completion and history")
Definition: KeyInput.h:73
GLuint index
Definition: glext.h:3476
void Sys_ShowConsole(int visLevel, bool quitOnClose)
Definition: posix_main.cpp:424
void Posix_SetExit(int ret)
Definition: posix_main.cpp:109
void Clear(void)
Definition: EditField.cpp:124
void Posix_EarlyInit(void)
Definition: posix_main.cpp:538
idCommon * common
Definition: Common.cpp:206
void Posix_InitConsoleInput(void)
Definition: posix_main.cpp:568
#define NULL
Definition: Lib.h:88
void KeyDownEvent(int key)
Definition: EditField.cpp:373
#define select(args...)
Definition: amigaos.h:39
void SetInteger(const int value)
Definition: CVarSystem.h:148
void * Sys_DLL_GetProcAddress(int handle, const char *sym)
Definition: posix_main.cpp:401
int evValue2
Definition: sys_public.h:218
int GetInteger(void) const
Definition: CVarSystem.h:143
int Sys_GetSystemRam(void)
Definition: main.cpp:339
void Posix_Shutdown(void)
Definition: posix_main.cpp:376
static void Copynz(char *dest, const char *src, int destsize)
Definition: Str.cpp:1376
const char * path
Definition: sws.c:117
void Sys_DestroyThread(xthreadInfo &info)
char * Sys_GetClipboardData(void)
Definition: posix_main.cpp:455
#define EXIT_FAILURE
Definition: jerror.c:27
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
bool Sys_LockMemory(void *ptr, int bytes)
Definition: posix_main.cpp:490
void Clear(void)
Definition: Str.h:724
void Sys_Init(void)
Definition: posix_main.cpp:369
void tty_Del()
Definition: posix_main.cpp:635
char * Posix_ConsoleInput(void)
Definition: posix_main.cpp:717
virtual void Printf(const char *fmt,...) id_attribute((format(printf
idEditField input_field
Definition: posix_main.cpp:52
#define MAX_OSPATH
Definition: posix_main.cpp:47
sysEventType_t evType
Definition: sys_public.h:216
int eventHead
Definition: win_main.cpp:720
GLubyte GLubyte b
Definition: glext.h:4662
void tty_Show()
Definition: posix_main.cpp:682
int Append(const type &obj)
Definition: List.h:646
idCVar com_pid("com_pid","0", CVAR_INTEGER|CVAR_INIT|CVAR_SYSTEM,"process id")
bool GetBool(void) const
Definition: CVarSystem.h:142
int eventTail
Definition: win_main.cpp:721
void Sys_DebugVPrintf(const char *fmt, va_list arg)
void Sys_SetClipboardData(const char *string)
Definition: posix_main.cpp:460
const char * Sys_DefaultCDPath(void)
Definition: posix_main.cpp:429
void Sys_GetMemoryStatus(sysMemoryStats_t &stats)
Definition: posix_main.cpp:351
void Posix_QueEvent(sysEventType_t type, int value, int value2, int ptrLength, void *ptr)
Definition: posix_main.cpp:275
int Num(void) const
Definition: List.h:265
void Sys_ClearEvents(void)
Definition: posix_main.cpp:328
idEditField history_backup
Definition: posix_main.cpp:59
void SetBuffer(const char *buffer)
Definition: EditField.cpp:520
const char * Posix_Cwd(void)
Definition: posix_main.cpp:337
void tty_FlushIn()
Definition: posix_main.cpp:702
Definition: Str.h:116
sysEvent_t eventQue[MAX_QUED_EVENTS]
Definition: win_main.cpp:719
void Sys_VPrintf(const char *msg, va_list arg)
void Sys_SetPhysicalWorkMemory(int minBytes, int maxBytes)
Definition: posix_main.cpp:508
virtual void StartProcess(const char *exeName, bool quit)
Definition: posix_main.cpp:132
bool Sys_AlreadyRunning(void)
Definition: posix_main.cpp:529
int threadHandle
Definition: sys_public.h:490
void Posix_ClearSigs()
virtual bool GetCVarBool(const char *name) const =0
void SetBool(const bool value)
Definition: CVarSystem.h:147
#define COMMAND_HISTORY
Definition: posix_main.cpp:48
void Sys_GetCurrentMemoryStatus(sysMemoryStats_t &stats)
Definition: posix_main.cpp:355
void Sys_Error(const char *error,...)
void Sys_DoStartProcess(const char *exeName, bool dofork)
Definition: main.cpp:368
#define MAX_QUED_EVENTS
Definition: posix_main.cpp:262
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
int Sys_GetVideoRam(void)
Definition: dedicated.cpp:65
void Sys_FPU_SetPrecision(int precision)
Definition: posix_main.cpp:482
int Sys_Milliseconds(void)
Definition: posix_main.cpp:168
void ExtractFileExtension(idStr &dest) const
Definition: Str.cpp:965
sysEvent_t Sys_GetEvent(void)
Definition: posix_main.cpp:309
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
ID_INLINE T Min(T x, T y)
Definition: Lib.h:159
void Posix_LateInit(void)
Definition: posix_main.cpp:552
void Clear(void)
Definition: List.h:184