* Adjustment: Initial work on moving x86Unix platform code into a more common POSIX platform.

This commit is contained in:
Robert MacGregor 2021-11-13 20:22:49 -05:00
parent e9414a1660
commit 6583134ef2
34 changed files with 33 additions and 5216 deletions

View file

@ -0,0 +1,51 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef __APPLE__
#include "platform/platform.h"
#include "platformX86UNIX/platformX86UNIX.h"
#include "console/console.h"
#include "core/stringTable.h"
#include "core/strings/stringFunctions.h"
#include <math.h>
#include "platform/platformCPUCount.h"
#include <unistd.h>
Platform::SystemInfo_struct Platform::SystemInfo;
void Processor::init() {}
// TODO LINUX CPUInfo::CPUCount better support
namespace CPUInfo
{
EConfig CPUCount(U32& TotAvailLogical, U32& TotAvailCore, U32& PhysicalNum)
{
PhysicalNum = TotAvailCore = 0;
TotAvailLogical = (int)sysconf(_SC_NPROCESSORS_ONLN);
return CONFIG_SingleCoreHTDisabled;
}
}; // namespace CPUInfo
#endif

View file

@ -0,0 +1,426 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platformX86UNIX/platformX86UNIX.h"
#include "platformPOSIX/POSIXStdConsole.h"
#include "platformPOSIX/POSIXUtils.h"
#include "platform/input/event.h"
#include "platform/platform.h"
#include "core/util/rawData.h"
#include "core/strings/stringFunctions.h"
#include "core/util/journal/process.h"
#include <signal.h>
#include <unistd.h>
#include <stdarg.h>
#include <fcntl.h>
#include "console/engineAPI.h"
StdConsole *stdConsole = NULL;
DefineEngineFunction(enableWinConsole, void, (bool _enable),, "enableWinConsole(bool);")
{
if (stdConsole)
{
stdConsole->enable(_enable);
stdConsole->enableInput(_enable);
}
}
void StdConsole::create()
{
if (stdConsole == NULL)
stdConsole = new StdConsole();
}
void StdConsole::destroy()
{
if (stdConsole && stdConsole->isEnabled())
stdConsole->enable(false);
delete stdConsole;
stdConsole = NULL;
}
static void signalHandler(int sigtype)
{
if (sigtype == SIGCONT && stdConsole != NULL)
stdConsole->resetTerminal();
}
void StdConsole::resetTerminal()
{
if (stdConsoleEnabled)
{
/* setup the proper terminal modes */
struct termios termModes;
tcgetattr(stdIn, &termModes);
termModes.c_lflag &= ~ICANON; // enable non-canonical mode
termModes.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHOKE);
termModes.c_cc[VMIN] = 0;
termModes.c_cc[VTIME] = 5;
tcsetattr(stdIn, TCSAFLUSH, &termModes);
}
}
void StdConsole::enable(bool enabled)
{
if (enabled && !stdConsoleEnabled)
{
stdConsoleEnabled = true;
// install signal handler for sigcont
signal(SIGCONT, &signalHandler);
// save the terminal state
if (originalTermState == NULL)
originalTermState = new termios;
tcgetattr(stdIn, originalTermState);
// put the terminal into our preferred mode
resetTerminal();
printf("%s", Con::getVariable("Con::Prompt"));
}
else if (!enabled && stdConsoleEnabled)
{
stdConsoleEnabled = false;
// uninstall signal handler
signal(SIGCONT, SIG_DFL);
// reset the original terminal state
if (originalTermState != NULL)
tcsetattr(stdIn, TCSANOW, originalTermState);
}
}
void StdConsole::enableInput( bool enabled )
{
stdConsoleInputEnabled = enabled;
}
bool StdConsole::isEnabled()
{
if ( stdConsole )
return stdConsole->stdConsoleEnabled;
return false;
}
static void stdConsoleConsumer(/*ConsoleLogEntry::Level*/ U32, const char *line)
{
stdConsole->processConsoleLine(line);
}
StdConsole::StdConsole()
{
for (S32 iIndex = 0; iIndex < MAX_CMDS; iIndex ++)
rgCmds[iIndex][0] = '\0';
stdOut = dup(1);
stdIn = dup(0);
stdErr = dup(2);
// Ensure in buffer is null terminated after allocation
inbuf[0] = 0x00;
iCmdIndex = 0;
stdConsoleEnabled = false;
stdConsoleInputEnabled = false;
Con::addConsumer(stdConsoleConsumer);
inpos = 0;
lineOutput = false;
inBackground = false;
originalTermState = NULL;
Process::notify(this, &StdConsole::process, PROCESS_LAST_ORDER);
}
StdConsole::~StdConsole()
{
Con::removeConsumer(stdConsoleConsumer);
if (stdConsoleEnabled)
enable(false);
if (originalTermState != NULL)
{
delete originalTermState;
originalTermState = NULL;
}
}
void StdConsole::printf(const char *s, ...)
{
// Get the line into a buffer.
static const int BufSize = 4096;
static char buffer[BufSize];
va_list args;
va_start(args, s);
vsnprintf(buffer, BufSize, s, args);
va_end(args);
// Replace tabs with carats, like the "real" console does.
char *pos = buffer;
while (*pos) {
if (*pos == '\t') {
*pos = '^';
}
pos++;
}
// Axe the color characters.
Con::stripColorChars(buffer);
// Print it.
write(stdOut, buffer, strlen(buffer));
fflush(stdout);
}
void StdConsole::processConsoleLine(const char *consoleLine)
{
if(stdConsoleEnabled)
{
if(lineOutput)
printf("%s\n", consoleLine);
else
{
// Clear current line before outputting the console line. This prevents prompt text from overflowing onto normal output.
printf("%c[2K", 27);
printf("%c%s\n%s%s", '\r', consoleLine, Con::getVariable("Con::Prompt"), inbuf);
}
}
}
void StdConsole::process()
{
if(stdConsoleEnabled)
{
//U16 key;
char typedData[64]; // damn, if you can type this fast... :-D
if (UUtils->inBackground())
// we don't have the terminal
inBackground = true;
else
{
// if we were in the background, reset the terminal
if (inBackground)
resetTerminal();
inBackground = false;
}
// see if stdIn has any input waiting
// mojo for select call
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(stdIn, &rfds);
// don't wait at all in select
tv.tv_sec = 0;
tv.tv_usec = 0;
int numEvents = select(stdIn+1, &rfds, NULL, NULL, &tv);
if (numEvents <= 0)
// no data available
return;
numEvents = read(stdIn, typedData, 64);
if (numEvents == -1)
return;
// TODO LINUX, when debug in qtCreator some times we get false console inputs.
if( !stdConsoleInputEnabled )
return;
typedData[numEvents] = '\0';
if (numEvents > 0)
{
char outbuf[512];
S32 outpos = 0;
for (int i = 0; i < numEvents; i++)
{
switch(typedData[i])
{
case 8:
case 127:
/* backspace */
if (inpos > 0)
{
outbuf[outpos++] = '\b';
outbuf[outpos++] = ' ';
outbuf[outpos++] = '\b';
inpos--;
}
break;
// XXX Don't know if we can detect shift-TAB. So, only handling
// TAB for now.
case '\t':
// In the output buffer, we're going to have to erase the current line (in case
// we're cycling through various completions) and write out the whole input
// buffer, so (inpos * 3) + complen <= 512. Should be OK. The input buffer is
// also 512 chars long so that constraint will also be fine for the input buffer.
{
// Erase the current line.
U32 i;
for (i = 0; i < inpos; i++) {
outbuf[outpos++] = '\b';
outbuf[outpos++] = ' ';
outbuf[outpos++] = '\b';
}
// Modify the input buffer with the completion.
U32 maxlen = 512 - (inpos * 3);
inpos = Con::tabComplete(inbuf, inpos, maxlen, true);
// Copy the input buffer to the output.
for (i = 0; i < inpos; i++) {
outbuf[outpos++] = inbuf[i];
}
}
break;
case '\n':
case '\r':
/* new line */
outbuf[outpos++] = '\n';
inbuf[inpos] = 0;
outbuf[outpos] = 0;
printf("%s", outbuf);
S32 eventSize;
eventSize = 1;
{
RawData rd;
rd.size = inpos + 1;
rd.data = (S8*) inbuf;
Con::smConsoleInput.trigger(rd);
}
// If we've gone off the end of our array, wrap
// back to the beginning
if (iCmdIndex >= MAX_CMDS)
iCmdIndex %= MAX_CMDS;
// Put the new command into the array
strcpy(rgCmds[iCmdIndex ++], inbuf);
printf("%s", Con::getVariable("Con::Prompt"));
inpos = outpos = 0;
inbuf[0] = 0x00; // Ensure inbuf is NULL terminated after sending out command
break;
case 27:
// JMQTODO: are these magic numbers keyboard map specific?
if (typedData[i+1] == 91 || typedData[i+1] == 79)
{
i += 2;
// an arrow key was pressed.
switch(typedData[i])
{
case 'A':
/* up arrow */
// Go to the previous command in the cyclic array
if ((-- iCmdIndex) < 0)
iCmdIndex = MAX_CMDS - 1;
// If this command isn't empty ...
if (rgCmds[iCmdIndex][0] != '\0')
{
// Obliterate current displayed text
for (S32 i = outpos = 0; i < inpos; i ++)
{
outbuf[outpos++] = '\b';
outbuf[outpos++] = ' ';
outbuf[outpos++] = '\b';
}
// Copy command into command and display buffers
for (inpos = 0; inpos < (S32)strlen(rgCmds[iCmdIndex]); inpos++, outpos++)
{
outbuf[outpos] = rgCmds[iCmdIndex][inpos];
inbuf [inpos ] = rgCmds[iCmdIndex][inpos];
}
}
// If previous is empty, stay on current command
else if ((++ iCmdIndex) >= MAX_CMDS)
{
iCmdIndex = 0;
}
break;
case 'B':
/* down arrow */
// Go to the next command in the command array, if
// it isn't empty
if (rgCmds[iCmdIndex][0] != '\0' && (++ iCmdIndex) >= MAX_CMDS)
iCmdIndex = 0;
// Obliterate current displayed text
for (S32 i = outpos = 0; i < inpos; i ++)
{
outbuf[outpos++] = '\b';
outbuf[outpos++] = ' ';
outbuf[outpos++] = '\b';
}
// Copy command into command and display buffers
for (inpos = 0; inpos < (S32)strlen(rgCmds[iCmdIndex]); inpos++, outpos++)
{
outbuf[outpos] = rgCmds[iCmdIndex][inpos];
inbuf [inpos ] = rgCmds[iCmdIndex][inpos];
}
break;
case 'C':
/* right arrow */
break;
case 'D':
/* left arrow */
break;
}
// read again to get rid of a bad char.
//read(stdIn, &key, sizeof(char));
break;
} else {
inbuf[inpos++] = typedData[i];
outbuf[outpos++] = typedData[i];
break;
}
break;
default:
inbuf[inpos++] = typedData[i];
outbuf[outpos++] = typedData[i];
break;
}
}
if (outpos)
{
outbuf[outpos] = 0;
printf("%s", outbuf);
}
}
}
}

View file

@ -0,0 +1,392 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#if 0
#include "platformX86UNIX/platformGL.h"
#include "platformX86UNIX/platformX86UNIX.h"
#include "console/console.h"
#include <dlfcn.h>
#include <SDL/SDL.h>
// declare stub functions
#define GL_FUNCTION(fn_return, fn_name, fn_args, fn_value) fn_return stub_##fn_name fn_args{ fn_value }
#include "platform/GLCoreFunc.h"
#include "platform/GLExtFunc.h"
#undef GL_FUNCTION
// point gl function pointers at stub functions
#define GL_FUNCTION(fn_return,fn_name,fn_args, fn_value) fn_return (*fn_name)fn_args = stub_##fn_name;
#include "platform/GLCoreFunc.h"
#include "platform/GLExtFunc.h"
#undef GL_FUNCTION
static void* dlHandle = NULL;
//------------------------------------------------------------------
//bind functions for each function prototype
//------------------------------------------------------------------
//GL_EXT/ARB
enum {
ARB_multitexture = BIT(0),
ARB_texture_compression = BIT(1),
EXT_compiled_vertex_array = BIT(2),
EXT_fog_coord = BIT(3),
EXT_paletted_texture = BIT(4),
NV_vertex_array_range = BIT(5),
EXT_blend_color = BIT(6),
EXT_blend_minmax = BIT(7)
};
//WGL_ARB
enum {
WGL_ARB_extensions_string = BIT(0),
WGL_EXT_swap_control = BIT(1),
WGL_3DFX_gamma_control = BIT(2)
};
static bool isFnOk( const char *name)
{
bool ok = false;
// JMQ: these are specific to torque's d3d->gl wrapper. They are not used under linux.
if (dStrcmp(name, "glAvailableVertexBufferEXT")==0)
ok = true;
else if (dStrcmp(name, "glAllocateVertexBufferEXT")==0)
ok = true;
else if (dStrcmp(name, "glLockVertexBufferEXT")==0)
ok = true;
else if (dStrcmp(name, "glUnlockVertexBufferEXT")==0)
ok = true;
else if (dStrcmp(name, "glSetVertexBufferEXT")==0)
ok = true;
else if (dStrcmp(name, "glOffsetVertexBufferEXT")==0)
ok = true;
else if (dStrcmp(name, "glFillVertexBufferEXT")==0)
ok = true;
else if (dStrcmp(name, "glFreeVertexBufferEXT")==0)
ok = true;
return ok;
}
//------------------------------------------------------------------
//bind functions for each function prototype
//------------------------------------------------------------------
static bool bindGLFunction( void *&fnAddress, const char *name )
{
void* addr = (void*)SDL_GL_GetProcAddress(name);
bool ok = (bool)addr;
if( !ok )
{
if (!isFnOk(name))
Con::errorf(ConsoleLogEntry::General, " Missing OpenGL function '%s'", name);
else
ok = true;
}
else
fnAddress = addr;
return ok;
}
static bool bindEXTFunction( void *&fnAddress, const char *name )
{
void* addr = (void*)SDL_GL_GetProcAddress(name);
if( !addr )
Con::errorf(ConsoleLogEntry::General, " Missing OpenGL extension '%s'", name);
else
fnAddress = addr;
return (addr != NULL);
}
//------------------------------------------------------------------
//binds for each function group
//------------------------------------------------------------------
static bool bindGLFunctions()
{
bool result = true;
#define GL_FUNCTION(fn_return, fn_name, fn_args, fn_value) \
result &= bindGLFunction( *(void**)&fn_name, #fn_name);
#include "platform/GLCoreFunc.h"
#undef GL_FUNCTION
return result;
}
static bool bindEXTFunctions(U32 extMask)
{
bool result = true;
#define GL_GROUP_BEGIN( flag ) \
if( extMask & flag ) {
#define GL_GROUP_END() }
#define GL_FUNCTION(fn_return, fn_name, fn_args, fn_value) \
result &= bindEXTFunction( *(void**)&fn_name, #fn_name);
#include "platform/GLExtFunc.h"
#undef GL_FUNCTION
#undef GL_GROUP_BEGIN
#undef GL_GROUP_END
return result;
}
static void unbindGLFunctions()
{
// point gl function pointers at stub functions
#define GL_FUNCTION(fn_return, fn_name, fn_args, fn_value) fn_name = stub_##fn_name;
#include "platform/GLCoreFunc.h"
#include "platform/GLExtFunc.h"
#undef GL_FUNCTION
}
namespace GLLoader
{
bool OpenGLInit()
{
return OpenGLDLLInit();
}
void OpenGLShutdown()
{
OpenGLDLLShutdown();
}
bool OpenGLDLLInit()
{
OpenGLDLLShutdown();
// load libGL.so
if (SDL_GL_LoadLibrary("libGL.so") == -1 &&
SDL_GL_LoadLibrary("libGL.so.1") == -1)
{
Con::errorf("Error loading GL library: %s", SDL_GetError());
return false;
}
// bind functions
if (!bindGLFunctions())
{
Con::errorf("Error binding GL functions");
OpenGLDLLShutdown();
return false;
}
return true;
}
void OpenGLDLLShutdown()
{
// there is no way to tell SDL to unload the library
if (dlHandle != NULL)
{
dlclose(dlHandle);
dlHandle = NULL;
}
unbindGLFunctions();
}
}
GLState gGLState;
bool gOpenGLDisablePT = false;
bool gOpenGLDisableCVA = false;
bool gOpenGLDisableTEC = false;
bool gOpenGLDisableARBMT = false;
bool gOpenGLDisableFC = false;
bool gOpenGLDisableTCompress = false;
bool gOpenGLNoEnvColor = false;
float gOpenGLGammaCorrection = 0.5;
bool gOpenGLNoDrawArraysAlpha = false;
// JMQTODO: really need a platform-shared version of this nastiness
bool GL_EXT_Init( )
{
// Load extensions...
//
const char* pExtString = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
gGLState.primMode = 0;
U32 extBitMask = 0;
// GL_EXT_paletted_texture
if (pExtString && dStrstr(pExtString, (const char*)"GL_EXT_paletted_texture") != NULL)
{
extBitMask |= EXT_paletted_texture;
gGLState.suppPalettedTexture = true;
}
else
gGLState.suppPalettedTexture = false;
// EXT_compiled_vertex_array
if (pExtString && dStrstr(pExtString, (const char*)"GL_EXT_compiled_vertex_array") != NULL)
{
extBitMask |= EXT_compiled_vertex_array;
gGLState.suppLockedArrays = true;
}
else
{
gGLState.suppLockedArrays = false;
}
// ARB_multitexture
if (pExtString && dStrstr(pExtString, (const char*)"GL_ARB_multitexture") != NULL)
{
extBitMask |= ARB_multitexture;
gGLState.suppARBMultitexture = true;
} else {
gGLState.suppARBMultitexture = false;
}
// EXT_blend_color
if(pExtString && dStrstr(pExtString, (const char*)"GL_EXT_blend_color") != NULL)
{
extBitMask |= EXT_blend_color;
gGLState.suppEXTblendcolor = true;
} else {
gGLState.suppEXTblendcolor = false;
}
// EXT_blend_minmax
if(pExtString && dStrstr(pExtString, (const char*)"GL_EXT_blend_minmax") != NULL)
{
extBitMask |= EXT_blend_color;
gGLState.suppEXTblendminmax = true;
} else {
gGLState.suppEXTblendminmax = false;
}
// EXT_fog_coord
if (pExtString && dStrstr(pExtString, (const char*)"GL_EXT_fog_coord") != NULL)
{
extBitMask |= EXT_fog_coord;
gGLState.suppFogCoord = true;
} else {
gGLState.suppFogCoord = false;
}
// EXT_texture_compression_s3tc
if (pExtString && dStrstr(pExtString, (const char*)"GL_EXT_texture_compression_s3tc") != NULL)
gGLState.suppS3TC = true;
else
gGLState.suppS3TC = false;
// ARB_texture_compression
if (pExtString && dStrstr(pExtString, (const char*)"GL_ARB_texture_compression") != NULL)
{
extBitMask |= ARB_texture_compression;
gGLState.suppTextureCompression = true;
} else {
gGLState.suppTextureCompression = false;
}
// NV_vertex_array_range (not on *nix)
gGLState.suppVertexArrayRange = false;
// 3DFX_texture_compression_FXT1
if (pExtString && dStrstr(pExtString, (const char*)"3DFX_texture_compression_FXT1") != NULL)
gGLState.suppFXT1 = true;
else
gGLState.suppFXT1 = false;
if (!bindEXTFunctions(extBitMask))
Con::warnf("You are missing some OpenGL Extensions. You may experience rendering problems.");
// Binary states, i.e., no supporting functions
// EXT_packed_pixels
// EXT_texture_env_combine
//
// dhc note: a number of these can have multiple matching 'versions', private, ext, and arb.
gGLState.suppPackedPixels = pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_packed_pixels") != NULL) : false;
gGLState.suppTextureEnvCombine = pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_texture_env_combine") != NULL) : false;
gGLState.suppEdgeClamp = pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_texture_edge_clamp") != NULL) : false;
gGLState.suppEdgeClamp |= pExtString? (dStrstr(pExtString, (const char*)"GL_SGIS_texture_edge_clamp") != NULL) : false;
gGLState.suppTexEnvAdd = pExtString? (dStrstr(pExtString, (const char*)"GL_ARB_texture_env_add") != NULL) : false;
gGLState.suppTexEnvAdd |= pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_texture_env_add") != NULL) : false;
// Anisotropic filtering
gGLState.suppTexAnisotropic = pExtString? (dStrstr(pExtString, (const char*)"GL_EXT_texture_filter_anisotropic") != NULL) : false;
if (gGLState.suppTexAnisotropic)
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGLState.maxAnisotropy);
if (gGLState.suppARBMultitexture)
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gGLState.maxTextureUnits);
else
gGLState.maxTextureUnits = 1;
// JMQ: vsync/swap interval skipped
gGLState.suppSwapInterval = false;
Con::printf("OpenGL Init: Enabled Extensions");
if (gGLState.suppARBMultitexture) Con::printf(" ARB_multitexture (Max Texture Units: %d)", gGLState.maxTextureUnits);
if (gGLState.suppEXTblendcolor) Con::printf(" EXT_blend_color");
if (gGLState.suppEXTblendminmax) Con::printf(" EXT_blend_minmax");
if (gGLState.suppPalettedTexture) Con::printf(" EXT_paletted_texture");
if (gGLState.suppLockedArrays) Con::printf(" EXT_compiled_vertex_array");
if (gGLState.suppVertexArrayRange) Con::printf(" NV_vertex_array_range");
if (gGLState.suppTextureEnvCombine) Con::printf(" EXT_texture_env_combine");
if (gGLState.suppPackedPixels) Con::printf(" EXT_packed_pixels");
if (gGLState.suppFogCoord) Con::printf(" EXT_fog_coord");
if (gGLState.suppTextureCompression) Con::printf(" ARB_texture_compression");
if (gGLState.suppS3TC) Con::printf(" EXT_texture_compression_s3tc");
if (gGLState.suppFXT1) Con::printf(" 3DFX_texture_compression_FXT1");
if (gGLState.suppTexEnvAdd) Con::printf(" (ARB|EXT)_texture_env_add");
if (gGLState.suppTexAnisotropic) Con::printf(" EXT_texture_filter_anisotropic (Max anisotropy: %f)", gGLState.maxAnisotropy);
if (gGLState.suppSwapInterval) Con::printf(" WGL_EXT_swap_control");
Con::warnf("OpenGL Init: Disabled Extensions");
if (!gGLState.suppARBMultitexture) Con::warnf(" ARB_multitexture");
if (!gGLState.suppEXTblendcolor) Con::warnf(" EXT_blend_color");
if (!gGLState.suppEXTblendminmax) Con::warnf(" EXT_blend_minmax");
if (!gGLState.suppPalettedTexture) Con::warnf(" EXT_paletted_texture");
if (!gGLState.suppLockedArrays) Con::warnf(" EXT_compiled_vertex_array");
if (!gGLState.suppVertexArrayRange) Con::warnf(" NV_vertex_array_range");
if (!gGLState.suppTextureEnvCombine) Con::warnf(" EXT_texture_env_combine");
if (!gGLState.suppPackedPixels) Con::warnf(" EXT_packed_pixels");
if (!gGLState.suppFogCoord) Con::warnf(" EXT_fog_coord");
if (!gGLState.suppTextureCompression) Con::warnf(" ARB_texture_compression");
if (!gGLState.suppS3TC) Con::warnf(" EXT_texture_compression_s3tc");
if (!gGLState.suppFXT1) Con::warnf(" 3DFX_texture_compression_FXT1");
if (!gGLState.suppTexEnvAdd) Con::warnf(" (ARB|EXT)_texture_env_add");
if (!gGLState.suppTexAnisotropic) Con::warnf(" EXT_texture_filter_anisotropic");
if (!gGLState.suppSwapInterval) Con::warnf(" WGL_EXT_swap_control");
Con::printf(" ");
// Set some console variables:
Con::setBoolVariable( "$FogCoordSupported", gGLState.suppFogCoord );
Con::setBoolVariable( "$TextureCompressionSupported", gGLState.suppTextureCompression );
Con::setBoolVariable( "$AnisotropySupported", gGLState.suppTexAnisotropic );
Con::setBoolVariable( "$PalettedTextureSupported", gGLState.suppPalettedTexture );
Con::setBoolVariable( "$SwapIntervalSupported", gGLState.suppSwapInterval );
if (!gGLState.suppPalettedTexture && Con::getBoolVariable("$pref::OpenGL::forcePalettedTexture",false))
{
Con::setBoolVariable("$pref::OpenGL::forcePalettedTexture", false);
Con::setBoolVariable("$pref::OpenGL::force16BitTexture", true);
}
return true;
}
#endif // 0

View file

@ -0,0 +1,107 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef __APPLE__
#include "platform/platform.h"
#include "platform/platformInput.h"
#include "console/console.h"
#include "platformX86UNIX/platformX86UNIX.h"
#include "platformPOSIX/POSIXStdConsole.h"
#include "platformPOSIX/POSIXState.h"
extern void InitWindowingSystem();
//------------------------------------------------------------------------------
void Platform::init()
{
StdConsole::create();
stdConsole->enable(true);
// init process control stuff
ProcessControlInit();
Con::printf("Initializing platform...");
// Set the platform variable for the scripts
Con::setVariable( "$platform", "x86UNIX" );
#if defined(__linux__)
Con::setVariable( "$platformUnixType", "Linux" );
#elif defined(__OpenBSD__)
Con::setVariable( "$platformUnixType", "OpenBSD" );
#else
Con::setVariable( "$platformUnixType", "Unknown" );
#endif
Input::init();
//installRedBookDevices();
#ifndef TORQUE_DEDICATED
// if we're not dedicated do more initialization
InitWindowingSystem();
#endif
}
//------------------------------------------------------------------------------
void Platform::shutdown()
{
Cleanup();
}
//------------------------------------------------------------------------------
extern "C"
{
bool torque_engineinit(int argc, const char **argv);
int torque_enginetick();
S32 torque_getreturnstatus();
bool torque_engineshutdown();
int torque_unixmain(int argc, const char **argv)
{
if (!torque_engineinit(argc, argv))
return 1;
while(torque_enginetick())
{
}
torque_engineshutdown();
return torque_getreturnstatus();
}
}
extern S32 TorqueMain(S32 argc, const char **argv);
#if !defined(TORQUE_SHARED)
int main(int argc, const char **argv)
{
return TorqueMain(argc, argv);
}
#endif
#endif

View file

@ -0,0 +1,182 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef __APPLE__
#include "platform/platform.h"
#include "console/console.h"
#include "math/mMath.h"
#include "core/strings/stringFunctions.h"
#include "console/engineAPI.h"
extern void mInstallLibrary_C();
extern void mInstallLibrary_ASM();
extern void mInstall_AMD_Math();
extern void mInstall_Library_SSE();
//--------------------------------------
DefineEngineStringlyVariadicFunction( mathInit, void, 1, 10, "( ... )"
"@brief Install the math library with specified extensions.\n\n"
"Possible parameters are:\n\n"
" - 'DETECT' Autodetect math lib settings.\n\n"
" - 'C' Enable the C math routines. C routines are always enabled.\n\n"
" - 'SSE' Enable SSE math routines.\n\n"
"@ingroup Math")
{
U32 properties = CPU_PROP_C; // C entensions are always used
if (argc == 1)
{
Math::init(0);
return;
}
for (argc--, argv++; argc; argc--, argv++)
{
if (dStricmp(*argv, "DETECT") == 0) {
Math::init(0);
return;
}
if (dStricmp(*argv, "C") == 0) {
properties |= CPU_PROP_C;
continue;
}
if (dStricmp(*argv, "FPU") == 0) {
properties |= CPU_PROP_FPU;
continue;
}
if (dStricmp(*argv, "MMX") == 0) {
properties |= CPU_PROP_MMX;
continue;
}
if (dStricmp(*argv, "3DNOW") == 0) {
properties |= CPU_PROP_3DNOW;
continue;
}
if (dStricmp(*argv, "SSE") == 0) {
properties |= CPU_PROP_SSE;
continue;
}
Con::printf("Error: MathInit(): ignoring unknown math extension '%s'", (const char*)argv[0]);
}
Math::init(properties);
}
//------------------------------------------------------------------------------
void Math::init(U32 properties)
{
if (!properties)
// detect what's available
properties = Platform::SystemInfo.processor.properties;
else
// Make sure we're not asking for anything that's not supported
properties &= Platform::SystemInfo.processor.properties;
Con::printf("Math Init:");
Con::printf(" Installing Standard C extensions");
mInstallLibrary_C();
#if defined(TORQUE_CPU_X32) || defined(TORQUE_CPU_X64)
Con::printf(" Installing Assembly extensions");
mInstallLibrary_ASM();
#endif
if (properties & CPU_PROP_FPU)
{
Con::printf(" Installing FPU extensions");
}
if (properties & CPU_PROP_MMX)
{
Con::printf(" Installing MMX extensions");
if (properties & CPU_PROP_3DNOW)
{
Con::printf(" Installing 3DNow extensions");
mInstall_AMD_Math();
}
}
#if !defined(__MWERKS__) || (__MWERKS__ >= 0x2400)
if (properties & CPU_PROP_SSE)
{
Con::printf(" Installing SSE extensions");
mInstall_Library_SSE();
}
#endif //mwerks>2.4
Con::printf(" ");
}
//------------------------------------------------------------------------------
static MRandomLCG sgPlatRandom;
F32 Platform::getRandom()
{
return sgPlatRandom.randF();
}
#if defined(TORQUE_CPU_X86) || defined(__x86_64__)
U32 Platform::getMathControlState()
{
U16 cw;
asm("fstcw %0" : "=m" (cw) :);
return cw;
}
void Platform::setMathControlState(U32 state)
{
U16 cw = state;
asm("fldcw %0" : : "m" (cw));
}
void Platform::setMathControlStateKnown()
{
U16 cw = 0x27F;
asm("fldcw %0" : : "m" (cw));
}
#else
U32 Platform::getMathControlState()
{
return 0;
}
void Platform::setMathControlState(U32 state)
{
}
void Platform::setMathControlStateKnown()
{
}
#endif
#endif

View file

@ -0,0 +1,68 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platformX86UNIX/platformX86UNIX.h"
#include <stdlib.h>
#include <mm_malloc.h>
void* dMemcpy(void *dst, const void *src, dsize_t size)
{
return memcpy(dst,src,size);
}
//--------------------------------------
void* dMemmove(void *dst, const void *src, dsize_t size)
{
return memmove(dst,src,size);
}
//--------------------------------------
void* dMemset(void *dst, S32 c, dsize_t size)
{
return memset(dst,c,size);
}
//--------------------------------------
S32 dMemcmp(const void *ptr1, const void *ptr2, dsize_t len)
{
return memcmp(ptr1, ptr2, len);
}
void* dRealMalloc(dsize_t s)
{
return malloc(s);
}
void dRealFree(void* p)
{
free(p);
}
void *dMalloc_aligned(dsize_t in_size, int alignment)
{
return _mm_malloc(in_size, alignment);
}
void dFree_aligned(void* p)
{
return _mm_free(p);
}

View file

@ -0,0 +1,237 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef __APPLE__
#include "platformX86UNIX/platformX86UNIX.h"
#include "platformPOSIX/POSIXState.h"
#include "platformPOSIX/POSIXStdConsole.h"
#include "platform/platformInput.h"
#include "windowManager/platformWindow.h"
#include "windowManager/platformWindowMgr.h"
#include "console/console.h"
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "console/engineAPI.h"
#ifndef TORQUE_DEDICATED
#include <SDL.h>
#endif
//-----------------------------------------------------------------------------
// This is a mainly a debugging function for intercepting a nonzero exit code
// and generating a core dump for a stack trace.
// Need an S64 here because postQuitMessage uses a U32, and
// forceshutdown uses an S32. So S64 is needed to
// accomodate them both
static void CheckExitCode(S64 exitCode)
{
if (exitCode != 0)
{
Con::errorf(ConsoleLogEntry::General,
"Nonzero exit code: %d, triggering SIGSEGV for core dump",
exitCode);
kill(getpid(), SIGSEGV);
}
}
//-----------------------------------------------------------------------------
static void SignalHandler(int sigtype)
{
if (sigtype == SIGSEGV || sigtype == SIGTRAP)
{
signal(SIGSEGV, SIG_DFL);
signal(SIGTRAP, SIG_DFL);
// restore the signal handling to default so that we don't get into
// a crash loop with ImmediateShutdown
ImmediateShutdown(-sigtype, sigtype);
}
else
{
signal(sigtype, SIG_DFL);
dPrintf("Unknown signal caught by SignalHandler: %d\n", sigtype);
// exit to be safe
ImmediateShutdown(1);
}
}
//-----------------------------------------------------------------------------
void Cleanup(bool minimal)
{
if (!minimal)
{
Input::destroy();
}
StdConsole::destroy();
#ifndef TORQUE_DEDICATED
SDL_Quit();
#endif
}
//-----------------------------------------------------------------------------
void ImmediateShutdown(S32 exitCode, S32 signalNum)
{
bool segfault = signalNum > 0;
Cleanup(segfault);
if (!segfault)
{
dPrintf("Exiting\n");
// exit (doesn't call destructors)
_exit(exitCode);
}
else
{
// there is a problem in kernel 2.4.17 which causes a hang when a segfault
// occurs. also subsequent runs of "ps" will hang and the machine has to be
// hard reset to clear up the problem
// JMQ: this bug appears to be fixed in 2.4.18
//#define KERNEL_2_4_WORKAROUND
#ifdef KERNEL_2_4_WORKAROUND
dPrintf("Segmentation Fault (Exiting without core dump due to #define KERNEL_2_4_WORKAROUND)\n");
dFflushStdout();
_exit(exitCode);
#else
// kill with signal
kill(getpid(), signalNum);
#endif
}
}
//-----------------------------------------------------------------------------
void ProcessControlInit()
{
// JMQ: ignore IO signals background read/write terminal (so that we don't
// get suspended in daemon mode)
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
// we're not interested in the exit status of child processes, so this
// prevents zombies from accumulating.
#if defined(__FreeBSD__) || defined(__APPLE__)
signal(SIGCHLD, SIG_IGN);
#else
signal(SIGCLD, SIG_IGN);
#endif
// install signal handler for SIGSEGV, so that we can attempt
// clean shutdown
signal(SIGSEGV, &SignalHandler);
signal(SIGTRAP, &SignalHandler);
}
//-----------------------------------------------------------------------------
void Platform::postQuitMessage(const S32 in_quitVal)
{
// if we have a window send a quit event, otherwise just force shutdown
#if 0
if (x86UNIXState->windowCreated())
{
CheckExitCode(in_quitVal);
SendQuitEvent();
}
else
#endif
{
forceShutdown(in_quitVal);
}
}
//-----------------------------------------------------------------------------
void Platform::debugBreak()
{
// in windows, "Calling DebugBreak causes the program to display
// a dialog box as if it had crashed." So we segfault.
Con::errorf(ConsoleLogEntry::General,
"Platform::debugBreak: triggering SIGSEGV for core dump");
//kill(getpid(), SIGSEGV);
// On Linux, the mouse cursor will remain trapped when the SIGTRAP below triggers so we ensure the mouse
// locked state is disabled prior to dropping to debug
PlatformWindow* firstWindow = WindowManager->getFirstWindow();
if (firstWindow)
{
firstWindow->setMouseLocked(false);
}
kill(getpid(), SIGTRAP);
}
//-----------------------------------------------------------------------------
void Platform::forceShutdown(S32 returnValue)
{
#if 0
// if a dedicated server is running, turn it off
if (x86UNIXState->isDedicated() && Game->isRunning())
Game->setRunning(false);
else
#endif
ImmediateShutdown(returnValue);
}
//-----------------------------------------------------------------------------
void Platform::outputDebugString(const char *string, ...)
{
char buffer[2048];
va_list args;
va_start( args, string );
dVsprintf( buffer, sizeof(buffer), string, args );
va_end( args );
U32 length = dStrlen(buffer);
if( length == (sizeof(buffer) - 1 ) )
length--;
buffer[length++] = '\n';
buffer[length] = '\0';
fwrite(buffer, sizeof(char), length, stderr);
}
//-----------------------------------------------------------------------------
// testing function
//DefineEngineFunction(debug_debugbreak, void, () , , "debug_debugbreak();");
//-----------------------------------------------------------------------------
void Platform::restartInstance()
{
/*
if (Game->isRunning() )
{
//Con::errorf( "Error restarting Instance. Game is Still running!");
return;
}
char cmd[2048];
sprintf(cmd, "%s &", x86UNIXState->getExePathName());
system(cmd);
*/
exit(0);
}
#endif

View file

@ -0,0 +1,261 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "math/mPoint2.h"
#include "platformX86UNIX/platformX86UNIX.h"
//#include "platformX86UNIX/platformGL.h"
#include "core/strings/stringFunctions.h"
#define Display int
#define Window int
#define Screen int
#include <libgen.h> // for basename
typedef void (*LockFunc_t)(void);
class DisplayPtrManager;
class x86UNIXPlatformState
{
friend class DisplayPtrManager;
private:
Point2I mDesktopSize;
Point2I mWindowSize;
S32 mDesktopBpp;
Display *mDisplay;
Window mCurrentWindow;
Screen *mScreenPointer;
int mScreenNumber;
char mWindowName[40];
char mExePathName[4096];
char mExeName[40];
bool mWindowCreated;
bool mWindowActive;
bool mWindowLocked;
bool mXWindowsRunning;
bool mDedicated;
bool mCDAudioEnabled;
bool mDSleep;
bool mUseRedirect;
// Access to the display* needs to be controlled because the SDL event
// loop runs in a separate thread. If you need the display pointer,
// use the DisplayPtrManager class. See the clipboard functions in
// x86unixinput.cc for an example.
//Display *getDisplayPointer() { return mDisplay; }
public:
U32 currentTime;
void setDisplayPointer( Display *displayPointer ) { mDisplay = displayPointer; }
Display* getDisplayPointer() { return mDisplay; }
void setScreenNumber( int newNumber ) { mScreenNumber = newNumber; }
int getScreenNumber() { return mScreenNumber; }
void setScreenPointer( Screen *newScreenPointer )
{ mScreenPointer = newScreenPointer; }
Screen * getScreenPointer() { return mScreenPointer; }
// for compatibility, convert 24 bpp to 32
void setDesktopBpp( S32 bpp )
{
if (bpp == 24)
mDesktopBpp = 32;
else
mDesktopBpp = bpp;
}
S32 getDesktopBpp() { return mDesktopBpp; }
void setDesktopSize( S32 horizontal, S32 vertical )
{ mDesktopSize.set( horizontal, vertical ); }
Point2I getDesktopSize() { return mDesktopSize; }
void setWindow( Window newWindow ) { mCurrentWindow = newWindow; }
Window getWindow() { return mCurrentWindow; }
void setWindowSize (S32 horizontal, S32 vertical )
{ mWindowSize.set ( horizontal, vertical ); }
void setWindowSize( Point2I size ) { mWindowSize = size; }
Point2I& getWindowSize() { return ( mWindowSize ); }
void setWindowName (const char * windowName)
{
if (windowName == NULL)
dStrncpy( mWindowName, "", sizeof( mWindowName ));
else
dStrncpy( mWindowName, windowName, sizeof( mWindowName ) );
}
const char * getWindowName() { return mWindowName; }
void setExePathName(const char* exePathName)
{
if (exePathName == NULL)
dStrncpy(mExePathName, "", sizeof(mExePathName));
else
dStrncpy(mExePathName, exePathName, sizeof(mExePathName));
// set the base exe name field
char tempBuf[2048];
dStrncpy(tempBuf, mExePathName, 2048);
dStrncpy(mExeName, basename(tempBuf), sizeof(mExeName));
}
const char * getExePathName() { return mExePathName; }
const char * getExeName() { return mExeName; }
bool windowCreated() { return mWindowCreated; }
bool windowActive() { return mWindowActive; }
bool windowLocked() { return mWindowLocked; }
void setWindowCreated(bool windowCreated)
{ mWindowCreated = windowCreated; }
void setWindowActive(bool windowActive)
{ mWindowActive = windowActive; }
void setWindowLocked(bool windowLocked)
{ mWindowLocked = windowLocked; }
bool isXWindowsRunning() { return mXWindowsRunning; }
void setXWindowsRunning(bool running) { mXWindowsRunning = running; }
bool isDedicated() { return mDedicated; }
void setDedicated(bool dedicated) { mDedicated = dedicated; }
bool getCDAudioEnabled() { return mCDAudioEnabled; }
void setCDAudioEnabled(bool enabled) { mCDAudioEnabled = enabled; }
bool getDSleep() { return mDSleep; }
void setDSleep(bool enabled) { mDSleep = enabled; }
bool getUseRedirect() { return mUseRedirect; }
void setUseRedirect(bool enabled) { mUseRedirect = enabled; }
x86UNIXPlatformState()
{
currentTime = 0;
mDesktopBpp = 16;
mDesktopSize.set( 0, 0 );
mWindowSize.set( 800, 600 );
setWindowName("Torque");
setExePathName(NULL);
mWindowCreated = mWindowActive = mWindowLocked = false;
mXWindowsRunning = false;
mDedicated = false;
mCDAudioEnabled = false;
mDSleep = false;
#ifdef USE_FILE_REDIRECT
mUseRedirect = true;
#else
mUseRedirect = false;
#endif
}
};
extern x86UNIXPlatformState * x86UNIXState;
class DisplayPtrManager
{
// static interface
private:
static bool sgDisplayLocked;
static LockFunc_t sgLockFunc;
static LockFunc_t sgUnlockFunc;
static bool lockDisplay()
{
if (!sgDisplayLocked && sgLockFunc)
{
sgLockFunc();
sgDisplayLocked = true;
return true;
}
else
return false;
}
static void unlockDisplay()
{
if (sgDisplayLocked && sgUnlockFunc)
{
sgUnlockFunc();
sgDisplayLocked = false;
}
}
//friend Display* x86UNIXPlatformState::getDisplayPointer();
public:
static void setDisplayLockFunction(LockFunc_t lockFunc)
{ sgLockFunc = lockFunc; }
static void setDisplayUnlockFunction(LockFunc_t unlockFunc)
{ sgUnlockFunc = unlockFunc; }
// nonstatic interface
private:
bool mAcquiredLock; // true if this instance acquired the display lock
// (multiple instances of DisplayPtrManager can coexist, but only
// the first to access the display pointer will be responsible for
// acquiring and releasing the lock)
bool mOpenedDisplay; // true if this instance created a display pointer
// because the one in platform state was null.
Display* mDisplay;
private:
Display* openDisplay()
{
return mDisplay;
}
void closeDisplay()
{
if (mOpenedDisplay)
{
}
}
public:
DisplayPtrManager()
{
mAcquiredLock = false;
mOpenedDisplay = false;
mDisplay = NULL;
}
~DisplayPtrManager()
{
if (mAcquiredLock)
{
DisplayPtrManager::unlockDisplay();
mAcquiredLock = false;
}
closeDisplay();
}
Display* getDisplayPointer()
{
Display* display = x86UNIXState->getDisplayPointer();
if (display == NULL)
return openDisplay();
mAcquiredLock = DisplayPtrManager::lockDisplay();
return display;
}
};

View file

@ -0,0 +1,75 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _X86UNIXSTDCONSOLE_H_
#define _X86UNIXSTDCONSOLE_H_
#define MAX_CMDS 10
#ifndef _CONSOLE_H_
#include "console/console.h"
#endif
#ifndef _EVENT_H_
#include "platform/event.h"
#endif
#include <termios.h>
class StdConsole
{
bool stdConsoleEnabled;
bool stdConsoleInputEnabled;
// true if we're running in the background
bool inBackground;
int stdOut;
int stdIn;
int stdErr;
char inbuf[512];
S32 inpos;
bool lineOutput;
char curTabComplete[512];
S32 tabCompleteStart;
char rgCmds[MAX_CMDS][512];
S32 iCmdIndex;
// this holds the original terminal state
// before we messed with it
struct termios *originalTermState;
void printf(const char *s, ...);
public:
StdConsole();
virtual ~StdConsole();
void process();
void enable(bool);
void enableInput(bool enabled);
void processConsoleLine(const char *consoleLine);
static void create();
static void destroy();
static bool isEnabled();
void resetTerminal();
};
extern StdConsole *stdConsole;
#endif

View file

@ -0,0 +1,70 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platformX86UNIX/platformX86UNIX.h"
#include "core/strings/stringFunctions.h"
#include <stdarg.h>
#include <ctype.h>
#include <stdlib.h>
const char *stristr(const char *szStringToBeSearched, const char *szSubstringToSearchFor)
{
const char *pPos = NULL;
char *szCopy1 = NULL;
char *szCopy2 = NULL;
// verify parameters
if ( szStringToBeSearched == NULL ||
szSubstringToSearchFor == NULL )
{
return szStringToBeSearched;
}
// empty substring - return input (consistent with strstr)
if (strlen(szSubstringToSearchFor) == 0 ) {
return szStringToBeSearched;
}
szCopy1 = dStrlwr(strdup(szStringToBeSearched));
szCopy2 = dStrlwr(strdup(szSubstringToSearchFor));
if ( szCopy1 == NULL || szCopy2 == NULL ) {
// another option is to raise an exception here
free((void*)szCopy1);
free((void*)szCopy2);
return NULL;
}
pPos = strstr((const char*)szCopy1, (const char*)szCopy2);
if ( pPos != NULL ) {
// map to the original string
pPos = szStringToBeSearched + (pPos - szCopy1);
}
free((void*)szCopy1);
free((void*)szCopy2);
return pPos;
} // stristr(...)

View file

@ -0,0 +1,163 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef __APPLE__
#include "platformX86UNIX/platformX86UNIX.h"
#include "platform/platformTimer.h"
#include "time.h"
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
static U32 sgCurrentTime = 0;
U32 x86UNIXGetTickCount();
//--------------------------------------
void Platform::getLocalTime(LocalTime &lt)
{
struct tm *systime;
time_t long_time;
time( &long_time ); // Get time as long integer.
systime = localtime( &long_time ); // Convert to local time.
lt.sec = systime->tm_sec;
lt.min = systime->tm_min;
lt.hour = systime->tm_hour;
lt.month = systime->tm_mon;
lt.monthday = systime->tm_mday;
lt.weekday = systime->tm_wday;
lt.year = systime->tm_year;
lt.yearday = systime->tm_yday;
lt.isdst = systime->tm_isdst;
}
String Platform::localTimeToString( const LocalTime &lt )
{
tm systime;
systime.tm_sec = lt.sec;
systime.tm_min = lt.min;
systime.tm_hour = lt.hour;
systime.tm_mon = lt.month;
systime.tm_mday = lt.monthday;
systime.tm_wday = lt.weekday;
systime.tm_year = lt.year;
systime.tm_yday = lt.yearday;
systime.tm_isdst = lt.isdst;
return asctime( &systime );
}
U32 Platform::getTime()
{
time_t long_time;
time( &long_time );
return long_time;
}
U32 Platform::getRealMilliseconds()
{
// struct rusage usageStats;
// getrusage(RUSAGE_SELF, &usageStats);
// return usageStats.ru_utime.tv_usec;
return x86UNIXGetTickCount();
}
U32 Platform::getVirtualMilliseconds()
{
return sgCurrentTime;
}
void Platform::advanceTime(U32 delta)
{
sgCurrentTime += delta;
}
void Platform::fileToLocalTime(const FileTime & ft, LocalTime * lt)
{
if(!lt)
return;
time_t long_time = ft;
struct tm systime;
/// Convert to local time, thread safe.
localtime_r( &long_time, &systime );
/// Fill the return struct
lt->sec = systime.tm_sec;
lt->min = systime.tm_min;
lt->hour = systime.tm_hour;
lt->month = systime.tm_mon;
lt->monthday = systime.tm_mday;
lt->weekday = systime.tm_wday;
lt->year = systime.tm_year;
lt->yearday = systime.tm_yday;
lt->isdst = systime.tm_isdst;
}
PlatformTimer *PlatformTimer::create()
{
return new DefaultPlatformTimer();
}
//------------------------------------------------------------------------------
//-------------------------------------- x86UNIX Implementation
//
//
static bool sg_initialized = false;
static U32 sg_secsOffset = 0;
//--------------------------------------
U32 x86UNIXGetTickCount()
{
// TODO: What happens when crossing a day boundary?
//
timeval t;
if (sg_initialized == false) {
sg_initialized = true;
gettimeofday(&t, NULL);
sg_secsOffset = t.tv_sec;
}
gettimeofday(&t, NULL);
U32 secs = t.tv_sec - sg_secsOffset;
U32 uSecs = t.tv_usec;
// Make granularity 1 ms
return (secs * 1000) + (uSecs / 1000);
}
void Platform::sleep(U32 ms)
{
// note: this will overflow if you want to sleep for more than 49 days. just so ye know.
usleep( ms * 1000 );
}
#endif

View file

@ -0,0 +1,284 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <sys/utsname.h>
// for UnixCommandExecutor
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdlib.h>
#include "platformX86UNIX/platformX86UNIX.h"
#include "platformPOSIX/POSIXUtils.h"
UnixUtils *UUtils = NULL;
UnixUtils utils;
UnixUtils::UnixUtils()
{
UUtils = this;
mUnameInfo = (struct utsname*)dRealMalloc(sizeof(struct utsname));;
if (uname(mUnameInfo) == -1)
{
// oh well
dRealFree(mUnameInfo);
mUnameInfo = NULL;
}
}
UnixUtils::~UnixUtils()
{
if (mUnameInfo != NULL)
{
dRealFree(mUnameInfo);
mUnameInfo = NULL;
}
}
const char* UnixUtils::getOSName()
{
if (mUnameInfo == NULL)
return "";
return mUnameInfo->sysname;
}
bool UnixUtils::inBackground()
{
int terminalGroupId = tcgetpgrp(fileno(stdin));
int myPid = getpid();
if (terminalGroupId != myPid)
return true;
else
return false;
}
//-----------------------------------------------------------------------------
// UnixCommandExecutor
void UnixCommandExecutor::clearFields()
{
mRet = -1;
mStdoutSave = -1;
mStderrSave = -1;
mPipeFiledes[0] = -1;
mPipeFiledes[1] = -1;
mChildPID = -1;
mBytesRead = 0;
mStdoutClosed = false;
mStderrClosed = false;
mChildExited = false;
}
UnixCommandExecutor::UnixCommandExecutor()
{
clearFields();
}
UnixCommandExecutor::~UnixCommandExecutor()
{
cleanup();
}
int UnixCommandExecutor::exec(char* args[],
char* stdoutCapture, int stdoutCaptureSize)
{
// check for shitty parameters
if (args == NULL || stdoutCapture == NULL ||
stdoutCaptureSize <= 0)
return -666;
// we're going to be redirecting stdout, so save it so that we can
// restore it
mRet = dup(1);
if (mRet == -1)
{
cleanup();
return mRet;
}
mStdoutSave = mRet;
// save stderr
mRet = dup(2);
if (mRet == -1)
{
cleanup();
return mRet;
}
mStderrSave = mRet;
// we'll need some pipe action for communicating with subprocess
mRet = pipe(mPipeFiledes);
if (mRet == -1)
{
cleanup();
return mRet;
}
// close stdout
mRet = close(1);
if (mRet == -1)
{
cleanup();
return mRet;
}
mStdoutClosed = true;
// stderr just gets closed and the output discarded
mRet = close(2);
if (mRet == -1)
{
cleanup();
return mRet;
}
mStderrClosed = true;
// dup the pipe output into stdout
mRet = dup2(mPipeFiledes[1], 1);
if (mRet == -1)
{
cleanup();
return mRet;
}
// fork
mRet = fork();
if (mRet == -1)
{
cleanup();
return mRet;
}
if (mRet == 0)
{
// child process
//close(mPipeFiledes[0]);
mRet = execvp(args[0], args);
// if exec returns, some bad shit went down, so just
// get outta here
exit(mRet);
}
// parent process
mChildPID = mRet;
// need to suck in data from pipe while child is running,
// otherwise child will eventually block on write and we'll
// wait forever
memset(stdoutCapture, 0, stdoutCaptureSize);
// set input to be non blocking so that we don't block on read
mRet = fcntl(mPipeFiledes[0], F_SETFL, O_NONBLOCK);
if (mRet == -1)
{
cleanup();
return mRet;
}
// check to see if child has exited
mRet = waitpid(mChildPID, NULL, WNOHANG);
while (mRet == 0)
{
// not exited, read some data
mRet = read(mPipeFiledes[0], stdoutCapture + mBytesRead,
stdoutCaptureSize - mBytesRead);
// any error that isn't EAGAIN means we should exit
if (mRet == -1 && errno != EAGAIN)
{
cleanup();
return mRet;
}
// if the read was ok, increment bytes read
if (mRet != -1)
mBytesRead += mRet;
// check again for child exit
mRet = waitpid(mChildPID, NULL, WNOHANG);
}
// check for error from waitpid
if (mRet == -1 && errno != ECHILD)
{
cleanup();
return mRet;
}
// if we get here, the child exited
mChildExited = true;
// read final bit of data
mRet = read(mPipeFiledes[0], stdoutCapture + mBytesRead,
stdoutCaptureSize - mBytesRead);
if (mRet == -1 && errno != EAGAIN)
{
cleanup();
return mRet;
}
if (mRet != -1)
mBytesRead += mRet;
// done...cleanup
cleanup();
return 0;
}
void UnixCommandExecutor::cleanup()
{
// if child spawned and not exited, wait
if (mChildPID > 0 && !mChildExited)
waitpid(mChildPID, NULL, 0);
// close pipe descriptors
if (mPipeFiledes[0] != -1)
close(mPipeFiledes[0]);
if (mPipeFiledes[1] != -1)
close(mPipeFiledes[1]);
// if stdout is redirected, restore it
if (mStdoutClosed && mStdoutSave != -1)
dup2(mStdoutSave, 1);
// close stdout save descriptor
if (mStdoutSave != -1)
close(mStdoutSave);
// if stderr is redirected, restore it
if (mStderrClosed && mStderrSave != -1)
dup2(mStderrSave, 2);
// close stderr save descriptor
if (mStderrSave != -1)
close(mStderrSave);
clearFields();
}
/* Usage:
UnixCommandExecutor exec;
char* args[] = { "ps", "-aux", NULL };
char data[20000];
int ret = exec.exec(args, data, sizeof(data));
printf("%s", data);
*/

View file

@ -0,0 +1,90 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _X86UNIXUTILS_H_
#define _X86UNIXUTILS_H_
struct utsname;
class UnixUtils
{
public:
UnixUtils();
virtual ~UnixUtils();
/**
Returns true if we're running in the background, false otherwise.
There's no "standard" way to determine this in unix, but
modern job control unices should support the method described
here:
http://www.faqs.org/faqs/unix-faq/faq/part3/
(question 3.7)
*/
bool inBackground();
/**
Returns the name of the OS, as reported by uname.
*/
const char* getOSName();
private:
struct utsname* mUnameInfo;
};
extern UnixUtils *UUtils;
// utility class for running a unix command and capturing its output
class UnixCommandExecutor
{
private:
int mRet;
int mStdoutSave;
int mStderrSave;
int mPipeFiledes[2];
int mChildPID;
int mBytesRead;
bool mStdoutClosed;
bool mStderrClosed;
bool mChildExited;
void clearFields();
void cleanup();
public:
UnixCommandExecutor();
~UnixCommandExecutor();
// Runs the specified command.
// - args is a null terminated list of the command and its arguments,
// e.g: "ps", "-aux", NULL
// - stdoutCapture is the buffer where stdout data will be stored
// - stdoutCaptureSize is the size of the buffer
// None of these parameters may be null. stdoutCaptureSize must be > 0
//
// returns -2 if the parameters are bad. returns -1 if some other
// error occurs, check errno for the exact error.
int exec(char* args[], char* stdoutCapture, int stdoutCaptureSize);
};
#endif