123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #include "../../idlib/precompiled.h"
- #include "../sys_local.h"
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <dirent.h>
- #include <unistd.h>
- #include <sys/mman.h>
- #include <sys/time.h>
- #include <pwd.h>
- #include <pthread.h>
- #include <dlfcn.h>
- #include <termios.h>
- #include <signal.h>
- #include <fcntl.h>
- #include "posix_public.h"
- #define MAX_OSPATH 256
- #define COMMAND_HISTORY 64
- static int input_hide = 0;
- idEditField input_field;
- static char input_ret[256];
- static idStr history[ COMMAND_HISTORY ]; // cycle buffer
- static int history_count = 0; // buffer fill up
- static int history_start = 0; // current history start
- static int history_current = 0; // goes back in history
- idEditField history_backup; // the base edit line
- // terminal support
- idCVar in_tty( "in_tty", "1", CVAR_BOOL | CVAR_INIT | CVAR_SYSTEM, "terminal tab-completion and history" );
- static bool tty_enabled = false;
- static struct termios tty_tc;
- // pid - useful when you attach to gdb..
- idCVar com_pid( "com_pid", "0", CVAR_INTEGER | CVAR_INIT | CVAR_SYSTEM, "process id" );
- // exit - quit - error --------------------------------------------------------
- static int set_exit = 0;
- static char exit_spawn[ 1024 ];
- /*
- ================
- Posix_Exit
- ================
- */
- void Posix_Exit(int ret) {
- if ( tty_enabled ) {
- Sys_Printf( "shutdown terminal support\n" );
- if ( tcsetattr( 0, TCSADRAIN, &tty_tc ) == -1 ) {
- Sys_Printf( "tcsetattr failed: %s\n", strerror( errno ) );
- }
- }
- // at this point, too late to catch signals
- Posix_ClearSigs();
- if ( asyncThread.threadHandle ) {
- Sys_DestroyThread( asyncThread );
- }
- // process spawning. it's best when it happens after everything has shut down
- if ( exit_spawn[0] ) {
- Sys_DoStartProcess( exit_spawn, false );
- }
- // in case of signal, handler tries a common->Quit
- // we use set_exit to maintain a correct exit code
- if ( set_exit ) {
- exit( set_exit );
- }
- exit( ret );
- }
- /*
- ================
- Posix_SetExit
- ================
- */
- void Posix_SetExit(int ret) {
- set_exit = 0;
- }
- /*
- ===============
- Posix_SetExitSpawn
- set the process to be spawned when we quit
- ===============
- */
- void Posix_SetExitSpawn( const char *exeName ) {
- idStr::Copynz( exit_spawn, exeName, 1024 );
- }
- /*
- ==================
- idSysLocal::StartProcess
- if !quit, start the process asap
- otherwise, push it for execution at exit
- (i.e. let complete shutdown of the game and freeing of resources happen)
- NOTE: might even want to add a small delay?
- ==================
- */
- void idSysLocal::StartProcess( const char *exeName, bool quit ) {
- if ( quit ) {
- common->DPrintf( "Sys_StartProcess %s (delaying until final exit)\n", exeName );
- Posix_SetExitSpawn( exeName );
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" );
- return;
- }
- common->DPrintf( "Sys_StartProcess %s\n", exeName );
- Sys_DoStartProcess( exeName );
- }
- /*
- ================
- Sys_Quit
- ================
- */
- void Sys_Quit(void) {
- Posix_Exit( EXIT_SUCCESS );
- }
- /*
- ================
- Sys_Milliseconds
- ================
- */
- /* base time in seconds, that's our origin
- timeval:tv_sec is an int:
- assuming this wraps every 0x7fffffff - ~68 years since the Epoch (1970) - we're safe till 2038
- using unsigned long data type to work right with Sys_XTimeToSysTime */
- unsigned long sys_timeBase = 0;
- /* current time in ms, using sys_timeBase as origin
- NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch
- 0x7fffffff ms - ~24 days
- or is it 48 days? the specs say int, but maybe it's casted from unsigned int?
- */
- int Sys_Milliseconds( void ) {
- int curtime;
- struct timeval tp;
- gettimeofday(&tp, NULL);
- if (!sys_timeBase) {
- sys_timeBase = tp.tv_sec;
- return tp.tv_usec / 1000;
- }
- curtime = (tp.tv_sec - sys_timeBase) * 1000 + tp.tv_usec / 1000;
- return curtime;
- }
- /*
- ================
- Sys_Mkdir
- ================
- */
- void Sys_Mkdir( const char *path ) {
- mkdir(path, 0777);
- }
- /*
- ================
- Sys_ListFiles
- ================
- */
- int Sys_ListFiles( const char *directory, const char *extension, idStrList &list ) {
- struct dirent *d;
- DIR *fdir;
- bool dironly = false;
- char search[MAX_OSPATH];
- struct stat st;
- bool debug;
-
- list.Clear();
- debug = cvarSystem->GetCVarBool( "fs_debug" );
-
- if (!extension)
- extension = "";
-
- // passing a slash as extension will find directories
- if (extension[0] == '/' && extension[1] == 0) {
- extension = "";
- dironly = true;
- }
-
- // search
- // NOTE: case sensitivity of directory path can screw us up here
- if ((fdir = opendir(directory)) == NULL) {
- if (debug) {
- common->Printf("Sys_ListFiles: opendir %s failed\n", directory);
- }
- return -1;
- }
-
- while ((d = readdir(fdir)) != NULL) {
- idStr::snPrintf(search, sizeof(search), "%s/%s", directory, d->d_name);
- if (stat(search, &st) == -1)
- continue;
- if (!dironly) {
- idStr look(search);
- idStr ext;
- look.ExtractFileExtension(ext);
- if (extension[0] != '\0' && ext.Icmp(&extension[1]) != 0) {
- continue;
- }
- }
- if ((dironly && !(st.st_mode & S_IFDIR)) ||
- (!dironly && (st.st_mode & S_IFDIR)))
- continue;
- list.Append(d->d_name);
- }
- closedir(fdir);
-
- if ( debug ) {
- common->Printf( "Sys_ListFiles: %d entries in %s\n", list.Num(), directory );
- }
-
- return list.Num();
- }
- /*
- ============================================================================
- EVENT LOOP
- ============================================================================
- */
- #ifndef USE_SDL
- #define MAX_QUED_EVENTS 256
- #define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 )
- static sysEvent_t eventQue[MAX_QUED_EVENTS];
- static int eventHead, eventTail;
- /*
- ================
- Posix_QueEvent
- ptr should either be null, or point to a block of data that can be freed later
- ================
- */
- void Posix_QueEvent( sysEventType_t type, int value, int value2,
- int ptrLength, void *ptr ) {
- sysEvent_t *ev;
- ev = &eventQue[eventHead & MASK_QUED_EVENTS];
- if (eventHead - eventTail >= MAX_QUED_EVENTS) {
- common->Printf( "Posix_QueEvent: overflow\n" );
- // we are discarding an event, but don't leak memory
- // TTimo: verbose dropped event types?
- if (ev->evPtr) {
- Mem_Free(ev->evPtr);
- ev->evPtr = NULL;
- }
- eventTail++;
- }
- eventHead++;
- ev->evType = type;
- ev->evValue = value;
- ev->evValue2 = value2;
- ev->evPtrLength = ptrLength;
- ev->evPtr = ptr;
- #if 0
- common->Printf( "Event %d: %d %d\n", ev->evType, ev->evValue, ev->evValue2 );
- #endif
- }
- /*
- ================
- Sys_GetEvent
- ================
- */
- sysEvent_t Sys_GetEvent(void) {
- static sysEvent_t ev;
- // return if we have data
- if (eventHead > eventTail) {
- eventTail++;
- return eventQue[(eventTail - 1) & MASK_QUED_EVENTS];
- }
- // return the empty event with the current time
- memset(&ev, 0, sizeof(ev));
- return ev;
- }
- /*
- ================
- Sys_ClearEvents
- ================
- */
- void Sys_ClearEvents( void ) {
- eventHead = eventTail = 0;
- }
- #endif
- /*
- ================
- Posix_Cwd
- ================
- */
- const char *Posix_Cwd( void ) {
- static char cwd[MAX_OSPATH];
- getcwd( cwd, sizeof( cwd ) - 1 );
- cwd[MAX_OSPATH-1] = 0;
- return cwd;
- }
- /*
- =================
- Sys_GetMemoryStatus
- =================
- */
- void Sys_GetMemoryStatus( sysMemoryStats_t &stats ) {
- common->Printf( "FIXME: Sys_GetMemoryStatus stub\n" );
- }
- void Sys_GetCurrentMemoryStatus( sysMemoryStats_t &stats ) {
- common->Printf( "FIXME: Sys_GetCurrentMemoryStatus\n" );
- }
- void Sys_GetExeLaunchMemoryStatus( sysMemoryStats_t &stats ) {
- common->Printf( "FIXME: Sys_GetExeLaunchMemoryStatus\n" );
- }
- /*
- =================
- Sys_Init
- Posix_EarlyInit/Posix_LateInit is better
- =================
- */
- void Sys_Init( void ) { }
- /*
- =================
- Posix_Shutdown
- =================
- */
- void Posix_Shutdown( void ) {
- for ( int i = 0; i < COMMAND_HISTORY; i++ ) {
- history[ i ].Clear();
- }
- }
- /*
- =================
- Sys_DLL_Load
- TODO: OSX - use the native API instead? NSModule
- =================
- */
- int Sys_DLL_Load( const char *path ) {
- void *handle = dlopen( path, RTLD_NOW );
- if ( !handle ) {
- Sys_Printf( "dlopen '%s' failed: %s\n", path, dlerror() );
- }
- return (int)handle;
- }
- /*
- =================
- Sys_DLL_GetProcAddress
- =================
- */
- void* Sys_DLL_GetProcAddress( int handle, const char *sym ) {
- const char *error;
- void *ret = dlsym( (void *)handle, sym );
- if ((error = dlerror()) != NULL) {
- Sys_Printf( "dlsym '%s' failed: %s\n", sym, error );
- }
- return ret;
- }
- /*
- =================
- Sys_DLL_Unload
- =================
- */
- void Sys_DLL_Unload( int handle ) {
- dlclose( (void *)handle );
- }
- /*
- ================
- Sys_ShowConsole
- ================
- */
- void Sys_ShowConsole( int visLevel, bool quitOnClose ) { }
- // ---------------------------------------------------------------------------
- // only relevant when specified on command line
- const char *Sys_DefaultCDPath( void ) {
- return "";
- }
- long Sys_FileTimeStamp(FILE * fp) {
- struct stat st;
- fstat(fileno(fp), &st);
- return st.st_mtime;
- }
- void Sys_Sleep(int msec) {
- if ( msec < 20 ) {
- static int last = 0;
- int now = Sys_Milliseconds();
- if ( now - last > 1000 ) {
- Sys_Printf("WARNING: Sys_Sleep - %d < 20 msec is not portable\n", msec);
- last = now;
- }
- // ignore that sleep call, keep going
- return;
- }
- // use nanosleep? keep sleeping if signal interrupt?
- if (usleep(msec * 1000) == -1)
- Sys_Printf("usleep: %s\n", strerror(errno));
- }
- char *Sys_GetClipboardData(void) {
- Sys_Printf( "TODO: Sys_GetClipboardData\n" );
- return NULL;
- }
- void Sys_SetClipboardData( const char *string ) {
- Sys_Printf( "TODO: Sys_SetClipboardData\n" );
- }
-
- // stub pretty much everywhere - heavy calling
- void Sys_FlushCacheMemory(void *base, int bytes)
- {
- // Sys_Printf("Sys_FlushCacheMemory stub\n");
- }
- bool Sys_FPU_StackIsEmpty( void ) {
- return true;
- }
- void Sys_FPU_ClearStack( void ) {
- }
- const char *Sys_FPU_GetState( void ) {
- return "";
- }
- void Sys_FPU_SetPrecision( int precision ) {
- }
- /*
- ================
- Sys_LockMemory
- ================
- */
- bool Sys_LockMemory( void *ptr, int bytes ) {
- return true;
- }
- /*
- ================
- Sys_UnlockMemory
- ================
- */
- bool Sys_UnlockMemory( void *ptr, int bytes ) {
- return true;
- }
- /*
- ================
- Sys_SetPhysicalWorkMemory
- ================
- */
- void Sys_SetPhysicalWorkMemory( int minBytes, int maxBytes ) {
- common->DPrintf( "TODO: Sys_SetPhysicalWorkMemory\n" );
- }
- /*
- ===========
- Sys_GetDriveFreeSpace
- return in MegaBytes
- ===========
- */
- int Sys_GetDriveFreeSpace( const char *path ) {
- common->DPrintf( "TODO: Sys_GetDriveFreeSpace\n" );
- return 1000 * 1024;
- }
- /*
- ================
- Sys_AlreadyRunning
- return true if there is a copy of D3 running already
- ================
- */
- bool Sys_AlreadyRunning( void ) {
- return false;
- }
- /*
- ===============
- Posix_EarlyInit
- ===============
- */
- void Posix_EarlyInit( void ) {
- memset( &asyncThread, 0, sizeof( asyncThread ) );
- exit_spawn[0] = '\0';
- Posix_InitSigs();
- // set the base time
- Sys_Milliseconds();
- Posix_InitPThreads();
- }
- /*
- ===============
- Posix_LateInit
- ===============
- */
- void Posix_LateInit( void ) {
- Posix_InitConsoleInput();
- com_pid.SetInteger( getpid() );
- common->Printf( "pid: %d\n", com_pid.GetInteger() );
- common->Printf( "%d MB System Memory\n", Sys_GetSystemRam() );
- #ifndef ID_DEDICATED
- common->Printf( "%d MB Video Memory\n", Sys_GetVideoRam() );
- #endif
- Posix_StartAsyncThread( );
- }
- /*
- ===============
- Posix_InitConsoleInput
- ===============
- */
- void Posix_InitConsoleInput( void ) {
- struct termios tc;
- if ( in_tty.GetBool() ) {
- if ( isatty( STDIN_FILENO ) != 1 ) {
- Sys_Printf( "terminal support disabled: stdin is not a tty\n" );
- in_tty.SetBool( false );
- return;
- }
- if ( tcgetattr( 0, &tty_tc ) == -1 ) {
- Sys_Printf( "tcgetattr failed. disabling terminal support: %s\n", strerror( errno ) );
- in_tty.SetBool( false );
- return;
- }
- // make the input non blocking
- if ( fcntl( STDIN_FILENO, F_SETFL, fcntl( STDIN_FILENO, F_GETFL, 0 ) | O_NONBLOCK ) == -1 ) {
- Sys_Printf( "fcntl STDIN non blocking failed. disabling terminal support: %s\n", strerror( errno ) );
- in_tty.SetBool( false );
- return;
- }
- tc = tty_tc;
- /*
- ECHO: don't echo input characters
- ICANON: enable canonical mode. This enables the special
- characters EOF, EOL, EOL2, ERASE, KILL, REPRINT,
- STATUS, and WERASE, and buffers by lines.
- ISIG: when any of the characters INTR, QUIT, SUSP, or
- DSUSP are received, generate the corresponding signal
- */
- tc.c_lflag &= ~(ECHO | ICANON);
- /*
- ISTRIP strip off bit 8
- INPCK enable input parity checking
- */
- tc.c_iflag &= ~(ISTRIP | INPCK);
- tc.c_cc[VMIN] = 1;
- tc.c_cc[VTIME] = 0;
- if ( tcsetattr( 0, TCSADRAIN, &tc ) == -1 ) {
- Sys_Printf( "tcsetattr failed: %s\n", strerror( errno ) );
- Sys_Printf( "terminal support may not work correctly. Use +set in_tty 0 to disable it\n" );
- }
- #if 0
- // make the output non blocking
- if ( fcntl( STDOUT_FILENO, F_SETFL, fcntl( STDOUT_FILENO, F_GETFL, 0 ) | O_NONBLOCK ) == -1 ) {
- Sys_Printf( "fcntl STDOUT non blocking failed: %s\n", strerror( errno ) );
- }
- #endif
- tty_enabled = true;
- // check the terminal type for the supported ones
- char *term = getenv( "TERM" );
- if ( term ) {
- if ( strcmp( term, "linux" ) && strcmp( term, "xterm" ) && strcmp( term, "xterm-color" ) && strcmp( term, "screen" ) ) {
- Sys_Printf( "WARNING: terminal type '%s' is unknown. terminal support may not work correctly\n", term );
- }
- }
- Sys_Printf( "terminal support enabled ( use +set in_tty 0 to disabled )\n" );
- } else {
- Sys_Printf( "terminal support disabled\n" );
- }
- }
- /*
- ================
- terminal support utilities
- ================
- */
- void tty_Del() {
- char key;
- key = '\b';
- write( STDOUT_FILENO, &key, 1 );
- key = ' ';
- write( STDOUT_FILENO, &key, 1 );
- key = '\b';
- write( STDOUT_FILENO, &key, 1 );
- }
- void tty_Left() {
- char key = '\b';
- write( STDOUT_FILENO, &key, 1 );
- }
- void tty_Right() {
- char key = 27;
- write( STDOUT_FILENO, &key, 1 );
- write( STDOUT_FILENO, "[C", 2 );
- }
- // clear the display of the line currently edited
- // bring cursor back to beginning of line
- void tty_Hide() {
- int len, buf_len;
- if ( !tty_enabled ) {
- return;
- }
- if ( input_hide ) {
- input_hide++;
- return;
- }
- // clear after cursor
- len = strlen( input_field.GetBuffer() ) - input_field.GetCursor();
- while ( len > 0 ) {
- tty_Right();
- len--;
- }
- buf_len = strlen( input_field.GetBuffer() );
- while ( buf_len > 0 ) {
- tty_Del();
- buf_len--;
- }
- input_hide++;
- }
- // show the current line
- void tty_Show() {
- // int i;
- if ( !tty_enabled ) {
- return;
- }
- assert( input_hide > 0 );
- input_hide--;
- if ( input_hide == 0 ) {
- char *buf = input_field.GetBuffer();
- if ( buf[0] ) {
- write( STDOUT_FILENO, buf, strlen( buf ) );
- int back = strlen( buf ) - input_field.GetCursor();
- while ( back > 0 ) {
- tty_Left();
- back--;
- }
- }
- }
- }
- void tty_FlushIn() {
- char key;
- while ( read(0, &key, 1) != -1 ) {
- Sys_Printf( "'%d' ", key );
- }
- Sys_Printf( "\n" );
- }
- /*
- ================
- Sys_ConsoleInput
- Checks for a complete line of text typed in at the console.
- Return NULL if a complete line is not ready.
- ================
- */
- char *Sys_ConsoleInput( void ) {
- if ( tty_enabled ) {
- int ret;
- char key;
- bool hidden = false;
- while ( ( ret = read( STDIN_FILENO, &key, 1 ) ) > 0 ) {
- if ( !hidden ) {
- tty_Hide();
- hidden = true;
- }
- switch ( key ) {
- case 1:
- input_field.SetCursor( 0 );
- break;
- case 5:
- input_field.SetCursor( strlen( input_field.GetBuffer() ) );
- break;
- case 127:
- case 8:
- input_field.CharEvent( K_BACKSPACE );
- break;
- case '\n':
- idStr::Copynz( input_ret, input_field.GetBuffer(), sizeof( input_ret ) );
- assert( hidden );
- tty_Show();
- write( STDOUT_FILENO, &key, 1 );
- input_field.Clear();
- if ( history_count < COMMAND_HISTORY ) {
- history[ history_count ] = input_ret;
- history_count++;
- } else {
- history[ history_start ] = input_ret;
- history_start++;
- history_start %= COMMAND_HISTORY;
- }
- history_current = 0;
- return input_ret;
- case '\t':
- input_field.AutoComplete();
- break;
- case 27: {
- // enter escape sequence mode
- ret = read( STDIN_FILENO, &key, 1 );
- if ( ret <= 0 ) {
- Sys_Printf( "dropping sequence: '27' " );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- switch ( key ) {
- case 79:
- ret = read( STDIN_FILENO, &key, 1 );
- if ( ret <= 0 ) {
- Sys_Printf( "dropping sequence: '27' '79' " );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- switch ( key ) {
- case 72:
- // xterm only
- input_field.SetCursor( 0 );
- break;
- case 70:
- // xterm only
- input_field.SetCursor( strlen( input_field.GetBuffer() ) );
- break;
- default:
- Sys_Printf( "dropping sequence: '27' '79' '%d' ", key );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- break;
- case 91: {
- ret = read( STDIN_FILENO, &key, 1 );
- if ( ret <= 0 ) {
- Sys_Printf( "dropping sequence: '27' '91' " );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- switch ( key ) {
- case 49: {
- ret = read( STDIN_FILENO, &key, 1 );
- if ( ret <= 0 || key != 126 ) {
- Sys_Printf( "dropping sequence: '27' '91' '49' '%d' ", key );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- // only screen and linux terms
- input_field.SetCursor( 0 );
- break;
- }
- case 50: {
- ret = read( STDIN_FILENO, &key, 1 );
- if ( ret <= 0 || key != 126 ) {
- Sys_Printf( "dropping sequence: '27' '91' '50' '%d' ", key );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- // all terms
- input_field.KeyDownEvent( K_INS );
- break;
- }
- case 52: {
- ret = read( STDIN_FILENO, &key, 1 );
- if ( ret <= 0 || key != 126 ) {
- Sys_Printf( "dropping sequence: '27' '91' '52' '%d' ", key );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- // only screen and linux terms
- input_field.SetCursor( strlen( input_field.GetBuffer() ) );
- break;
- }
- case 51: {
- ret = read( STDIN_FILENO, &key, 1 );
- if ( ret <= 0 ) {
- Sys_Printf( "dropping sequence: '27' '91' '51' " );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- if ( key == 126 ) {
- input_field.KeyDownEvent( K_DEL );
- break;
- }
- Sys_Printf( "dropping sequence: '27' '91' '51' '%d'", key );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- case 65:
- case 66: {
- // history
- if ( history_current == 0 ) {
- history_backup = input_field;
- }
- if ( key == 65 ) {
- // up
- history_current++;
- } else {
- // down
- history_current--;
- }
- // history_current cycle:
- // 0: current edit
- // 1 .. Min( COMMAND_HISTORY, history_count ): back in history
- if ( history_current < 0 ) {
- history_current = Min( COMMAND_HISTORY, history_count );
- } else {
- history_current %= Min( COMMAND_HISTORY, history_count ) + 1;
- }
- int index = -1;
- if ( history_current == 0 ) {
- input_field = history_backup;
- } else {
- index = history_start + Min( COMMAND_HISTORY, history_count ) - history_current;
- index %= COMMAND_HISTORY;
- assert( index >= 0 && index < COMMAND_HISTORY );
- input_field.SetBuffer( history[ index ] );
- }
- assert( hidden );
- tty_Show();
- return NULL;
- }
- case 67:
- input_field.KeyDownEvent( K_RIGHTARROW );
- break;
- case 68:
- input_field.KeyDownEvent( K_LEFTARROW );
- break;
- default:
- Sys_Printf( "dropping sequence: '27' '91' '%d' ", key );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- break;
- }
- default:
- Sys_Printf( "dropping sequence: '27' '%d' ", key );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- break;
- }
- default:
- if ( key >= ' ' ) {
- input_field.CharEvent( key );
- break;
- }
- Sys_Printf( "dropping sequence: '%d' ", key );
- tty_FlushIn();
- assert( hidden );
- tty_Show();
- return NULL;
- }
- }
- if ( hidden ) {
- tty_Show();
- }
- return NULL;
- } else {
- // disabled on OSX. works fine from a terminal, but launching from Finder is causing trouble
- // I'm pretty sure it could be re-enabled if needed, and just handling the Finder failure case right (TTimo)
- #ifndef MACOS_X
- // no terminal support - read only complete lines
- int len;
- fd_set fdset;
- struct timeval timeout;
- FD_ZERO( &fdset );
- FD_SET( STDIN_FILENO, &fdset );
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- if ( select( 1, &fdset, NULL, NULL, &timeout ) == -1 || !FD_ISSET( 0, &fdset ) ) {
- return NULL;
- }
- len = read( 0, input_ret, sizeof( input_ret ) );
- if ( len == 0 ) {
- // EOF
- return NULL;
- }
- if ( len < 1 ) {
- Sys_Printf( "read failed: %s\n", strerror( errno ) ); // something bad happened, cancel this line and print an error
- return NULL;
- }
- if ( len == sizeof( input_ret ) ) {
- Sys_Printf( "read overflow\n" ); // things are likely to break, as input will be cut into pieces
- }
- input_ret[ len-1 ] = '\0'; // rip off the \n and terminate
- return input_ret;
- #endif
- }
- return NULL;
- }
- #ifndef USE_SDL
- /*
- called during frame loops, pacifier updates etc.
- this is only for console input polling and misc mouse grab tasks
- the actual mouse and keyboard input is in the Sys_Poll logic
- */
- void Sys_GenerateEvents( void ) {
- char *s;
- if ( ( s = Sys_ConsoleInput() ) ) {
- char *b;
- int len;
- len = strlen( s ) + 1;
- b = (char *)Mem_Alloc( len );
- strcpy( b, s );
- Posix_QueEvent( SE_CONSOLE, 0, 0, len, b );
- }
- }
- #endif
- /*
- ===============
- low level output
- ===============
- */
- void Sys_DebugPrintf( const char *fmt, ... ) {
- va_list argptr;
- tty_Hide();
- va_start( argptr, fmt );
- vprintf( fmt, argptr );
- va_end( argptr );
- tty_Show();
- }
- void Sys_DebugVPrintf( const char *fmt, va_list arg ) {
- tty_Hide();
- vprintf( fmt, arg );
- tty_Show();
- }
- void Sys_Printf(const char *msg, ...) {
- va_list argptr;
- tty_Hide();
- va_start( argptr, msg );
- vprintf( msg, argptr );
- va_end( argptr );
- tty_Show();
- }
- void Sys_VPrintf(const char *msg, va_list arg) {
- tty_Hide();
- vprintf(msg, arg);
- tty_Show();
- }
- /*
- ================
- Sys_Error
- ================
- */
- void Sys_Error(const char *error, ...) {
- va_list argptr;
- Sys_Printf( "Sys_Error: " );
- va_start( argptr, error );
- Sys_DebugVPrintf( error, argptr );
- va_end( argptr );
- Sys_Printf( "\n" );
- Posix_Exit( EXIT_FAILURE );
- }
- /*
- ===============
- Sys_FreeOpenAL
- ===============
- */
- void Sys_FreeOpenAL( void ) { }
|