# 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:
parent
0e1eb62687
commit
cbafd43eea
@ -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,8 +732,8 @@ 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")
|
||||
|
||||
|
@ -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__
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
MainControllerInit();
|
||||
CmdLineArgs args(argc, argv);
|
||||
|
||||
debug_filter_add("LOADER");
|
||||
bool ran_atlas = ATLAS_RunIfOnCmdLine(args);
|
||||
|
||||
//trace_gen_random(5000);
|
||||
//trace_write_to_file("../logs/trace.txt");
|
||||
// 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();
|
||||
|
||||
#if 0
|
||||
trace_run("../logs/trace.txt");
|
||||
#else
|
||||
while(!quit)
|
||||
Frame();
|
||||
#endif
|
||||
debug_filter_add("LOADER"); // TODO: remove this?
|
||||
|
||||
Shutdown(0);
|
||||
MainControllerShutdown();
|
||||
while(!quit)
|
||||
Frame();
|
||||
|
||||
Shutdown(0);
|
||||
MainControllerShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
debug_printf("Shutdown complete, calling exit() now\n");
|
||||
|
||||
|
@ -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(argc, argv, ATLAS_NO_GUI);
|
||||
break;
|
||||
}
|
||||
ATLAS_Run(args, ATLAS_NO_GUI);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
74
source/ps/GameSetup/CmdLineArgs.cpp
Normal file
74
source/ps/GameSetup/CmdLineArgs.cpp
Normal 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;
|
||||
}
|
52
source/ps/GameSetup/CmdLineArgs.h
Normal file
52
source/ps/GameSetup/CmdLineArgs.h
Normal 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__
|
@ -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,120 +90,94 @@ static void LoadGlobals()
|
||||
}
|
||||
|
||||
|
||||
static void ParseCommandLineArgs(int argc, char* argv[])
|
||||
static void ProcessCommandLineArgs(const CmdLineArgs& args)
|
||||
{
|
||||
for(int i = 1; i < argc; i++)
|
||||
// TODO: all these options (and the ones processed elsewhere) should
|
||||
// be documented somewhere for users.
|
||||
|
||||
if (args.Has("autostart"))
|
||||
g_AutostartMap = args.Get("autostart");
|
||||
|
||||
if (args.Has("buildarchive"))
|
||||
{
|
||||
// this arg isn't an option; skip
|
||||
if(argv[i][0] != '-')
|
||||
continue;
|
||||
|
||||
char* name = argv[i]+1; // no leading '-'
|
||||
|
||||
// switch first letter of option name
|
||||
switch(argv[i][1])
|
||||
{
|
||||
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)
|
||||
{
|
||||
if(argc-i >= 1) // at least one arg left
|
||||
{
|
||||
i++;
|
||||
char* arg = argv[i];
|
||||
char* equ = strchr(arg, '=');
|
||||
if(equ)
|
||||
{
|
||||
*equ = 0;
|
||||
g_ConfigDB.CreateValue(CFG_COMMAND, arg)
|
||||
->m_String = (equ+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if(strncmp(name, "entgraph", 8) == 0)
|
||||
g_EntGraph = true;
|
||||
break;
|
||||
case 'f':
|
||||
if(strncmp(name, "fixedframe", 10) == 0)
|
||||
g_FixedFrameTiming = true;
|
||||
break;
|
||||
case 'g':
|
||||
if(strncmp(name, "g=", 2) == 0)
|
||||
{
|
||||
g_Gamma = (float)atof(argv[i] + 3);
|
||||
if(g_Gamma == 0.0f)
|
||||
g_Gamma = 1.0f;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if(strncmp(name, "listfiles", 9) == 0)
|
||||
trace_enable(true);
|
||||
break;
|
||||
case 'm':
|
||||
if(strncmp(name, "mod=", 4) == 0)
|
||||
{
|
||||
const char* mod_name = name+4;
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, ARRAY_SIZE(path), "mods/%s", mod_name);
|
||||
path[PATH_MAX-1] = '\0';
|
||||
// note: default is 0. we should set this higher in case the
|
||||
// mod file mtimes are actually older than the official
|
||||
// version (*could* happen), otherwise the mod might not
|
||||
// actually override as intended.
|
||||
//
|
||||
// HACK: since this is the only place where mods are added,
|
||||
// we can get away with just setting it to 1.
|
||||
// otherwise, add a static counter.
|
||||
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)
|
||||
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)
|
||||
g_Quickstart = true;
|
||||
break;
|
||||
case 's':
|
||||
if(strncmp(name, "shadows", 7) == 0)
|
||||
g_ConfigDB.CreateValue(CFG_COMMAND, "shadows")->m_String="true";
|
||||
break;
|
||||
case 'v':
|
||||
if(strncmp(name, "vsync", 5) == 0)
|
||||
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
|
||||
// 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");
|
||||
}
|
||||
|
||||
// Handle "-conf=key:value" (potentially multiple times)
|
||||
std::vector<CStr> conf = args.GetMultiple("conf");
|
||||
for (size_t i = 0; i < conf.size(); ++i)
|
||||
{
|
||||
CStr name_value = conf[i];
|
||||
if (name_value.Find(':') != -1)
|
||||
{
|
||||
CStr name = name_value.BeforeFirst(":");
|
||||
CStr value = name_value.AfterFirst(":");
|
||||
g_ConfigDB.CreateValue(CFG_COMMAND, name)->m_String = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.Has("entgraph"))
|
||||
g_EntGraph = true;
|
||||
|
||||
if (args.Has("fixedframe"))
|
||||
g_FixedFrameTiming = true;
|
||||
|
||||
if (args.Has("g"))
|
||||
{
|
||||
g_Gamma = (float)atof(args.Get("g"));
|
||||
if (g_Gamma == 0.0f)
|
||||
g_Gamma = 1.0f;
|
||||
}
|
||||
|
||||
if (args.Has("listfiles"))
|
||||
trace_enable(true);
|
||||
|
||||
std::vector<CStr> mods = args.GetMultiple("mod");
|
||||
for (size_t i = 0; i < mods.size(); ++i)
|
||||
{
|
||||
const char* mod_name = mods[i];
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, ARRAY_SIZE(path), "mods/%s", mod_name);
|
||||
path[PATH_MAX-1] = '\0';
|
||||
// note: default is 0. we should set this higher in case the
|
||||
// mod file mtimes are actually older than the official
|
||||
// version (*could* happen), otherwise the mod might not
|
||||
// actually override as intended.
|
||||
//
|
||||
// HACK: since this is the only place where mods are added,
|
||||
// we can get away with just setting it to 1.
|
||||
// otherwise, add a static counter.
|
||||
uint pri = 1;
|
||||
(void)vfs_mount("", path, VFS_MOUNT_RECURSIVE|VFS_MOUNT_ARCHIVES|VFS_MOUNT_WATCH, pri);
|
||||
}
|
||||
|
||||
if (args.Has("novbo"))
|
||||
g_ConfigDB.CreateValue(CFG_COMMAND, "novbo")->m_String="true";
|
||||
|
||||
if (args.Has("profile"))
|
||||
g_ConfigDB.CreateValue(CFG_COMMAND, "profile")->m_String = args.Get("profile");
|
||||
|
||||
if (args.Has("quickstart"))
|
||||
g_Quickstart = true;
|
||||
|
||||
if (args.Has("shadows"))
|
||||
g_ConfigDB.CreateValue(CFG_COMMAND, "shadows")->m_String = "true";
|
||||
|
||||
if (args.Has("vsync"))
|
||||
g_ConfigDB.CreateValue(CFG_COMMAND, "vsync")->m_String = "true";
|
||||
|
||||
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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
69
source/ps/GameSetup/tests/test_CmdLineArgs.h
Normal file
69
source/ps/GameSetup/tests/test_CmdLineArgs.h
Normal 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(), "");
|
||||
}
|
||||
};
|
@ -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\"");
|
||||
}
|
||||
};
|
||||
|
@ -1437,7 +1437,7 @@ bool CRenderer::LoadTexture(CTexture* texture,u32 wrapflags)
|
||||
{
|
||||
const Handle errorhandle = -1;
|
||||
|
||||
Handle h=texture->GetHandle();
|
||||
Handle h = texture->GetHandle();
|
||||
// already tried to load this texture
|
||||
if (h)
|
||||
{
|
||||
@ -1446,7 +1446,7 @@ bool CRenderer::LoadTexture(CTexture* texture,u32 wrapflags)
|
||||
return h==errorhandle ? true : false;
|
||||
}
|
||||
|
||||
h=ogl_tex_load(texture->GetName());
|
||||
h = ogl_tex_load(texture->GetName());
|
||||
if (h <= 0)
|
||||
{
|
||||
LOG(ERROR, LOG_CATEGORY, "LoadTexture failed on \"%s\"",(const char*) texture->GetName());
|
||||
|
@ -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")
|
||||
|
@ -58,15 +58,12 @@ 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)
|
||||
return L"ActorViewer";
|
||||
}
|
||||
|
||||
return L"ScenarioEditor";
|
||||
if (args.Has("actorviewer"))
|
||||
return L"ActorViewer";
|
||||
else
|
||||
return L"ScenarioEditor";
|
||||
}
|
||||
|
||||
static ErrorReaction AtlasDisplayError(const wchar_t* text, uint flags)
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user