diff --git a/reaction/code/sys/sys_unix.c b/reaction/code/sys/sys_unix.c index 0f4014c9..653da2ec 100644 --- a/reaction/code/sys/sys_unix.c +++ b/reaction/code/sys/sys_unix.c @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include +#include qboolean stdinIsATTY; @@ -550,28 +551,106 @@ void Sys_ErrorDialog( const char *error ) } #ifndef MACOS_X +static char execBuffer[ 1024 ]; +static char *execBufferPointer; +static char *execArgv[ 16 ]; +static int execArgc; + +/* +============== +Sys_ClearExecBuffer +============== +*/ +static void Sys_ClearExecBuffer( void ) +{ + execBufferPointer = execBuffer; + Com_Memset( execArgv, 0, sizeof( execArgv ) ); + execArgc = 0; +} + +/* +============== +Sys_AppendToExecBuffer +============== +*/ +static void Sys_AppendToExecBuffer( const char *text ) +{ + size_t size = sizeof( execBuffer ) - ( execBufferPointer - execBuffer ); + int length = strlen( text ) + 1; + + if( length > size || execArgc >= ARRAY_LEN( execArgv ) ) + return; + + Q_strncpyz( execBufferPointer, text, size ); + execArgv[ execArgc++ ] = execBufferPointer; + + execBufferPointer += length; +} + +/* +============== +Sys_Exec +============== +*/ +static int Sys_Exec( void ) +{ + pid_t pid = fork( ); + + if( pid < 0 ) + return -1; + + if( pid ) + { + // Parent + int exitCode; + + wait( &exitCode ); + + return WEXITSTATUS( exitCode ); + } + else + { + // Child + execvp( execArgv[ 0 ], execArgv ); + + // Failed to execute + exit( -1 ); + + return -1; + } +} + /* ============== Sys_ZenityCommand ============== */ -static void Sys_ZenityCommand( dialogType_t type, const char *message, const char *title, - char *command, size_t commandSize ) +static void Sys_ZenityCommand( dialogType_t type, const char *message, const char *title ) { - const char *options = ""; + Sys_ClearExecBuffer( ); + Sys_AppendToExecBuffer( "zenity" ); switch( type ) { default: - case DT_INFO: options = "--info"; break; - case DT_WARNING: options = "--warning"; break; - case DT_ERROR: options = "--error"; break; - case DT_YES_NO: options = "--question --ok-label=\"Yes\" --cancel-label=\"No\""; break; - case DT_OK_CANCEL: options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\""; break; + case DT_INFO: Sys_AppendToExecBuffer( "--info" ); break; + case DT_WARNING: Sys_AppendToExecBuffer( "--warning" ); break; + case DT_ERROR: Sys_AppendToExecBuffer( "--error" ); break; + case DT_YES_NO: + Sys_AppendToExecBuffer( "--question" ); + Sys_AppendToExecBuffer( "--ok-label=Yes" ); + Sys_AppendToExecBuffer( "--cancel-label=No" ); + break; + + case DT_OK_CANCEL: + Sys_AppendToExecBuffer( "--question" ); + Sys_AppendToExecBuffer( "--ok-label=OK" ); + Sys_AppendToExecBuffer( "--cancel-label=Cancel" ); + break; } - Com_sprintf( command, commandSize, "zenity %s --text=\"%s\" --title=\"%s\" >/dev/null 2>/dev/null", - options, message, title ); + Sys_AppendToExecBuffer( va( "--text=%s", message ) ); + Sys_AppendToExecBuffer( va( "--title=%s", title ) ); } /* @@ -579,23 +658,23 @@ static void Sys_ZenityCommand( dialogType_t type, const char *message, const cha Sys_KdialogCommand ============== */ -static void Sys_KdialogCommand( dialogType_t type, const char *message, const char *title, - char *command, size_t commandSize ) +static void Sys_KdialogCommand( dialogType_t type, const char *message, const char *title ) { - const char *options = ""; + Sys_ClearExecBuffer( ); + Sys_AppendToExecBuffer( "kdialog" ); switch( type ) { default: - case DT_INFO: options = "--msgbox"; break; - case DT_WARNING: options = "--sorry"; break; - case DT_ERROR: options = "--error"; break; - case DT_YES_NO: options = "--warningyesno"; break; - case DT_OK_CANCEL: options = "--warningcontinuecancel"; break; + case DT_INFO: Sys_AppendToExecBuffer( "--msgbox" ); break; + case DT_WARNING: Sys_AppendToExecBuffer( "--sorry" ); break; + case DT_ERROR: Sys_AppendToExecBuffer( "--error" ); break; + case DT_YES_NO: Sys_AppendToExecBuffer( "--warningyesno" ); break; + case DT_OK_CANCEL: Sys_AppendToExecBuffer( "--warningcontinuecancel" ); break; } - Com_sprintf( command, commandSize, "kdialog %s \"%s\" --title \"%s\" >/dev/null 2>/dev/null", - options, message, title ); + Sys_AppendToExecBuffer( message ); + Sys_AppendToExecBuffer( va( "--title=%s", title ) ); } /* @@ -603,20 +682,21 @@ static void Sys_KdialogCommand( dialogType_t type, const char *message, const ch Sys_XmessageCommand ============== */ -static void Sys_XmessageCommand( dialogType_t type, const char *message, const char *title, - char *command, size_t commandSize ) +static void Sys_XmessageCommand( dialogType_t type, const char *message, const char *title ) { - const char *options = ""; + Sys_ClearExecBuffer( ); + Sys_AppendToExecBuffer( "xmessage" ); + Sys_AppendToExecBuffer( "-buttons" ); switch( type ) { - default: options = "-buttons OK:0"; break; - case DT_YES_NO: options = "-buttons Yes:0,No:1"; break; - case DT_OK_CANCEL: options = "-buttons OK:0,Cancel:1"; break; + default: Sys_AppendToExecBuffer( "OK:0" ); break; + case DT_YES_NO: Sys_AppendToExecBuffer( "Yes:0,No:1" ); break; + case DT_OK_CANCEL: Sys_AppendToExecBuffer( "OK:0,Cancel:1" ); break; } - Com_sprintf( command, commandSize, "xmessage -center %s \"%s\" >/dev/null 2>/dev/null", - options, message ); + Sys_AppendToExecBuffer( "-center" ); + Sys_AppendToExecBuffer( message ); } /* @@ -636,7 +716,7 @@ dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *t XMESSAGE, NUM_DIALOG_PROGRAMS } dialogCommandType_t; - typedef void (*dialogCommandBuilder_t)( dialogType_t, const char *, const char *, char *, size_t ); + typedef void (*dialogCommandBuilder_t)( dialogType_t, const char *, const char * ); const char *session = getenv( "DESKTOP_SESSION" ); qboolean tried[ NUM_DIALOG_PROGRAMS ] = { qfalse }; @@ -665,21 +745,16 @@ dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *t if( !tried[ i ] ) { int exitCode; - int childSignal; - int childCode; - char command[ 1024 ]; - commands[ i ]( type, message, title, command, sizeof( command ) ); - exitCode = system( command ); - childSignal = exitCode & 127; - childCode = exitCode >> 8; + commands[ i ]( type, message, title ); + exitCode = Sys_Exec( ); - if( exitCode != -1 && childSignal == 0 && childCode != 126 && childCode != 127 ) + if( exitCode >= 0 ) { switch( type ) { - case DT_YES_NO: return childCode ? DR_NO : DR_YES; - case DT_OK_CANCEL: return childCode ? DR_CANCEL : DR_OK; + case DT_YES_NO: return exitCode ? DR_NO : DR_YES; + case DT_OK_CANCEL: return exitCode ? DR_CANCEL : DR_OK; default: return DR_OK; } }