Browse Source

Merge pull request #472 from dpogue/plCmdParser

plCmdParser
Adam Johnson 9 years ago
parent
commit
91f9d6b8d4
  1. 23
      Sources/Plasma/Apps/plClient/winmain.cpp
  2. 29
      Sources/Plasma/Apps/plUruLauncher/plClientLauncher.cpp
  3. 2
      Sources/Plasma/CoreLib/CMakeLists.txt
  4. 618
      Sources/Plasma/CoreLib/plCmdParser.cpp
  5. 136
      Sources/Plasma/CoreLib/plCmdParser.h
  6. 15
      Sources/Plasma/NucleusLib/pnUtils/CMakeLists.txt
  7. 41
      Sources/Plasma/NucleusLib/pnUtils/Win32/W32Int.h
  8. 60
      Sources/Plasma/NucleusLib/pnUtils/Win32/pnUtW32Misc.cpp
  9. 2
      Sources/Plasma/NucleusLib/pnUtils/pnUtAllIncludes.h
  10. 650
      Sources/Plasma/NucleusLib/pnUtils/pnUtCmd.cpp
  11. 136
      Sources/Plasma/NucleusLib/pnUtils/pnUtCmd.h
  12. 91
      Sources/Plasma/NucleusLib/pnUtils/pnUtMisc.cpp
  13. 72
      Sources/Plasma/NucleusLib/pnUtils/pnUtMisc.h
  14. 169
      Sources/Plasma/NucleusLib/pnUtils/pnUtStr.cpp
  15. 22
      Sources/Plasma/NucleusLib/pnUtils/pnUtStr.h
  16. 1
      Sources/Tests/CoreTests/CMakeLists.txt
  17. 547
      Sources/Tests/CoreTests/test_plCmdParser.cpp

23
Sources/Plasma/Apps/plClient/winmain.cpp

@ -50,6 +50,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include <curl/curl.h>
#include "hsStream.h"
#include "plCmdParser.h"
#include "plClient.h"
#include "plClientResMgr/plClientResMgr.h"
#include "pfCrashHandler/plCrashCli.h"
@ -96,11 +97,11 @@ enum
kArgSkipPreload
};
static const CmdArgDef s_cmdLineArgs[] = {
{ kCmdArgFlagged | kCmdTypeBool, L"SkipLoginDialog", kArgSkipLoginDialog },
{ kCmdArgFlagged | kCmdTypeString, L"ServerIni", kArgServerIni },
{ kCmdArgFlagged | kCmdTypeBool, L"LocalData", kArgLocalData },
{ kCmdArgFlagged | kCmdTypeBool, L"SkipPreload", kArgSkipPreload },
static const plCmdArgDef s_cmdLineArgs[] = {
{ kCmdArgFlagged | kCmdTypeBool, "SkipLoginDialog", kArgSkipLoginDialog },
{ kCmdArgFlagged | kCmdTypeString, "ServerIni", kArgServerIni },
{ kCmdArgFlagged | kCmdTypeBool, "LocalData", kArgLocalData },
{ kCmdArgFlagged | kCmdTypeBool, "SkipPreload", kArgSkipPreload },
};
/// Made globals now, so we can set them to zero if we take the border and
@ -1132,8 +1133,14 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
// Set global handle
gHInst = hInst;
CCmdParser cmdParser(s_cmdLineArgs, arrsize(s_cmdLineArgs));
cmdParser.Parse();
std::vector<plString> args;
args.reserve(__argc);
for (size_t i = 0; i < __argc; i++) {
args.push_back(plString::FromUtf8(__argv[i]));
}
plCmdParser cmdParser(s_cmdLineArgs, arrsize(s_cmdLineArgs));
cmdParser.Parse(args);
bool doIntroDialogs = true;
#ifndef PLASMA_EXTERNAL_RELEASE
@ -1150,7 +1157,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
plFileName serverIni = "server.ini";
if (cmdParser.IsSpecified(kArgServerIni))
serverIni = plString::FromWchar(cmdParser.GetString(kArgServerIni));
serverIni = cmdParser.GetString(kArgServerIni);
// check to see if we were launched from the patcher
bool eventExists = false;

29
Sources/Plasma/Apps/plUruLauncher/plClientLauncher.cpp

@ -46,8 +46,9 @@ Mead, WA 99021
#include "plProduct.h"
#include "hsThread.h"
#include "hsTimer.h"
#include "plCmdParser.h"
#include "pnUtils/pnUtils.h" // for CCmdParser
#include "pnUtils/pnUtils.h"
#include "pnAsyncCore/pnAsyncCore.h"
#include "plNetGameLib/plNetGameLib.h"
#include "plStatusLog/plStatusLog.h"
@ -432,21 +433,27 @@ void plClientLauncher::ParseArguments()
enum { kArgServerIni, kArgNoSelfPatch, kArgImage, kArgRepairGame, kArgPatchOnly,
kArgSkipLoginDialog };
const CmdArgDef cmdLineArgs[] = {
{ kCmdArgFlagged | kCmdTypeString, L"ServerIni", kArgServerIni },
{ kCmdArgFlagged | kCmdTypeBool, L"NoSelfPatch", kArgNoSelfPatch },
{ kCmdArgFlagged | kCmdTypeBool, L"Image", kArgImage },
{ kCmdArgFlagged | kCmdTypeBool, L"Repair", kArgRepairGame },
{ kCmdArgFlagged | kCmdTypeBool, L"PatchOnly", kArgPatchOnly },
{ kCmdArgFlagged | kCmdTypeBool, L"SkipLoginDialog", kArgSkipLoginDialog }
const plCmdArgDef cmdLineArgs[] = {
{ kCmdArgFlagged | kCmdTypeString, "ServerIni", kArgServerIni },
{ kCmdArgFlagged | kCmdTypeBool, "NoSelfPatch", kArgNoSelfPatch },
{ kCmdArgFlagged | kCmdTypeBool, "Image", kArgImage },
{ kCmdArgFlagged | kCmdTypeBool, "Repair", kArgRepairGame },
{ kCmdArgFlagged | kCmdTypeBool, "PatchOnly", kArgPatchOnly },
{ kCmdArgFlagged | kCmdTypeBool, "SkipLoginDialog", kArgSkipLoginDialog }
};
CCmdParser cmdParser(cmdLineArgs, arrsize(cmdLineArgs));
cmdParser.Parse();
std::vector<plString> args;
args.reserve(__argc);
for (size_t i = 0; i < __argc; i++) {
args.push_back(plString::FromUtf8(__argv[i]));
}
plCmdParser cmdParser(cmdLineArgs, arrsize(cmdLineArgs));
cmdParser.Parse(args);
// cache 'em
if (cmdParser.IsSpecified(kArgServerIni))
fServerIni = plString::FromWchar(cmdParser.GetString(kArgServerIni));
fServerIni = cmdParser.GetString(kArgServerIni);
APPLY_FLAG(kArgNoSelfPatch, kHaveSelfPatched);
APPLY_FLAG(kArgImage, kClientImage);
APPLY_FLAG(kArgRepairGame, kRepairGame);

2
Sources/Plasma/CoreLib/CMakeLists.txt

@ -28,6 +28,7 @@ set(CoreLib_SOURCES
hsTemplates.cpp
hsWide.cpp
pcSmallRect.cpp
plCmdParser.cpp
plFileSystem.cpp
plFormat.cpp
plGeneric.cpp
@ -74,6 +75,7 @@ set(CoreLib_HEADERS
hsWide.h
hsWindows.h
pcSmallRect.h
plCmdParser.h
plFileSystem.h
plFormat.h
plGeneric.h

618
Sources/Plasma/CoreLib/plCmdParser.cpp

@ -0,0 +1,618 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plCmdParser.h"
#include <vector>
#include <algorithm>
#define WHITESPACE " \"\t\r\n\x1A"
#define FLAGS "-/"
#define SEPARATORS "=:"
#define TOGGLES "+-"
#define ALL WHITESPACE FLAGS SEPARATORS TOGGLES
#define hsCheckFlagBits(f,c,m) ((f & m)==c)
struct plCmdArgData
{
plCmdArgDef def;
union {
bool boolVal;
float floatVal;
int32_t intVal;
const char* strVal;
uint32_t uintVal;
} val;
plString buffer;
size_t nameChars;
bool isSpecified;
};
struct plCmdTokenState {
size_t fPendingIndex;
size_t fUnflaggedIndex;
};
class plCmdParserImpl
{
protected:
plString fProgramName;
std::vector<plCmdArgData> fArgArray;
std::vector<uint32_t> fLookupArray;
std::vector<uint32_t> fUnflaggedArray;
uint32_t fRequiredCount;
CmdError fError;
void SetDefaultValue(plCmdArgData& arg);
bool ProcessValue(plCmdTokenState* state, size_t index, const plString& str);
bool TokenizeFlags(plCmdTokenState* state, const plString& str);
bool LookupFlagged(plString& name, size_t* lastIndex, bool force=false) const;
public:
plCmdParserImpl(const plCmdArgDef* defs, size_t defCount);
bool Tokenize(plCmdTokenState* state, std::vector<plString>& strs);
const plCmdArgData* FindArgByName(const plString& name) const;
const plCmdArgData* FindArgById(size_t id) const;
bool CheckAllRequiredArguments(plCmdTokenState* state);
const plString GetProgramName() const { return fProgramName; }
CmdError GetError() const { return fError; }
};
plCmdParserImpl::plCmdParserImpl(const plCmdArgDef* defs, size_t defCount)
{
size_t loop;
fError = kCmdErrorSuccess;
// Save the argument definitions
size_t maxId = 0;
size_t unflaggedCount = 0;
fArgArray.resize(defCount);
for (loop = 0; loop < defCount; ++loop) {
plCmdArgDef def = defs[loop];
// Check whether this argument is flagged
bool flagged = hsCheckFlagBits(def.flags,
kCmdArgFlagged,
kCmdArgMask);
// Disallow names on unflagged arguments
ASSERT(flagged || !def.name.IsEmpty());
// Store the argument data
plCmdArgData& arg = fArgArray[loop];
arg.def = def;
arg.buffer = "";
arg.nameChars = def.name.GetSize();
arg.isSpecified = false;
SetDefaultValue(arg);
maxId = std::max(maxId, def.id);
// Track the number of unflagged arguments
if (!flagged) {
++unflaggedCount;
}
}
// Build the id lookup table
size_t idTableSize = std::min(maxId + 1, defCount * 2);
fLookupArray.resize(idTableSize);
for (loop = 0; loop < defCount; ++loop) {
if (defs[loop].id < idTableSize) {
fLookupArray[defs[loop].id] = loop;
}
}
// Build the unflagged array
size_t unflaggedIndex = 0;
fUnflaggedArray.resize(unflaggedCount);
for (loop = 0; loop < defCount; ++loop) {
bool req = hsCheckFlagBits(defs[loop].flags,
kCmdArgRequired,
kCmdArgMask);
if (req) {
fUnflaggedArray[unflaggedIndex++] = loop;
}
}
fRequiredCount = unflaggedIndex;
for (loop = 0; loop < defCount; ++loop) {
bool flagged = hsCheckFlagBits(defs[loop].flags,
kCmdArgFlagged,
kCmdArgMask);
bool req = hsCheckFlagBits(defs[loop].flags,
kCmdArgRequired,
kCmdArgMask);
if (!flagged && !req) {
fUnflaggedArray[unflaggedIndex++] = loop;
}
}
}
void plCmdParserImpl::SetDefaultValue(plCmdArgData& arg)
{
uint32_t argType = arg.def.flags & kCmdTypeMask;
switch (argType) {
case kCmdTypeBool:
arg.val.boolVal = !hsCheckFlagBits(arg.def.flags,
kCmdBoolSet,
kCmdBoolMask);
break;
case kCmdTypeInt:
arg.val.intVal = 0;
break;
case kCmdTypeUint:
arg.val.uintVal = 0;
break;
case kCmdTypeFloat:
arg.val.floatVal = 0.0f;
break;
case kCmdTypeString:
arg.val.strVal = "";
break;
DEFAULT_FATAL(argType);
}
}
bool plCmdParserImpl::Tokenize(plCmdTokenState* state, std::vector<plString>& strs)
{
bool result = true;
for (auto it = strs.begin(); result && it != strs.end(); ++it) {
if (fProgramName.IsEmpty()) {
fProgramName = *it;
continue;
}
// If the previous argument is awaiting a value, then use this token
// as the value
if (state->fPendingIndex != size_t(-1)) {
result = ProcessValue(state, state->fPendingIndex, *it);
state->fPendingIndex = size_t(-1);
continue;
}
// Identify and process flagged parameters
if ((*it).REMatch("[" FLAGS "].+") && TokenizeFlags(state, *it)) {
continue;
}
// Process unflagged parameters
if (state->fUnflaggedIndex < fUnflaggedArray.size()) {
result = ProcessValue(state, fUnflaggedArray[state->fUnflaggedIndex++], *it);
continue;
}
// Process invalid parameters
if (!fError) {
fError = kCmdErrorTooManyArgs;
}
result = false;
break;
}
return result;
}
bool plCmdParserImpl::ProcessValue(plCmdTokenState* state, size_t index, const plString& str)
{
plCmdArgData& arg = fArgArray[index];
arg.isSpecified = true;
uint32_t argType = arg.def.flags & kCmdTypeMask;
switch (argType) {
case kCmdTypeBool:
if (str.CompareI("true") == 0)
arg.val.boolVal = true;
else if (str.CompareI("false") == 0)
arg.val.boolVal = false;
else if (str.IsEmpty())
arg.val.boolVal = hsCheckFlagBits(arg.def.flags,
kCmdBoolSet,
kCmdBoolMask);
else
fError = kCmdErrorInvalidValue;
break;
case kCmdTypeFloat:
arg.val.floatVal = str.ToFloat();
break;
case kCmdTypeInt:
arg.val.intVal = str.ToInt();
break;
case kCmdTypeString:
arg.buffer = str;
arg.val.strVal = arg.buffer.c_str();
break;
case kCmdTypeUint:
arg.val.uintVal = str.ToUInt(10);
break;
DEFAULT_FATAL(argType);
}
return true;
}
bool plCmdParserImpl::TokenizeFlags(plCmdTokenState* state, const plString& str)
{
bool result = true;
std::vector<plString> tokens = str.Tokenize(ALL);
for (auto it = tokens.begin(); result && it != tokens.end(); ++it) {
size_t lastIndex = size_t(-1);
plString buffer = *it;
if (buffer.IsEmpty()) {
continue;
}
while (result) {
// Lookup the argument name
result = LookupFlagged(buffer, &lastIndex);
if (!result) {
fError = kCmdErrorInvalidArg;
result = false;
}
break;
}
if (!result) {
break;
}
// Check for an argument value provided using a separator
if (str.REMatch(".+[" SEPARATORS "].+") && !(*(++it)).IsEmpty()) {
result = ProcessValue(state, lastIndex, *it);
break;
}
bool isBool = hsCheckFlagBits(fArgArray[lastIndex].def.flags,
kCmdTypeBool,
kCmdTypeMask);
// Process values for boolean arguments
if (isBool) {
result = ProcessValue(state, lastIndex, plString::Null);
continue;
}
// Process values for non-boolean arguments
else {
// Check for an argument value immediately following the name
if (!buffer.IsEmpty()) {
result = ProcessValue(state, lastIndex, buffer);
break;
}
// Check for an argument value in the next token
else {
state->fPendingIndex = lastIndex;
break;
}
}
}
return result;
}
bool plCmdParserImpl::LookupFlagged(plString& name, size_t* lastIndex, bool force) const
{
size_t argCount = fArgArray.size();
size_t chars = name.GetSize();
size_t bestIndex = size_t(-1);
size_t bestChars = 0;
size_t prevChars = 0;
if (*lastIndex != size_t(-1)) {
prevChars = fArgArray[*lastIndex].def.name.GetSize();
}
for (; prevChars != size_t(-1) && !bestChars; --prevChars) {
// Find this argument in the list
for (size_t index = 0; index < argCount; ++index) {
const plCmdArgData& arg = fArgArray[index];
// Ignore non-flagged arguments
bool flagged = hsCheckFlagBits(arg.def.flags,
kCmdArgFlagged,
kCmdArgMask);
if (!flagged && !force)
continue;
// Ignore this arg if it wouldn't beat the previous best match
if (arg.def.name.GetSize() < bestChars + prevChars)
continue;
// Ignore this argument if it doesn't match the prefix
bool caseSensitive = hsCheckBits(arg.def.flags,
kCmdCaseSensitive);
if (prevChars) {
const plCmdArgData& prev = fArgArray[*lastIndex];
if (prevChars >= arg.def.name.GetSize())
continue;
if (caseSensitive &&
arg.def.name.CompareN(prev.def.name, prevChars))
continue;
if (!caseSensitive &&
arg.def.name.CompareNI(prev.def.name, prevChars))
continue;
}
// Ignore this argument if it doesn't match the suffix
plString suffix = arg.def.name.Substr(prevChars);
if (caseSensitive && suffix.CompareN(name, std::min(name.GetSize(), suffix.GetSize())))
continue;
if (!caseSensitive && suffix.CompareNI(name, std::min(name.GetSize(), suffix.GetSize())))
continue;
// Track the best match
bestIndex = index;
bestChars = arg.def.name.GetSize() - prevChars;
if (bestChars == chars)
break;
}
}
// Return the result
name = name.Substr(bestChars);
*lastIndex = bestIndex;
return bestChars != 0;
}
const plCmdArgData* plCmdParserImpl::FindArgByName(const plString& name) const
{
// Search for an argument with this name
size_t index = size_t(-1);
plString arg = name;
if (!LookupFlagged(arg, &index, true)) {
return nullptr;
}
// Return the argument data
return &fArgArray[index];
}
const plCmdArgData* plCmdParserImpl::FindArgById(size_t id) const
{
// Search for the argument with this id
size_t index;
if (id < fLookupArray.size()) {
index = fLookupArray[id];
} else {
for (index = 0; index < fArgArray.size(); ++index) {
if (fArgArray[index].def.id == id) {
break;
}
}
}
// Verify that we found the correct argument
if ((index >= fArgArray.size()) || (fArgArray[index].def.id != id)) {
return nullptr;
}
// Return the argument data
return &fArgArray[index];
}
bool plCmdParserImpl::CheckAllRequiredArguments(plCmdTokenState* state)
{
bool result = (state->fUnflaggedIndex >= fRequiredCount);
if (!result) {
fError = kCmdErrorTooFewArgs;
}
return result;
}
plCmdParser::plCmdParser(const plCmdArgDef* defs, size_t defCount)
{
Initialize(defs, defCount);
}
plCmdParser::~plCmdParser()
{
delete fParser;
}
void plCmdParser::Initialize(const plCmdArgDef* defs, size_t defCount)
{
fParser = new plCmdParserImpl(defs, defCount);
}
bool plCmdParser::Parse(const plString& cmdLine)
{
// Process the command line
plCmdTokenState state = {
size_t(-1), // pending index
0 // unflagged index
};
std::vector<plString> tokens = cmdLine.Tokenize(WHITESPACE);
bool result = fParser->Tokenize(&state, tokens);
if (result) {
result = fParser->CheckAllRequiredArguments(&state);
}
return result;
}
bool plCmdParser::Parse(std::vector<plString>& argv)
{
// Process the command line
plCmdTokenState state = {
size_t(-1), // pending index
0 // unflagged index
};
bool result = fParser->Tokenize(&state, argv);
if (result) {
result = fParser->CheckAllRequiredArguments(&state);
}
return result;
}
const plString plCmdParser::GetProgramName() const
{
return fParser->GetProgramName();
}
bool plCmdParser::GetBool(size_t id) const
{
return fParser->FindArgById(id)->val.boolVal;
}
bool plCmdParser::GetBool(const plString& name) const
{
return fParser->FindArgByName(name)->val.boolVal;
}
float plCmdParser::GetFloat(size_t id) const
{
return fParser->FindArgById(id)->val.floatVal;
}
float plCmdParser::GetFloat(const plString& name) const
{
return fParser->FindArgByName(name)->val.floatVal;
}
int32_t plCmdParser::GetInt(size_t id) const
{
return fParser->FindArgById(id)->val.intVal;
}
int32_t plCmdParser::GetInt(const plString& name) const
{
return fParser->FindArgByName(name)->val.intVal;
}
const plString plCmdParser::GetString(size_t id) const
{
return fParser->FindArgById(id)->val.strVal;
}
const plString plCmdParser::GetString(const plString& name) const
{
return fParser->FindArgByName(name)->val.strVal;
}
uint32_t plCmdParser::GetUint(size_t id) const
{
return fParser->FindArgById(id)->val.uintVal;
}
uint32_t plCmdParser::GetUint(const plString& name) const
{
return fParser->FindArgByName(name)->val.uintVal;
}
bool plCmdParser::IsSpecified(size_t id) const
{
if (const plCmdArgData* data = fParser->FindArgById(id)) {
return data->isSpecified;
}
return false;
}
bool plCmdParser::IsSpecified(const plString& name) const
{
if (const plCmdArgData* data = fParser->FindArgByName(name)) {
return data->isSpecified;
}
return false;
}
CmdError plCmdParser::GetError() const
{
return fParser->GetError();
}

136
Sources/Plasma/CoreLib/plCmdParser.h

@ -0,0 +1,136 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef _plCmdParser_h_
#define _plCmdParser_h_
#include "plString.h"
enum CmdArg
{
kCmdArgFlagged = 0x0, // default
kCmdArgOptional = 0x1,
kCmdArgRequired = 0x2,
kCmdArgMask = 0xF
};
enum CmdType
{
kCmdTypeBool = 0x0 << 4, // default
kCmdTypeInt = 0x1 << 4,
kCmdTypeUint = 0x2 << 4,
kCmdTypeFloat = 0x3 << 4,
kCmdTypeString = 0x4 << 4,
kCmdTypeMask = 0xF << 4
};
enum CmdBool
{
kCmdBoolSet = 0x0 << 8, // default
kCmdBoolUnset = 0x1 << 8,
kCmdBoolMask = 0xF << 8
};
enum CmdCase
{
kCmdCaseSensitive = 0x1 << 28
};
// Error codes
enum CmdError
{
kCmdErrorSuccess,
kCmdErrorInvalidArg,
kCmdErrorInvalidValue,
kCmdErrorTooFewArgs,
kCmdErrorTooManyArgs,
kNumCmdErrors
};
struct plCmdArgDef
{
uint32_t flags;
plString name; // must be compile-time constant
size_t id;
};
class plCmdParser
{
protected:
class plCmdParserImpl* fParser;
plCmdParser() : fParser(nullptr) { }
void Initialize(const plCmdArgDef* defs, size_t defCount);
public:
plCmdParser(const plCmdArgDef* defs, size_t defCount);
virtual ~plCmdParser();
bool Parse(const plString& cmdLine);
bool Parse(std::vector<plString>& argv);
const plString GetProgramName() const;
bool GetBool(size_t id) const;
bool GetBool(const plString& name) const;
float GetFloat(size_t id) const;
float GetFloat(const plString& name) const;
int32_t GetInt(size_t id) const;
int32_t GetInt(const plString& name) const;
const plString GetString(size_t id) const;
const plString GetString(const plString& name) const;
uint32_t GetUint(size_t id) const;
uint32_t GetUint(const plString& name) const;
bool IsSpecified(size_t id) const;
bool IsSpecified(const plString& name) const;
CmdError GetError() const;
};
#endif //_plCmdParser_h_

15
Sources/Plasma/NucleusLib/pnUtils/CMakeLists.txt

@ -7,11 +7,9 @@ set(pnUtils_HEADERS
pnUtCoreLib.h
pnUtAllIncludes.h
pnUtArray.h
pnUtCmd.h
pnUtCrypt.h
pnUtHash.h
pnUtList.h
pnUtMisc.h
pnUtPragma.h
pnUtPriQ.h
pnUtSort.h
@ -21,25 +19,16 @@ set(pnUtils_HEADERS
set(pnUtils_SOURCES
pnUtArray.cpp
pnUtCmd.cpp
pnUtCrypt.cpp
pnUtHash.cpp
pnUtList.cpp
pnUtMisc.cpp
pnUtStr.cpp
pnUtTime.cpp
)
if(WIN32)
set(pnUtils_WIN32
Win32/pnUtW32Misc.cpp
)
endif(WIN32)
add_library(pnUtils STATIC ${pnUtils_HEADERS} ${pnUtils_SOURCES})
add_library(pnUtils STATIC ${pnUtils_HEADERS} ${pnUtils_SOURCES} ${pnUtils_WIN32})
target_link_libraries(pnUtils CoreLib)
source_group("Header Files" FILES ${pnUtils_HEADERS})
source_group("Source Files" FILES ${pnUtils_SOURCES})
if(WIN32)
source_group("Win32" FILES ${pnUtils_WIN32})
endif(WIN32)

41
Sources/Plasma/NucleusLib/pnUtils/Win32/W32Int.h

@ -1,41 +0,0 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/

60
Sources/Plasma/NucleusLib/pnUtils/Win32/pnUtW32Misc.cpp

@ -1,60 +0,0 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/Win32/pnUtW32Misc.cpp
*
***/
#include "../pnUtils.h"
/*****************************************************************************
*
* Exports
*
***/
//============================================================================
const wchar_t * AppGetCommandLine () {
return GetCommandLineW();
}

2
Sources/Plasma/NucleusLib/pnUtils/pnUtAllIncludes.h

@ -58,8 +58,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "pnUtPriQ.h"
#include "pnUtTime.h"
#include "pnUtStr.h"
#include "pnUtCmd.h"
#include "pnUtMisc.h"
#include "pnUtCrypt.h"
#endif // PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTALLINCLUDES_H

650
Sources/Plasma/NucleusLib/pnUtils/pnUtCmd.cpp

@ -1,650 +0,0 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtCmd.cpp
*
***/
#include "pnUtCmd.h"
#include "pnUtMisc.h"
/*****************************************************************************
*
* Private
*
***/
#define WHITESPACE L" \"\t\r\n\x1A"
#define FLAGS L"-/"
#define SEPARATORS L"=:"
#define TOGGLES L"+-"
#define ALL WHITESPACE FLAGS SEPARATORS TOGGLES
#if HS_BUILD_FOR_WIN32
static const unsigned kMaxTokenLength = MAX_PATH;
#else
static const unsigned kMaxTokenLength = 1024;
#endif
struct CmdArgData {
CmdArgDef def;
union {
bool boolVal;
float floatVal;
int intVal;
const wchar_t * strVal;
unsigned unsignedVal;
} val;
wchar_t * buffer;
unsigned nameChars;
bool isSpecified;
~CmdArgData () {
if (buffer)
free(buffer);
}
};
struct CmdTokState {
CCmdParser * parser;
unsigned pendingIndex;
unsigned unflaggedIndex;
};
class CICmdParser {
private:
FARRAYOBJ(CmdArgData) m_argArray;
FARRAY(unsigned) m_idLookupArray;
unsigned m_requiredCount;
FARRAY(unsigned) m_unflaggedArray;
inline bool CheckFlag (unsigned flags, unsigned flag, unsigned mask) const;
void Error (const CmdTokState * state, ECmdError errorCode, const wchar_t arg[], const wchar_t value[]) const;
bool LookupFlagged (const wchar_t ** name, unsigned * lastIndex) const;
bool ProcessValue (CmdTokState * state, unsigned index, const wchar_t str[]);
void SetDefaultValue (CmdArgData & arg);
bool TokenizeFlags (CmdTokState * state, const wchar_t str[]);
public:
CICmdParser (const CmdArgDef def[], unsigned defCount);
bool CheckAllRequiredArguments (CmdTokState * state);
const CmdArgData * FindArgById (unsigned id) const;
const CmdArgData * FindArgByName (const wchar_t name[]) const;
bool Tokenize (CmdTokState * state, const wchar_t str[]);
};
/*****************************************************************************
*
* CICmdParser implementation
*
***/
//===========================================================================
bool CICmdParser::CheckFlag (unsigned flags, unsigned flag, unsigned mask) const {
return ((flags & mask) == flag);
}
//===========================================================================
bool CICmdParser::CheckAllRequiredArguments (CmdTokState * state) {
bool result = (state->unflaggedIndex >= m_requiredCount);
if (!result)
Error(state, kCmdErrorTooFewArgs, nil, nil);
return result;
}
//===========================================================================
CICmdParser::CICmdParser (const CmdArgDef def[], unsigned defCount) {
unsigned loop;
// Save the argument definitions
unsigned maxId = 0;
unsigned unflaggedCount = 0;
m_argArray.SetCount(defCount);
for (loop = 0; loop < defCount; ++loop) {
// Check whether this argument is flagged
bool flagged = CheckFlag(def[loop].flags, kCmdArgFlagged, kCmdMaskArg);
// Disallow names on unflagged arguments
ASSERT(flagged || !def[loop].name);
// Store the argument data
CmdArgData & arg = m_argArray[loop];
arg.def = def[loop];
arg.buffer = nil;
arg.nameChars = def[loop].name ? StrLen(def[loop].name) : 0;
arg.isSpecified = false;
SetDefaultValue(arg);
maxId = std::max(maxId, def[loop].id);
// Track the number of unflagged arguments
if (!flagged)
++unflaggedCount;
}
// Build the id lookup table
unsigned idTableSize = std::min(maxId + 1, defCount * 2);
m_idLookupArray.SetCount(idTableSize);
m_idLookupArray.Zero();
for (loop = 0; loop < defCount; ++loop)
if (def[loop].id < idTableSize)
m_idLookupArray[def[loop].id] = loop;
// Build the unflagged array
unsigned unflaggedIndex = 0;
m_unflaggedArray.SetCount(unflaggedCount);
for (loop = 0; loop < defCount; ++loop)
if (CheckFlag(def[loop].flags, kCmdArgRequired, kCmdMaskArg))
m_unflaggedArray[unflaggedIndex++] = loop;
m_requiredCount = unflaggedIndex;
for (loop = 0; loop < defCount; ++loop)
if (!(CheckFlag(def[loop].flags, kCmdArgFlagged, kCmdMaskArg) ||
CheckFlag(def[loop].flags, kCmdArgRequired, kCmdMaskArg)))
m_unflaggedArray[unflaggedIndex++] = loop;
}
//===========================================================================
void CICmdParser::Error (const CmdTokState * state, ECmdError errorCode, const wchar_t arg[], const wchar_t value[]) const {
// Compose the error text
// (This text is only provided as a shortcut for trivial applications that
// don't want to compose their own text. Normally, an application would
// compose error text using its own localized strings.)
unsigned chars = 256 + (arg ? StrLen(arg) : 0) + (value ? StrLen(value) : 0);
wchar_t * buffer = (wchar_t *)malloc(chars * sizeof(wchar_t));
switch (errorCode) {
case kCmdErrorInvalidArg:
StrPrintf(buffer, chars, L"Invalid argument: %s", arg);
break;
case kCmdErrorInvalidValue:
StrPrintf(buffer, chars, L"Argument %s invalid value: %s", arg, value);
break;
case kCmdErrorTooFewArgs:
StrPrintf(buffer, chars, L"Too few arguments");
break;
case kCmdErrorTooManyArgs:
StrPrintf(buffer, chars, L"Too many arguments: %s", arg);
break;
DEFAULT_FATAL(errorCode);
}
// Call the error handler
state->parser->OnError(buffer, errorCode, arg, value);
// Free memory
free(buffer);
}
//===========================================================================
const CmdArgData * CICmdParser::FindArgById (unsigned id) const {
// Search for the argument with this id
unsigned index;
if (id < m_idLookupArray.Count())
index = m_idLookupArray[id];
else
for (index = 0; index < m_argArray.Count(); ++index)
if (m_argArray[index].def.id == id)
break;
// Verify that we found the correct argument
if ( (index >= m_argArray.Count()) ||
(m_argArray[index].def.id != id) )
return nil;
// Return the argument data
return &m_argArray[index];
}
//===========================================================================
const CmdArgData * CICmdParser::FindArgByName (const wchar_t name[]) const {
// Search for an argument with this name
unsigned index = (unsigned)-1;
if (!LookupFlagged(&name, &index))
return nil;
// Return the argument data
return &m_argArray[index];
}
//===========================================================================
bool CICmdParser::LookupFlagged (const wchar_t ** name, unsigned * lastIndex) const {
unsigned argCount = m_argArray.Count();
unsigned chars = StrLen(*name);
unsigned bestIndex = (unsigned)-1;
unsigned bestChars = 0;
// Check whether this argument is a suffix to any previously
// provided prefix in this token
for (unsigned prevChars = (*lastIndex != (unsigned)-1) ? m_argArray[*lastIndex].nameChars : 0;
(prevChars != (unsigned)-1) && !bestChars;
--prevChars) {
const CmdArgData & prev = prevChars ? m_argArray[*lastIndex] : *(const CmdArgData *)nil;
// Find this argument in the list
for (unsigned index = 0; index < argCount; ++index) {
const CmdArgData & arg = m_argArray[index];
// Ignore non-flagged arguments
if (!CheckFlag(arg.def.flags, kCmdArgFlagged, kCmdMaskArg))
continue;
// Ignore this argument if it wouldn't beat the previous best match
if (arg.nameChars < bestChars + prevChars)
continue;
// Ignore this argument if it doesn't match the prefix
bool caseSensitive = CheckFlag(arg.def.flags, kCmdCaseSensitive, kCmdCaseSensitive);
if ( prevChars &&
( (prevChars >= arg.nameChars) ||
( caseSensitive && StrCmp(arg.def.name, prev.def.name, prevChars)) ||
(!caseSensitive && StrCmpI(arg.def.name, prev.def.name, prevChars)) ) )
continue;
// Ignore this argument if it doesn't match the suffix
if ( ( caseSensitive && StrCmp(*name, arg.def.name + prevChars, arg.nameChars - prevChars)) ||
(!caseSensitive && StrCmpI(*name, arg.def.name + prevChars, arg.nameChars - prevChars)) )
continue;
// Track the best match
bestIndex = index;
bestChars = arg.nameChars - prevChars;
if (bestChars == chars)
break;
}
}
// Return the result
*name += bestChars;
*lastIndex = bestIndex;
return (bestChars != 0);
}
//===========================================================================
bool CICmdParser::ProcessValue (CmdTokState * state, unsigned index, const wchar_t str[]) {
CmdArgData & arg = m_argArray[index];
arg.isSpecified = true;
unsigned argType = arg.def.flags & kCmdMaskType;
switch (argType) {
case kCmdTypeBool:
if (*str == '+')
arg.val.boolVal = true;
else if (*str == '-')
arg.val.boolVal = false;
else if (!*str)
arg.val.boolVal = CheckFlag(arg.def.flags, kCmdBoolSet, kCmdMaskBool);
else
Error(state, kCmdErrorInvalidValue, arg.def.name, str);
break;
case kCmdTypeFloat:
{
const wchar_t * endPtr;
arg.val.floatVal = StrToFloat(str, &endPtr);
if (*endPtr)
Error(state, kCmdErrorInvalidValue, arg.def.name, str);
}
break;
case kCmdTypeInt:
{
const wchar_t * endPtr;
arg.val.intVal = StrToInt(str, &endPtr);
if (*endPtr)
Error(state, kCmdErrorInvalidValue, arg.def.name, str);
}
break;
case kCmdTypeString:
if (arg.buffer)
free(arg.buffer);
arg.buffer = StrDup(str);
arg.val.strVal = arg.buffer;
break;
case kCmdTypeUnsigned:
{
const wchar_t * endPtr;
arg.val.unsignedVal = StrToUnsigned(str, &endPtr, 10);
if (*endPtr)
Error(state, kCmdErrorInvalidValue, arg.def.name, str);
}
break;
DEFAULT_FATAL(argType);
}
return true;
}
//===========================================================================
void CICmdParser::SetDefaultValue (CmdArgData & arg) {
unsigned argType = arg.def.flags & kCmdMaskType;
switch (argType) {
case kCmdTypeBool:
arg.val.boolVal = !CheckFlag(arg.def.flags, kCmdBoolSet, kCmdMaskBool);
break;
case kCmdTypeInt:
arg.val.intVal = 0;
break;
case kCmdTypeUnsigned:
arg.val.unsignedVal = 0;
break;
case kCmdTypeFloat:
arg.val.floatVal = 0.0f;
break;
case kCmdTypeString:
arg.val.strVal = L"";
break;
DEFAULT_FATAL(argType);
}
}
//===========================================================================
bool CICmdParser::Tokenize (CmdTokState * state, const wchar_t str[]) {
wchar_t buffer[kMaxTokenLength];
bool result = true;
while (result && StrTokenize(&str, buffer, arrsize(buffer), WHITESPACE)) {
// If the previous argument is awaiting a value, then use this token
// as the value
if (state->pendingIndex != (unsigned)-1) {
result = ProcessValue(state, state->pendingIndex, buffer);
state->pendingIndex = (unsigned)-1;
continue;
}
// Identify and process flagged parameters
if (StrChr(FLAGS, buffer[0]) && TokenizeFlags(state, buffer))
continue;
// Process unflagged parameters
if (state->unflaggedIndex < m_unflaggedArray.Count()) {
result = ProcessValue(state, m_unflaggedArray[state->unflaggedIndex++], buffer);
continue;
}
// Process extra parameters
if (state->parser->OnExtra(buffer))
continue;
// Process invalid parameters
Error(state, kCmdErrorTooManyArgs, buffer, nil);
result = false;
break;
}
return result;
}
//===========================================================================
bool CICmdParser::TokenizeFlags (CmdTokState * state, const wchar_t str[]) {
// Process each separately flagged token within the string
wchar_t buffer[kMaxTokenLength];
bool result = true;
while (result && StrTokenize(&str, buffer, arrsize(buffer), ALL)) {
if (!buffer[0])
continue;
// Process each flag within the token
unsigned lastIndex = (unsigned)-1;
const wchar_t * bufferPtr = buffer;
while (result) {
// Lookup the argument name
result = LookupFlagged(&bufferPtr, &lastIndex);
if (!result) {
Error(state, kCmdErrorInvalidArg, bufferPtr, nil);
result = false;
break;
}
// If this argument is boolean, allow it to share a common prefix
// with the next argument. In this case there is no place for
// the user to provide a value, so use the default value.
if (*bufferPtr &&
CheckFlag(m_argArray[lastIndex].def.flags, kCmdTypeBool, kCmdMaskType)) {
result = ProcessValue(state, lastIndex, L"");
continue;
}
break;
}
if (!result)
break;
// Check for an argument value provided using a separator
if (*str && StrChr(SEPARATORS, *str)) {
result = ProcessValue(state, lastIndex, str + 1);
break;
}
// Process values for boolean arguments
if (CheckFlag(m_argArray[lastIndex].def.flags, kCmdTypeBool, kCmdMaskType)) {
// Check for a value provided with a toggle
if (*str && StrChr(TOGGLES, *str)) {
wchar_t tempStr[] = {*str, 0};
result = ProcessValue(state, lastIndex, tempStr);
++str;
continue;
}
// Check for a default value
else {
result = ProcessValue(state, lastIndex, L"");
continue;
}
}
// Process values for non-boolean arguments
else {
// Check for an argument value immediately following the name
if (*bufferPtr) {
result = ProcessValue(state, lastIndex, bufferPtr);
break;
}
// Check for an argument value in the next token
else {
state->pendingIndex = lastIndex;
break;
}
}
}
return result;
}
/*****************************************************************************
*
* CCmdParser implementation
*
***/
//===========================================================================
CCmdParser::CCmdParser () {
fParser = nil;
}
//===========================================================================
CCmdParser::CCmdParser (const CmdArgDef def[], unsigned defCount) {
Initialize(def, defCount);
}
//===========================================================================
CCmdParser::~CCmdParser () {
delete fParser;
}
//===========================================================================
bool CCmdParser::GetBool (unsigned id) const {
return fParser->FindArgById(id)->val.boolVal;
}
//===========================================================================
bool CCmdParser::GetBool (const wchar_t name[]) const {
return fParser->FindArgByName(name)->val.boolVal;
}
//===========================================================================
float CCmdParser::GetFloat (unsigned id) const {
return fParser->FindArgById(id)->val.floatVal;
}
//===========================================================================
float CCmdParser::GetFloat (const wchar_t name[]) const {
return fParser->FindArgByName(name)->val.floatVal;
}
//===========================================================================
int CCmdParser::GetInt (unsigned id) const {
return fParser->FindArgById(id)->val.intVal;
}
//===========================================================================
int CCmdParser::GetInt (const wchar_t name[]) const {
return fParser->FindArgByName(name)->val.intVal;
}
//===========================================================================
const wchar_t * CCmdParser::GetString (unsigned id) const {
return fParser->FindArgById(id)->val.strVal;
}
//===========================================================================
const wchar_t * CCmdParser::GetString (const wchar_t name[]) const {
return fParser->FindArgByName(name)->val.strVal;
}
//===========================================================================
unsigned CCmdParser::GetUnsigned (unsigned id) const {
return fParser->FindArgById(id)->val.unsignedVal;
}
//===========================================================================
unsigned CCmdParser::GetUnsigned (const wchar_t name[]) const {
return fParser->FindArgByName(name)->val.unsignedVal;
}
//===========================================================================
void CCmdParser::Initialize (const CmdArgDef def[], unsigned defCount) {
fParser = new CICmdParser(def, defCount);
}
//===========================================================================
bool CCmdParser::IsSpecified (unsigned id) const {
if (const CmdArgData * data = fParser->FindArgById(id))
return data->isSpecified;
return false;
}
//===========================================================================
bool CCmdParser::IsSpecified (const wchar_t name[]) const {
if (const CmdArgData * data = fParser->FindArgByName(name))
return data->isSpecified;
return false;
}
//===========================================================================
void CCmdParser::OnError (const wchar_t str[], ECmdError errorCode, const wchar_t arg[], const wchar_t value[]) {
}
//===========================================================================
bool CCmdParser::OnExtra (const wchar_t str[]) {
return false;
}
//===========================================================================
bool CCmdParser::Parse (const wchar_t cmdLine[]) {
// If no command line was passed, use the application's command line,
// skipping past the program name
if (!cmdLine) {
cmdLine = AppGetCommandLine();
StrTokenize(&cmdLine, nil, 0, WHITESPACE);
while (*cmdLine == L' ')
++cmdLine;
}
// Process the command line
CmdTokState state = {
this,
(unsigned)-1, // pending index
0 // unflagged index
};
bool result;
result = fParser->Tokenize(&state, cmdLine);
if (result)
result = fParser->CheckAllRequiredArguments(&state);
return result;
}

136
Sources/Plasma/NucleusLib/pnUtils/pnUtCmd.h

@ -1,136 +0,0 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtCmd.h
*
***/
#ifndef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTCMD_H
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTCMD_H
#include "Pch.h"
#include "pnUtArray.h"
#include "pnUtStr.h"
/*****************************************************************************
*
* Constants
*
***/
// Sets of mutually exclusive flags
const unsigned kCmdArgFlagged = 0x0 << 0; // default
const unsigned kCmdArgOptional = 0x1 << 0;
const unsigned kCmdArgRequired = 0x2 << 0;
const unsigned kCmdMaskArg = 0xf << 0;
const unsigned kCmdTypeBool = 0x0 << 4; // default
const unsigned kCmdTypeInt = 0x1 << 4;
const unsigned kCmdTypeUnsigned = 0x2 << 4;
const unsigned kCmdTypeFloat = 0x3 << 4;
const unsigned kCmdTypeString = 0x4 << 4;
const unsigned kCmdMaskType = 0xf << 4;
const unsigned kCmdBoolSet = 0x0 << 8; // default
const unsigned kCmdBoolUnset = 0x1 << 8;
const unsigned kCmdMaskBool = 0xf << 8;
// Other flags
const unsigned kCmdCaseSensitive = 0x1 << 28;
// Error codes
enum ECmdError {
kCmdErrorInvalidArg,
kCmdErrorInvalidValue,
kCmdErrorTooFewArgs,
kCmdErrorTooManyArgs,
kNumCmdErrors
};
/*****************************************************************************
*
* Types
*
***/
struct CmdArgDef {
unsigned flags;
const wchar_t * name; // must be compile-time constant
unsigned id;
};
class CCmdParser {
class CICmdParser * fParser;
static void DispatchError (const wchar_t str[], ECmdError errorCode, const wchar_t arg[], const wchar_t value[], void * param);
static bool DispatchExtra (const wchar_t str[], void * param);
protected:
CCmdParser ();
void Initialize (const CmdArgDef def[], unsigned defCount);
public:
CCmdParser (const CmdArgDef def[], unsigned defCount);
virtual ~CCmdParser ();
bool GetBool (unsigned id) const;
bool GetBool (const wchar_t name[]) const;
float GetFloat (unsigned id) const;
float GetFloat (const wchar_t name[]) const;
int GetInt (unsigned id) const;
int GetInt (const wchar_t name[]) const;
const wchar_t * GetString (unsigned id) const;
const wchar_t * GetString (const wchar_t name[]) const;
unsigned GetUnsigned (unsigned id) const;
unsigned GetUnsigned (const wchar_t name[]) const;
bool IsSpecified (unsigned id) const;
bool IsSpecified (const wchar_t name[]) const;
virtual void OnError (const wchar_t str[], ECmdError errorCode, const wchar_t arg[], const wchar_t value[]);
virtual bool OnExtra (const wchar_t str[]);
bool Parse (const wchar_t cmdLine[] = nil);
};
#endif

91
Sources/Plasma/NucleusLib/pnUtils/pnUtMisc.cpp

@ -1,91 +0,0 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtMisc.cpp
*
***/
#include "pnUtMisc.h"
/*****************************************************************************
*
* Private data
*
***/
static void * s_moduleInstance;
/*****************************************************************************
*
* Public functions
*
***/
//============================================================================
void ModuleSetInstance (void * instance) {
s_moduleInstance = instance;
}
//============================================================================
void * ModuleGetInstance () {
return s_moduleInstance;
}
/*****************************************************************************
*
* Dll initialization
*
***/
//============================================================================
#if HS_BUILD_FOR_WIN32
BOOL WINAPI PreDllMain (HANDLE handle, DWORD reason, LPVOID) {
if (reason == DLL_PROCESS_ATTACH) {
ModuleSetInstance(handle);
}
return true;
}
#endif

72
Sources/Plasma/NucleusLib/pnUtils/pnUtMisc.h

@ -1,72 +0,0 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtMisc.h
*
***/
#ifndef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTMISC_H
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTMISC_H
#include "Pch.h"
#include "pnUtArray.h"
/*****************************************************************************
*
* Module instance functions
*
***/
void ModuleSetInstance (void * instance);
void * ModuleGetInstance ();
/*****************************************************************************
*
* Command line functions
*
***/
const wchar_t * AppGetCommandLine ();
#endif

169
Sources/Plasma/NucleusLib/pnUtils/pnUtStr.cpp

@ -98,16 +98,6 @@ static chartype * IStrDup (const chartype str[]) {
return buffer;
}
//===========================================================================
template<class chartype, class findchartype>
static chartype * IStrChr (chartype * str, findchartype ch, unsigned chars) {
for (; chars--; ++str)
if (*str == ch)
return str;
else if (!*str)
break;
return nil;
}
//===========================================================================
template<typename chartype>
@ -179,85 +169,6 @@ static uint32_t IStrHashI (const chartype str[], unsigned chars) {
return result;
}
//===========================================================================
template<class chartype>
static bool IStrTokenize (const chartype * source[], chartype * dest, unsigned chars, const chartype whitespace[], unsigned maxWhitespaceSkipCount) {
// Skip past leading whitespace
bool inQuotes = false;
unsigned whitespaceSkipped = 0;
while (**source && IStrChr(whitespace, **source, (unsigned)-1) && whitespaceSkipped < maxWhitespaceSkipCount) {
inQuotes = (**source == '\"');
++*source;
++whitespaceSkipped;
if (inQuotes)
break;
}
// Copy the token
unsigned offset = 0;
while (**source &&
((inQuotes && (**source != '\"')) || !IStrChr(whitespace, **source, (unsigned)-1))) {
if (offset + 1 < chars)
dest[offset++] = **source;
++*source;
}
// Skip past the terminating quote
if (inQuotes && (**source == '\"'))
++*source;
// Null terminate the destination buffer
if (chars) {
ASSERT(offset < chars);
dest[offset] = 0;
}
// Upon return, 'source' is guaranteed to point to the first character
// following the returned token (and following any closing quotes)
return (offset || inQuotes);
}
//===========================================================================
template<class chartype>
static bool IStrTokenize (const chartype * source[], ARRAY(chartype) * destArray, const chartype whitespace[], unsigned maxWhitespaceSkipCount) {
// Verify that the destination array is empty
ASSERT(!destArray->Count());
// Skip past leading whitespace
bool inQuotes = false;
unsigned whitespaceSkipped = 0;
while (**source && IStrChr(whitespace, **source, (unsigned)-1) && whitespaceSkipped < maxWhitespaceSkipCount) {
inQuotes = (**source == '\"');
++*source;
++whitespaceSkipped;
if (inQuotes)
break;
}
// Copy the token
bool added = false;
while (**source &&
((inQuotes && (**source != '\"')) || !IStrChr(whitespace, **source, (unsigned)-1))) {
destArray->Add(**source);
added = true;
++*source;
}
// Skip past the terminating quote
if (inQuotes && (**source == '\"'))
++*source;
// Null terminate the destination array
destArray->Add(0);
// Upon return, 'source' is guaranteed to point to the first character
// following the returned token (and following any closing quotes)
return (added || inQuotes);
}
/****************************************************************************
@ -276,26 +187,6 @@ wchar_t * StrDup (const wchar_t str[]) {
return IStrDup(str);
}
//===========================================================================
char * StrChr (char * str, char ch, unsigned chars) {
return IStrChr(str, ch, chars);
}
//===========================================================================
wchar_t * StrChr (wchar_t * str, wchar_t ch, unsigned chars) {
return IStrChr(str, ch, chars);
}
//===========================================================================
const char * StrChr (const char str[], char ch, unsigned chars) {
return IStrChr(str, ch, chars);
}
//===========================================================================
const wchar_t * StrChr (const wchar_t str[], wchar_t ch, unsigned chars) {
return IStrChr(str, ch, chars);
}
//===========================================================================
unsigned StrPrintf (char * dest, unsigned count, const char format[], ...) {
va_list argList;
@ -366,46 +257,6 @@ unsigned StrLen (const wchar_t str[]) {
return IStrLen(str);
}
//===========================================================================
float StrToFloat (const char source[], const char ** endptr) {
return (float) strtod(source, const_cast<char **>(endptr));
}
//===========================================================================
float StrToFloat (const wchar_t source[], const wchar_t ** endptr) {
return (float) wcstod(source, const_cast<wchar_t **>(endptr));
}
//===========================================================================
int StrToInt (const char source[], const char ** endptr) {
return strtol(source, const_cast<char **>(endptr), 0);
}
//===========================================================================
int StrToInt (const wchar_t source[], const wchar_t ** endptr) {
return wcstol(source, const_cast<wchar_t **>(endptr), 0);
}
//===========================================================================
unsigned StrToUnsigned (char source[], char ** endptr, int radix) {
return strtoul(source, const_cast<char **>(endptr), radix);
}
//===========================================================================
unsigned StrToUnsigned (wchar_t source[], wchar_t ** endptr, int radix) {
return wcstoul(source, const_cast<wchar_t **>(endptr), radix);
}
//===========================================================================
unsigned StrToUnsigned (const char source[], const char ** endptr, int radix) {
return strtoul(source, const_cast<char **>(endptr), radix);
}
//===========================================================================
unsigned StrToUnsigned (const wchar_t source[], const wchar_t ** endptr, int radix) {
return wcstoul(source, const_cast<wchar_t **>(endptr), radix);
}
//===========================================================================
uint32_t StrHash (const char str[], unsigned chars) {
return IStrHash(str, chars);
@ -425,23 +276,3 @@ uint32_t StrHashI (const char str[], unsigned chars) {
uint32_t StrHashI (const wchar_t str[], unsigned chars) {
return IStrHashI(str, chars);
}
//===========================================================================
bool StrTokenize (const char * source[], char * dest, unsigned chars, const char whitespace[], unsigned maxWhitespaceSkipCount) {
return IStrTokenize(source, dest, chars, whitespace, maxWhitespaceSkipCount);
}
//===========================================================================
bool StrTokenize (const wchar_t * source[], wchar_t * dest, unsigned chars, const wchar_t whitespace[], unsigned maxWhitespaceSkipCount) {
return IStrTokenize(source, dest, chars, whitespace, maxWhitespaceSkipCount);
}
//===========================================================================
bool StrTokenize (const char * source[], ARRAY(char) * destArray, const char whitespace[], unsigned maxWhitespaceSkipCount) {
return IStrTokenize(source, destArray, whitespace, maxWhitespaceSkipCount);
}
//===========================================================================
bool StrTokenize (const wchar_t * source[], ARRAY(wchar_t) * destArray, const wchar_t whitespace[], unsigned maxWhitespaceSkipCount) {
return IStrTokenize(source, destArray, whitespace, maxWhitespaceSkipCount);
}

22
Sources/Plasma/NucleusLib/pnUtils/pnUtStr.h

@ -55,7 +55,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
// Got Damn eap...
// Duplicate Symbols in shlwapi!
#ifdef _INC_SHLWAPI
# undef StrChr
# undef StrDup
#endif // _INC_SHLWAPI
@ -68,11 +67,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
inline char CharLowerFast (char ch) { return ((ch >= 'A') && (ch <= 'Z')) ? (char )(ch + 'a' - 'A') : ch; }
inline wchar_t CharLowerFast (wchar_t ch) { return ((ch >= L'A') && (ch <= L'Z')) ? (wchar_t)(ch + L'a' - L'A') : ch; }
char * StrChr (char * str, char ch, unsigned chars = (unsigned)-1);
wchar_t * StrChr (wchar_t * str, wchar_t ch, unsigned chars = (unsigned)-1);
const char * StrChr (const char str[], char ch, unsigned chars = (unsigned)-1);
const wchar_t * StrChr (const wchar_t str[], wchar_t ch, unsigned chars = (unsigned)-1);
unsigned StrPrintf (char * dest, unsigned count, const char format[], ...);
unsigned StrPrintf (wchar_t * dest, unsigned count, const wchar_t format[], ...);
@ -94,25 +88,9 @@ int StrCmpI (const wchar_t str1[], const wchar_t str2[], unsigned chars = (unsig
void StrCopy (char * dest, const char source[], unsigned chars);
void StrCopy (wchar_t * dest, const wchar_t source[], unsigned chars);
float StrToFloat (const char source[], const char ** endptr);
float StrToFloat (const wchar_t source[], const wchar_t ** endptr);
int StrToInt (const char source[], const char ** endptr);
int StrToInt (const wchar_t source[], const wchar_t ** endptr);
unsigned StrToUnsigned (char source[], char ** endptr, int radix);
unsigned StrToUnsigned (wchar_t source[], wchar_t ** endptr, int radix);
unsigned StrToUnsigned (const char source[], const char ** endptr, int radix);
unsigned StrToUnsigned (const wchar_t source[], const wchar_t ** endptr, int radix);
uint32_t StrHash (const char str[], unsigned chars = (unsigned)-1);
uint32_t StrHash (const wchar_t str[], unsigned chars = (unsigned)-1);
uint32_t StrHashI (const char str[], unsigned chars = (unsigned)-1);
uint32_t StrHashI (const wchar_t str[], unsigned chars = (unsigned)-1);
bool StrTokenize (const char * source[], char * dest, unsigned chars, const char whitespace[], unsigned maxWhitespaceSkipCount = (unsigned)-1);
bool StrTokenize (const wchar_t * source[], wchar_t * dest, unsigned chars, const wchar_t whitespace[], unsigned maxWhitespaceSkipCount = (unsigned)-1);
bool StrTokenize (const char * source[], ARRAY(char) * destArray, const char whitespace[], unsigned maxWhitespaceSkipCount = (unsigned)-1);
bool StrTokenize (const wchar_t * source[], ARRAY(wchar_t) * destArray, const wchar_t whitespace[], unsigned maxWhitespaceSkipCount = (unsigned)-1);
#endif

1
Sources/Tests/CoreTests/CMakeLists.txt

@ -4,6 +4,7 @@ include_directories(../../Plasma/CoreLib)
SET(CoreLibTest_SOURCES
test_plString.cpp
test_plCmdParser.cpp
)
add_executable(test_CoreLib ${CoreLibTest_SOURCES})

547
Sources/Tests/CoreTests/test_plCmdParser.cpp

@ -0,0 +1,547 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include <cstring>
#include <gtest/gtest.h>
#include "plCmdParser.h"
TEST(plCmdParser, basic_parsing)
{
const plCmdArgDef cmds[] = {
{ kCmdArgRequired | kCmdTypeString, "path", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
bool success = parser.Parse("plCmdParser ~/.plasma/config.dat");
plString prog = parser.GetProgramName();
plString path = parser.GetString(0);
EXPECT_EQ(success, true);
EXPECT_STREQ(prog.c_str(), "plCmdParser");
EXPECT_STREQ(path.c_str(), "~/.plasma/config.dat");
EXPECT_EQ(parser.GetError(), kCmdErrorSuccess);
}
TEST(plCmdParser, argv_parsing)
{
const plCmdArgDef cmds[] = {
{ kCmdArgRequired | kCmdTypeString, "path", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
const char* args[] = {"plCmdParser", "~/.plasma/config.dat"};
int argc = 2;
std::vector<plString> tokens(args, args+argc);
bool success = parser.Parse(tokens);
plString prog = parser.GetProgramName();
plString path = parser.GetString(0);
EXPECT_EQ(success, true);
EXPECT_STREQ(prog.c_str(), "plCmdParser");
EXPECT_STREQ(path.c_str(), "~/.plasma/config.dat");
EXPECT_EQ(parser.GetError(), kCmdErrorSuccess);
}
TEST(plCmdParser, argv_preserving_spaces)
{
const plCmdArgDef cmds[] = {
{ kCmdArgRequired | kCmdTypeString, "path", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
const char* args[] = {"plCmdParser", "~/.plasma/Uru Live/config.dat"};
int argc = 2;
std::vector<plString> tokens(args, args+argc);
bool success = parser.Parse(tokens);
plString prog = parser.GetProgramName();
plString path = parser.GetString(0);
EXPECT_EQ(success, true);
EXPECT_STREQ(prog.c_str(), "plCmdParser");
EXPECT_STREQ(path.c_str(), "~/.plasma/Uru Live/config.dat");
EXPECT_EQ(parser.GetError(), kCmdErrorSuccess);
}
TEST(plCmdParser, wchar_argv_parsing)
{
const plCmdArgDef cmds[] = {
{ kCmdArgRequired | kCmdTypeString, "path", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
const wchar_t* args[] = {L"plCmdParser", L"~/.plasma/config.dat"};
int argc = 2;
std::vector<plString> tokens(argc);
for (int i = 0; i < argc; i++) {
tokens.push_back(plString::FromWchar(args[i]));
}
bool success = parser.Parse(tokens);
plString prog = parser.GetProgramName();
plString path = parser.GetString(0);
EXPECT_EQ(success, true);
EXPECT_STREQ(prog.c_str(), "plCmdParser");
EXPECT_STREQ(path.c_str(), "~/.plasma/config.dat");
EXPECT_EQ(parser.GetError(), kCmdErrorSuccess);
}
TEST(plCmdParser, flagged_int)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --size 5");
int32_t size = parser.GetInt(0);
EXPECT_EQ(size, 5);
}
TEST(plCmdParser, flagged_int_short)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser -s 5");
int32_t size = parser.GetInt(0);
EXPECT_EQ(size, 5);
}
TEST(plCmdParser, flagged_int_assign)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --size=5");
int32_t size = parser.GetInt(0);
EXPECT_EQ(size, 5);
}
TEST(plCmdParser, flagged_int_slash)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser /size -5");
int32_t size = parser.GetInt(0);
EXPECT_EQ(size, -5);
}
TEST(plCmdParser, flagged_int_bystring)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --size 5");
int32_t size = parser.GetInt("size");
EXPECT_EQ(size, 5);
}
TEST(plCmdParser, flagged_uint)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeUint, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --size 5");
uint32_t size = parser.GetUint(0);
EXPECT_EQ(size, 5);
}
TEST(plCmdParser, flagged_uint_bystring)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeUint, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --size 5");
uint32_t size = parser.GetUint("size");
EXPECT_EQ(size, 5);
}
TEST(plCmdParser, flagged_float)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeFloat, "volume", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --volume 0.5");
float vol = parser.GetFloat(0);
EXPECT_EQ(vol, 0.5);
}
TEST(plCmdParser, flagged_float_bystring)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeFloat, "volume", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --volume 0.5");
float vol = parser.GetFloat("volume");
EXPECT_EQ(vol, 0.5);
}
TEST(plCmdParser, flagged_string)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeString, "path", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --path foo");
plString path = parser.GetString(0);
EXPECT_STREQ(path.c_str(), "foo");
}
TEST(plCmdParser, flagged_string_bystring)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeString, "path", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --path foo");
plString path = parser.GetString("path");
EXPECT_STREQ(path.c_str(), "foo");
}
TEST(plCmdParser, flagged_bool_default)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeBool, "verbose", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --verbose");
bool verbose = parser.GetBool(0);
EXPECT_EQ(verbose, true);
}
TEST(plCmdParser, flagged_bool_true)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeBool, "verbose", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --verbose=TRUE");
bool verbose = parser.GetBool(0);
EXPECT_EQ(verbose, true);
}
TEST(plCmdParser, flagged_bool_false)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeBool, "verbose", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --verbose=FALSE");
bool verbose = parser.GetBool(0);
EXPECT_EQ(verbose, false);
}
TEST(plCmdParser, flagged_bool_invalid)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeBool, "verbose", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --verbose=foo");
bool verbose = parser.GetBool(0);
EXPECT_EQ(verbose, false);
EXPECT_EQ(parser.GetError(), kCmdErrorInvalidValue);
}
TEST(plCmdParser, flagged_bool_bystring)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeBool, "verbose", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --verbose");
bool verbose = parser.GetBool("verbose");
EXPECT_EQ(verbose, true);
}
TEST(plCmdParser, optional_unspecified)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt | kCmdArgOptional, "speed", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser");
bool specified = parser.IsSpecified(0);
int32_t speed = parser.GetInt(0);
EXPECT_EQ(specified, false);
EXPECT_EQ(speed, 0);
}
TEST(plCmdParser, optional_specified)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt | kCmdArgOptional, "speed", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser 1");
bool specified = parser.IsSpecified(0);
int32_t speed = parser.GetInt(0);
EXPECT_EQ(specified, true);
EXPECT_EQ(speed, 1);
}
TEST(plCmdParser, optional_specified_bystring)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt | kCmdArgOptional, "speed", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser 1");
bool specified = parser.IsSpecified("speed");
int32_t speed = parser.GetInt("speed");
EXPECT_EQ(specified, true);
EXPECT_EQ(speed, 1);
}
TEST(plCmdParser, specified_invalid)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt | kCmdArgOptional, "speed", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser 1");
bool specified = parser.IsSpecified(1);
EXPECT_EQ(specified, false);
}
TEST(plCmdParser, specified_invalid_bystring)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt | kCmdArgOptional, "speed", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser 1");
bool specified = parser.IsSpecified("path");
EXPECT_EQ(specified, false);
}
TEST(plCmdParser, flagged_weird_id)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt, "size", 10}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --size 5");
int32_t size = parser.GetInt(10);
EXPECT_EQ(size, 5);
}
TEST(plCmdParser, fake_flag)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
bool success = parser.Parse("plCmdParser --speed 5");
EXPECT_EQ(success, false);
EXPECT_EQ(parser.GetError(), kCmdErrorInvalidArg);
}
TEST(plCmdParser, too_many_args)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
bool success = parser.Parse("plCmdParser --size 10 foo");
EXPECT_EQ(success, false);
EXPECT_EQ(parser.GetError(), kCmdErrorTooManyArgs);
}
TEST(plCmdParser, missing_required)
{
const plCmdArgDef cmds[] = {
{ kCmdArgRequired | kCmdTypeString, "path", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
bool success = parser.Parse("plCmdParser");
EXPECT_EQ(success, false);
EXPECT_EQ(parser.GetError(), kCmdErrorTooFewArgs);
}
TEST(plCmdParser, combined_assign)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt, "size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser --size5");
int32_t size = parser.GetInt(0);
EXPECT_EQ(size, 5);
}
TEST(plCmdParser, case_sensitive_nomatch)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt | kCmdCaseSensitive, "Size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser -s 5");
bool specified = parser.IsSpecified(0);
EXPECT_EQ(specified, false);
}
TEST(plCmdParser, case_sensitive_match)
{
const plCmdArgDef cmds[] = {
{ kCmdTypeInt | kCmdCaseSensitive, "Size", 0}
};
plCmdParser parser(cmds, arrsize(cmds));
parser.Parse("plCmdParser -S 5");
bool specified = parser.IsSpecified(0);
EXPECT_EQ(specified, true);
}
Loading…
Cancel
Save