1
0
forked from 0ad/0ad

# Changed handling of command-line arguments.

* Added CmdLineArgs, which does the parsing then lets various pieces of
code check for whatever arguments they want.
 * Made Atlas exit out of main() cleanly, instead of calling exit()
itself.
 * Disabled the global exception-catching in unit tests, via a
entry_noSEH, so it doesn't make debugging harder.
 * Added nice printing of CStr in unit test failure messages, and added
comparison of vector vs constant array.

This was SVN commit r4688.
This commit is contained in:
Ykkrosh 2006-12-09 14:39:52 +00:00
parent 0e1eb62687
commit cbafd43eea
19 changed files with 398 additions and 176 deletions

View File

@ -179,7 +179,7 @@ function package_setup_pch(pch_dir, header, source)
})
end
for i,v in project.configs do
tinsert(package.config[v].defines, { "USING_PCH" })
tinsert(package.config[v].defines, "USING_PCH")
end
end
end
@ -732,7 +732,7 @@ function setup_tests()
package_add_extern_libs(used_extern_libs)
if OS == "windows" then
-- required for win.cpp's init mechanism
tinsert(package.linkoptions, "/ENTRY:entry")
tinsert(package.linkoptions, "/ENTRY:entry_noSEH")
-- from "lowlevel" static lib; must be added here to be linked in
tinsert(package.files, source_root.."lib/sysdep/win/error_dialog.rc")

View File

@ -190,8 +190,38 @@ extern bool self_test_active;
#include <cxxtest/StdValueTraits.h>
#include <cxxtest/TestSuite.h>
// Perform nice printing of CStr, based on std::string
#include "ps/CStr.h"
namespace CxxTest
{
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const CStr8> : public ValueTraits<const CXXTEST_STD(string)>
{
public:
ValueTraits( const CStr8 &s ) : ValueTraits<const CXXTEST_STD(string)>( s.c_str() ) {}
};
CXXTEST_COPY_CONST_TRAITS( CStr8 );
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const CStrW> : public ValueTraits<const CXXTEST_STD(wstring)>
{
public:
ValueTraits( const CStrW &s ) : ValueTraits<const CXXTEST_STD(wstring)>( s.c_str() ) {}
};
CXXTEST_COPY_CONST_TRAITS( CStrW );
}
#define TS_ASSERT_OK(expr) TS_ASSERT_EQUALS((expr), INFO::OK)
#define TS_ASSERT_STR_EQUALS(str1, str2) TS_ASSERT_EQUALS(std::string(str1), std::string(str2))
#define TS_ASSERT_WSTR_EQUALS(str1, str2) TS_ASSERT_EQUALS(std::wstring(str1), std::wstring(str2))
template <typename T>
std::vector<T> ts_make_vector(T* start, size_t size_bytes)
{
return std::vector<T>(start, start+(size_bytes/sizeof(T)));
}
#define TS_ASSERT_VECTOR_EQUALS_ARRAY(vec1, array) TS_ASSERT_EQUALS(vec1, ts_make_vector((array), sizeof(array)))
#endif // #ifndef SELF_TEST_H__

View File

@ -365,3 +365,18 @@ int entry()
#endif
return SEH_wrapped_entry();
}
// Alternative entry point, for programs that don't want the SEH handler
// (e.g. unit tests, where it's better to let the debugger handle any errors)
int entry_noSEH()
{
int ret;
pre_libc_init();
#ifdef USE_WINMAIN
ret = WinMainCRTStartup();
#else
ret = mainCRTStartup();
#endif
return ret;
}

View File

@ -23,6 +23,7 @@ that of Atlas depending on commandline parameters.
#include "ps/GameSetup/GameSetup.h"
#include "ps/GameSetup/Atlas.h"
#include "ps/GameSetup/Config.h"
#include "ps/GameSetup/CmdLineArgs.h"
#include "ps/Loader.h"
#include "ps/CConsole.h"
#include "ps/Profile.h"
@ -365,32 +366,35 @@ void kill_mainloop()
int main(int argc, char* argv[])
{
// If you ever want to catch a particular allocation:
//_CrtSetBreakAlloc(7864);
//_CrtSetBreakAlloc(321);
// see discussion at declaration of win_pre_main_init.
#if OS_WIN
win_pre_main_init();
#endif
ATLAS_RunIfOnCmdLine(argc, argv);
{ // scope for args
Init(argc, argv, 0);
CmdLineArgs args(argc, argv);
bool ran_atlas = ATLAS_RunIfOnCmdLine(args);
// Atlas handles the whole init/shutdown/etc sequence by itself,
// so we skip all this and just exit if Atlas was run
if (! ran_atlas)
{
Init(args, 0);
MainControllerInit();
debug_filter_add("LOADER");
debug_filter_add("LOADER"); // TODO: remove this?
//trace_gen_random(5000);
//trace_write_to_file("../logs/trace.txt");
#if 0
trace_run("../logs/trace.txt");
#else
while(!quit)
Frame();
#endif
Shutdown(0);
MainControllerShutdown();
}
}
debug_printf("Shutdown complete, calling exit() now\n");

View File

@ -2,6 +2,7 @@
#include "lib/posix.h"
#include "lib/lib.h"
#include "ps/GameSetup/CmdLineArgs.h"
#include "Atlas.h"
//----------------------------------------------------------------------------
@ -74,7 +75,7 @@ enum AtlasRunFlags
};
// starts the Atlas UI.
static void ATLAS_Run(int argc, char* argv[], int flags = 0)
static void ATLAS_Run(const CmdLineArgs& args, int flags = 0)
{
// first check if we can run at all
if(!ATLAS_IsAvailable())
@ -87,8 +88,8 @@ static void ATLAS_Run(int argc, char* argv[], int flags = 0)
}
// TODO (make nicer)
extern bool BeginAtlas(int argc, char* argv[], void* dll);
if (!BeginAtlas(argc, argv, atlas_so_handle))
extern bool BeginAtlas(const CmdLineArgs& args, void* dll);
if (!BeginAtlas(args, atlas_so_handle))
{
debug_warn("Atlas loading failed");
return;
@ -103,21 +104,15 @@ static void ATLAS_Run(int argc, char* argv[], int flags = 0)
// notes:
// - GUI init still runs, but some GUI setup will be skipped since
// ATLAS_IsRunning() will return true.
// - could be merged into CFG_ParseCommandLineArgs, because that appears
// to be called early enough. it's not really worth it because this
// code is quite simple and we thus avoid startup order dependency.
void ATLAS_RunIfOnCmdLine(int argc, char* argv[])
bool ATLAS_RunIfOnCmdLine(const CmdLineArgs& args)
{
for(int i = 1; i < argc; i++) // skip program name argument
if (args.Has("editor"))
{
if(!strcmp(argv[i], "-editor"))
{
// don't bother removing this param (unnecessary)
ATLAS_Run(args, ATLAS_NO_GUI);
return true;
}
ATLAS_Run(argc, argv, ATLAS_NO_GUI);
break;
}
}
return false;
}

View File

@ -1,3 +1,5 @@
class CmdLineArgs;
// free reference to Atlas UI SO (avoids resource leak report)
extern void ATLAS_Shutdown();
@ -5,4 +7,4 @@ extern void ATLAS_Shutdown();
// this is the alternative to starting the main menu and clicking on
// the editor button; it is much faster because it's called during early
// init and therefore skips GUI setup.
extern void ATLAS_RunIfOnCmdLine(int argc, char* argv[]);
extern bool ATLAS_RunIfOnCmdLine(const CmdLineArgs& args);

View File

@ -0,0 +1,74 @@
#include "precompiled.h"
#include "CmdLineArgs.h"
CmdLineArgs::CmdLineArgs(int argc, char* argv[])
{
if (argc >= 1)
m_Arg0 = argv[0];
for (int i = 1; i < argc; ++i)
{
// Only accept arguments that start with '-'
if (argv[i][0] != '-')
continue;
CStr name, value;
// Check for "-arg=value"
const char* eq = strchr(argv[i], '=');
if (eq)
{
name = CStr(argv[i]+1, eq-argv[i]-1);
value = CStr(eq+1);
}
else
{
name = CStr(argv[i]+1);
}
m_Args.push_back(make_pair(name, value));
}
}
template<typename T>
struct first_equals
{
T x;
first_equals(const T& x) : x(x) {}
template<typename S> bool operator()(const S& v) { return v.first == x; }
};
bool CmdLineArgs::Has(const char* name) const
{
return find_if(m_Args.begin(), m_Args.end(), first_equals<CStr>(name)) != m_Args.end();
}
CStr CmdLineArgs::Get(const char* name) const
{
ArgsT::const_iterator it = find_if(m_Args.begin(), m_Args.end(), first_equals<CStr>(name));
if (it != m_Args.end())
return it->second;
else
return "";
}
std::vector<CStr> CmdLineArgs::GetMultiple(const char* name) const
{
std::vector<CStr> values;
ArgsT::const_iterator it = m_Args.begin();
while (1)
{
it = find_if(it, m_Args.end(), first_equals<CStr>(name));
if (it == m_Args.end())
break;
values.push_back(it->second);
++it; // start searching from the next one in the next iteration
}
return values;
}
CStr CmdLineArgs::GetArg0() const
{
return m_Arg0;
}

View File

@ -0,0 +1,52 @@
#ifndef CMDLINEARGS_H__
#define CMDLINEARGS_H__
#include "ps/CStr.h"
class CmdLineArgs
{
public:
CmdLineArgs() {}
/**
* Parse the command-line options, for future processing.
* All arguments are required to be of the form <tt>-name</tt> or
* <tt>-name=value</tt> - anything else is ignored.
*
* @param argc size of argv array
* @param argv array of arguments; argv[0] should be the program's name
*/
CmdLineArgs(int argc, char* argv[]);
/**
* Test whether the given name was specified, as either <tt>-name</tt> or
* <tt>-name=value</tt>
*/
bool Has(const char* name) const;
/**
* Get the value of the named parameter. If it was not specified, returns
* the empty string. If it was specified multiple times, returns the value
* from the first occurrence.
*/
CStr Get(const char* name) const;
/**
* Get all the values given to the named parameter. Returns values in the
* same order as they were given in argv.
*/
std::vector<CStr> GetMultiple(const char* name) const;
/**
* Get the value of argv[0], which is typically meant to be the name/path of
* the program (but the actual value is up to whoever executed the program).
*/
CStr GetArg0() const;
private:
typedef std::vector<std::pair<CStr, CStr> > ArgsT;
ArgsT m_Args;
CStr m_Arg0;
};
#endif // CMDLINEARGS_H__

View File

@ -3,6 +3,7 @@
#include "ps/CLogger.h"
#include "ps/ConfigDB.h"
#include "ps/CConsole.h"
#include "ps/GameSetup/CmdLineArgs.h"
#include "lib/timer.h"
#include "lib/res/sound/snd_mgr.h"
#include "lib/res/file/trace.h"
@ -89,71 +90,55 @@ static void LoadGlobals()
}
static void ParseCommandLineArgs(int argc, char* argv[])
static void ProcessCommandLineArgs(const CmdLineArgs& args)
{
for(int i = 1; i < argc; i++)
{
// this arg isn't an option; skip
if(argv[i][0] != '-')
continue;
// TODO: all these options (and the ones processed elsewhere) should
// be documented somewhere for users.
char* name = argv[i]+1; // no leading '-'
if (args.Has("autostart"))
g_AutostartMap = args.Get("autostart");
// switch first letter of option name
switch(argv[i][1])
if (args.Has("buildarchive"))
{
case 'a':
if(strncmp(name, "autostart=", 10) == 0)
g_AutostartMap = argv[i]+11;
break;
case 'b':
if(!strcmp(name, "buildarchive"))
// note: VFS init is sure to have been completed by now
// (since CONFIG_Init reads from file); therefore,
// it is safe to call this from here directly.
vfs_opt_rebuild_main_archive("mods/official/official1.zip", "../logs/trace.txt");
break;
case 'c':
if(strcmp(name, "conf") == 0)
}
// Handle "-conf=key:value" (potentially multiple times)
std::vector<CStr> conf = args.GetMultiple("conf");
for (size_t i = 0; i < conf.size(); ++i)
{
if(argc-i >= 1) // at least one arg left
CStr name_value = conf[i];
if (name_value.Find(':') != -1)
{
i++;
char* arg = argv[i];
char* equ = strchr(arg, '=');
if(equ)
{
*equ = 0;
g_ConfigDB.CreateValue(CFG_COMMAND, arg)
->m_String = (equ+1);
CStr name = name_value.BeforeFirst(":");
CStr value = name_value.AfterFirst(":");
g_ConfigDB.CreateValue(CFG_COMMAND, name)->m_String = value;
}
}
}
break;
case 'e':
if(strncmp(name, "entgraph", 8) == 0)
if (args.Has("entgraph"))
g_EntGraph = true;
break;
case 'f':
if(strncmp(name, "fixedframe", 10) == 0)
if (args.Has("fixedframe"))
g_FixedFrameTiming = true;
break;
case 'g':
if(strncmp(name, "g=", 2) == 0)
if (args.Has("g"))
{
g_Gamma = (float)atof(argv[i] + 3);
g_Gamma = (float)atof(args.Get("g"));
if (g_Gamma == 0.0f)
g_Gamma = 1.0f;
}
break;
case 'l':
if(strncmp(name, "listfiles", 9) == 0)
if (args.Has("listfiles"))
trace_enable(true);
break;
case 'm':
if(strncmp(name, "mod=", 4) == 0)
std::vector<CStr> mods = args.GetMultiple("mod");
for (size_t i = 0; i < mods.size(); ++i)
{
const char* mod_name = name+4;
const char* mod_name = mods[i];
char path[PATH_MAX];
snprintf(path, ARRAY_SIZE(path), "mods/%s", mod_name);
path[PATH_MAX-1] = '\0';
@ -168,41 +153,31 @@ static void ParseCommandLineArgs(int argc, char* argv[])
uint pri = 1;
(void)vfs_mount("", path, VFS_MOUNT_RECURSIVE|VFS_MOUNT_ARCHIVES|VFS_MOUNT_WATCH, pri);
}
break;
case 'n':
if(strncmp(name, "novbo", 5) == 0)
if (args.Has("novbo"))
g_ConfigDB.CreateValue(CFG_COMMAND, "novbo")->m_String="true";
break;
case 'p':
if(strncmp(name, "profile=", 8) == 0)
g_ConfigDB.CreateValue(CFG_COMMAND, "profile")->m_String = argv[i]+9;
break;
case 'q':
if(strncmp(name, "quickstart", 10) == 0)
if (args.Has("profile"))
g_ConfigDB.CreateValue(CFG_COMMAND, "profile")->m_String = args.Get("profile");
if (args.Has("quickstart"))
g_Quickstart = true;
break;
case 's':
if(strncmp(name, "shadows", 7) == 0)
if (args.Has("shadows"))
g_ConfigDB.CreateValue(CFG_COMMAND, "shadows")->m_String = "true";
break;
case 'v':
if(strncmp(name, "vsync", 5) == 0)
if (args.Has("vsync"))
g_ConfigDB.CreateValue(CFG_COMMAND, "vsync")->m_String = "true";
break;
case 'x':
if(strncmp(name, "xres=", 5) == 0)
g_ConfigDB.CreateValue(CFG_COMMAND, "xres")->m_String=argv[i]+6;
break;
case 'y':
if(strncmp(name, "yres=", 5) == 0)
g_ConfigDB.CreateValue(CFG_COMMAND, "yres")->m_String=argv[i]+6;
break;
} // switch
}
if (args.Has("xres"))
g_ConfigDB.CreateValue(CFG_COMMAND, "xres")->m_String = args.Get("xres");
if (args.Has("yres"))
g_ConfigDB.CreateValue(CFG_COMMAND, "yres")->m_String = args.Get("yres");
}
void CONFIG_Init(int argc, char* argv[])
void CONFIG_Init(const CmdLineArgs& args)
{
TIMER("CONFIG_Init");
MICROLOG(L"init config");
@ -215,7 +190,7 @@ void CONFIG_Init(int argc, char* argv[])
g_ConfigDB.SetConfigFile(CFG_MOD, true, "config/mod.cfg");
// No point in reloading mod.cfg here - we haven't mounted mods yet
ParseCommandLineArgs(argc, argv);
ProcessCommandLineArgs(args);
// Collect information from system.cfg, the profile file,
// and any command-line overrides to fill in the globals.

View File

@ -28,5 +28,5 @@ extern CStr g_AutostartMap;
extern CStr g_CursorName;
extern void CONFIG_Init(int argc, char* argv[]);
class CmdLineArgs;
extern void CONFIG_Init(const CmdLineArgs& args);

View File

@ -88,9 +88,10 @@
#include "network/Server.h"
#include "network/Client.h"
#include "Atlas.h"
#include "GameSetup.h"
#include "Config.h"
#include "ps/GameSetup/Atlas.h"
#include "ps/GameSetup/GameSetup.h"
#include "ps/GameSetup/Config.h"
#include "ps/GameSetup/CmdLineArgs.h"
ERROR_GROUP(System);
ERROR_TYPE(System, SDLInitFailed);
@ -875,7 +876,7 @@ void Shutdown(uint flags)
}
void Init(int argc, char* argv[], uint flags)
void Init(const CmdLineArgs& args, uint flags)
{
const bool setup_vmode = (flags & INIT_HAVE_VMODE) == 0;
@ -892,11 +893,7 @@ void Init(int argc, char* argv[], uint flags)
// and will mess up the error reporting if anything
// crashes before the working directory is set.
MICROLOG(L"init vfs");
const char* argv0 = argc? argv[0] : NULL;
// ScEd doesn't have a main(argc, argv), and so it has no argv. In that
// case, just pass NULL to InitVfs, which will work out the current
// directory for itself.
InitVfs(argv0);
InitVfs(args.GetArg0().c_str());
// This must come after VFS init, which sets the current directory
// (required for finding our output log files).
@ -938,7 +935,7 @@ void Init(int argc, char* argv[], uint flags)
InitScripting(); // before GUI
// g_ConfigDB, command line args, globals
CONFIG_Init(argc, argv);
CONFIG_Init(args);
// setup_gui must be set after CONFIG_Init, so command-line parameters can disable it
const bool setup_gui = ((flags & INIT_NO_GUI) == 0 && g_AutostartMap.Length() == 0);

View File

@ -34,5 +34,6 @@ enum InitFlags
INIT_NO_SIM = 4,
};
extern void Init(int argc, char* argv[], uint flags);
class CmdLineArgs;
extern void Init(const CmdLineArgs& args, uint flags);
extern void Shutdown(uint flags);

View File

@ -0,0 +1,69 @@
#include "lib/self_test.h"
#include "ps/GameSetup/CmdLineArgs.h"
class TestCmdLineArgs : public CxxTest::TestSuite
{
public:
void test_has()
{
char* argv[] = { "program", "-test2" };
CmdLineArgs c(ARRAY_SIZE(argv), argv);
TS_ASSERT(!c.Has("test1"));
TS_ASSERT(c.Has("test2"));
TS_ASSERT(!c.Has("test3"));
TS_ASSERT(!c.Has(""));
}
void test_get()
{
char* argv[] = { "program", "-test1=", "-test2=x", "-test3=-y=y-", "-=z" };
CmdLineArgs c(ARRAY_SIZE(argv), argv);
TS_ASSERT_STR_EQUALS(c.Get("test0"), "");
TS_ASSERT_STR_EQUALS(c.Get("test1"), "");
TS_ASSERT_STR_EQUALS(c.Get("test2"), "x");
TS_ASSERT_STR_EQUALS(c.Get("test3"), "-y=y-");
TS_ASSERT_STR_EQUALS(c.Get(""), "z");
}
void test_multiple()
{
char* argv[] = { "program", "-test1=one", "-test1=two", "-test2=none", "-test1=three" };
CmdLineArgs c(ARRAY_SIZE(argv), argv);
TS_ASSERT_STR_EQUALS(c.Get("test1"), "one");
TS_ASSERT_STR_EQUALS(c.Get("test2"), "none");
std::vector<CStr> test1 = c.GetMultiple("test1");
CStr expected1[] = { "one", "two", "three" };
TS_ASSERT_VECTOR_EQUALS_ARRAY(test1, expected1);
std::vector<CStr> test2 = c.GetMultiple("test2");
CStr expected2[] = { "none" };
TS_ASSERT_VECTOR_EQUALS_ARRAY(test2, expected2);
std::vector<CStr> test3 = c.GetMultiple("test3");
TS_ASSERT_EQUALS(test3.size(), (size_t)0);
}
void test_get_invalid()
{
char* argv[] = { "-test1", "-test2", "test3", " -test4" };
CmdLineArgs c(ARRAY_SIZE(argv), argv);
TS_ASSERT(!c.Has("test1"));
TS_ASSERT(c.Has("test2"));
TS_ASSERT(!c.Has("test3"));
TS_ASSERT(!c.Has("test4"));
}
void test_arg0()
{
char* argv[] = { "program" };
CmdLineArgs c(ARRAY_SIZE(argv), argv);
TS_ASSERT_STR_EQUALS(c.GetArg0(), "program");
CmdLineArgs c2(0, NULL);
TS_ASSERT_STR_EQUALS(c2.GetArg0(), "");
}
};

View File

@ -1,5 +1,7 @@
#include "lib/self_test.h"
#include "ps/CStr.h"
class TestTest : public CxxTest::TestSuite
{
public:
@ -27,4 +29,13 @@ public:
TS_ASSERT_STR_EQUALS(TS_AS_STRING((ssize_t)0), "0");
TS_ASSERT_STR_EQUALS(TS_AS_STRING((unsigned int)0), "0");
}
void test_cstr()
{
TS_ASSERT_STR_EQUALS(TS_AS_STRING(CStr("test")), "\"test\"");
TS_ASSERT_STR_EQUALS(TS_AS_STRING(std::string("test")), "\"test\"");
TS_ASSERT_STR_EQUALS(TS_AS_STRING(CStrW(L"test")), "L\"test\"");
TS_ASSERT_STR_EQUALS(TS_AS_STRING(std::wstring(L"test")), "L\"test\"");
}
};

View File

@ -332,7 +332,7 @@ void ActorEditor::OnCreateEntity(wxCommandEvent& WXUNUSED(event))
// The output should be an XML file like:
//
// <?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
// <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
// <Entity Parent="celt_csw_b">
// <Actor>units/celt_csw_a.xml</Actor>
// </Entity>
@ -391,7 +391,7 @@ void ActorEditor::OnCreateEntity(wxCommandEvent& WXUNUSED(event))
// Create the XML data to be written
// TODO: Native line endings
wxString xml =
_T("<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>\r\n")
_T("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n")
_T("\r\n")
_T("<Entity Parent=\"") + parentName + _T("\">\r\n")
_T("\t<Actor>") + actorFilename.GetFullPath(wxPATH_UNIX) + _T("</Actor>\r\n")

View File

@ -58,14 +58,11 @@ static void* LaunchWindow(void* data)
}
// Work out which Atlas window to launch, given the command-line arguments
static const wchar_t* FindWindowName(int argc, char* argv[])
static const wchar_t* FindWindowName(const CmdLineArgs& args)
{
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "-actorviewer") == 0)
if (args.Has("actorviewer"))
return L"ActorViewer";
}
else
return L"ScenarioEditor";
}
@ -77,7 +74,7 @@ static ErrorReaction AtlasDisplayError(const wchar_t* text, uint flags)
return ER_CONTINUE;
}
bool BeginAtlas(int argc, char* argv[], void* dll)
bool BeginAtlas(const CmdLineArgs& args, void* dll)
{
// Load required symbols from the DLL
#define GET(x) *(void**)&x = dlsym(dll, #x); debug_assert(x); if (! x) return false;
@ -100,7 +97,7 @@ bool BeginAtlas(int argc, char* argv[], void* dll)
RegisterHandlers();
// Create a new thread, and launch the Atlas window inside that thread
const wchar_t* windowName = FindWindowName(argc, argv);
const wchar_t* windowName = FindWindowName(args);
pthread_t uiThread;
pthread_create(&uiThread, NULL, LaunchWindow, reinterpret_cast<void*>(const_cast<wchar_t*>(windowName)));
@ -109,8 +106,7 @@ bool BeginAtlas(int argc, char* argv[], void* dll)
hooks.display_error = AtlasDisplayError;
app_hooks_update(&hooks);
state.argc = argc;
state.argv = argv;
state.args = args;
state.running = true;
state.view = View::GetView_None();
state.glContext = NULL;
@ -245,5 +241,5 @@ bool BeginAtlas(int argc, char* argv[], void* dll)
// Clean up
View::DestroyViews();
exit(0);
return true;
}

View File

@ -1,14 +1,15 @@
#ifndef GAMELOOP_H__
#define GAMELOOP_H__
#include "ps/GameSetup/CmdLineArgs.h"
extern void (*Atlas_GLSetCurrent)(void* context);
class View;
struct GameLoopState
{
int argc;
char** argv;
CmdLineArgs args;
bool running; // whether the Atlas game loop is still running
View* view; // current 'view' (controls updates, rendering, etc)

View File

@ -34,7 +34,7 @@ MESSAGEHANDLER(Init)
if (! msg->initsimulation)
flags |= INIT_NO_SIM;
Init(g_GameLoop->argc, g_GameLoop->argv, flags);
Init(g_GameLoop->args, flags);
g_DidInitSim = msg->initsimulation; // so we can shut down the right things later