CommandLine.h#
↰ Parent directory (commandline
)
Contains the CommandLine class.
Includes#
algorithm
cstdint
cstdlib
cstring
malloc.h
sstream
string
(CompileTimeHash.h)vector
Included By#
Namespaces#
Classes#
Defines#
Typedefs#
Source Code#
#pragma once
#include <vector>
#include <sstream>
#include <string>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#if !defined(__APPLE__)
#include <malloc.h>
#endif
#if !defined(_WIN32)
#define _stricmp strcasecmp
#endif
namespace pvr {
namespace platform {
class CommandLineParser
{
public:
class ParsedCommandLine
{
public:
ParsedCommandLine() = default;
ParsedCommandLine(int argc, char** argv)
{
CommandLineParser parser(argc, argv);
*this = parser.getParsedCommandLine();
}
struct Option
{
const char* arg;
const char* val;
bool operator==(const Option& rhs) const { return strcmp(arg, rhs.arg) == 0; }
bool operator==(const char* rhs) const { return strcmp(arg, rhs) == 0; }
};
typedef std::vector<Option> Options;
const Options& getOptionsList() const { return _options; }
bool hasOption(const char* name) const { return std::find(_options.begin(), _options.end(), name) != _options.end(); }
bool getStringOption(const char* name, std::string& outValue) const
{
auto it = std::find(_options.begin(), _options.end(), name);
if (it == _options.end()) { return false; }
outValue = it->val;
return true;
}
bool getStringOptionList(const char* name, std::vector<std::string>& outValues) const
{
std::string tmp;
if (!getStringOption(name, tmp)) { return false; }
if (!tmp.empty())
{
std::istringstream iss(tmp);
std::string output;
while (std::getline(iss, output, ',')) { outValues.emplace_back(output); }
}
return true;
}
bool getFloatOption(const char* name, float& outValue) const
{
auto it = std::find(_options.begin(), _options.end(), name);
if (it == _options.end() || it->val == NULL) { return false; }
outValue = static_cast<float>(atof(it->val));
return true;
}
bool getIntOption(const char* name, int32_t& outValue) const
{
auto it = std::find(_options.begin(), _options.end(), name);
if (it == _options.end() || it->val == NULL) { return false; }
outValue = atoi(it->val);
return true;
}
bool getBoolOptionSetTrueIfPresent(const char* name, bool& outValue) const
{
auto it = std::find(_options.begin(), _options.end(), name);
if (it == _options.end()) { return false; }
outValue = true;
return true;
}
bool getBoolOptionSetFalseIfPresent(const char* name, bool& outValue) const
{
auto it = std::find(_options.begin(), _options.end(), name);
if (it == _options.end()) { return false; }
outValue = false;
return true;
}
private:
friend class CommandLineParser;
Options _options;
};
CommandLineParser() : _data(0) {}
CommandLineParser(int argc, char** argv) : _data(0) { set(argc, argv); }
const ParsedCommandLine& getParsedCommandLine() const { return _commandLine; }
void set(const wchar_t* cmdLine)
{
if (cmdLine == nullptr) { return; }
size_t length = wcslen(cmdLine) + 1;
std::vector<char> tmp;
tmp.resize(length);
while (length != 0u)
{
--length;
tmp[length] = static_cast<char>(cmdLine[length]);
}
parseCmdLine(tmp.data());
}
void set(int argc, char** argv)
{
if (argc < 0) { return; }
_commandLine._options.clear();
{
size_t length = 0;
for (int i = 0; i < argc; ++i) { length += strlen(argv[i]) + 1; }
_data.resize(length);
}
size_t offset = 0;
for (int i = 0; i < argc; ++i)
{
// length
const size_t length = strlen(argv[i]) + 1;
memcpy(&_data[offset], argv[i], length);
// split into var/arg
parseArgV(&_data[offset]);
offset += length;
}
}
void set(const char* cmdLine) { parseCmdLine(cmdLine); }
void set(const CommandLineParser& cmdLine) { *this = cmdLine; }
void prefix(const wchar_t* cmdLine)
{
if (!_commandLine._options.empty() != 0u)
{
CommandLineParser tmp;
tmp.set(cmdLine);
prefix(tmp);
}
else
{
set(cmdLine);
}
}
void prefix(int argc, char** argv)
{
if (!_commandLine._options.empty() != 0u)
{
CommandLineParser tmp;
tmp.set(argc, argv);
prefix(tmp);
}
else
{
set(argc, argv);
}
}
void prefix(const char* cmdLine)
{
if (!_commandLine._options.empty() != 0u)
{
CommandLineParser tmp;
tmp.set(cmdLine);
prefix(tmp);
}
else
{
return set(cmdLine);
}
}
void prefix(const CommandLineParser& cmdLine)
{
if (cmdLine._commandLine._options.empty()) { return; }
std::vector<char> newData;
newData.resize(_data.size() + cmdLine._data.size());
std::vector<ParsedCommandLine::Option> newOptions;
newOptions.resize(_commandLine._options.size() + cmdLine._commandLine._options.size());
// copy the data
memcpy(newData.data(), cmdLine._data.data(), cmdLine._data.size());
memcpy(&newData[cmdLine._data.size()], _data.data(), _data.size());
// Initialize the options
for (uint32_t i = 0; i < cmdLine._commandLine._options.size(); ++i)
{
newOptions[i].arg = (const char*)((size_t)cmdLine._commandLine._options[i].arg - (size_t)cmdLine._data.data()) + (size_t)newData.data();
newOptions[i].val = (const char*)((size_t)cmdLine._commandLine._options[i].val - (size_t)cmdLine._data.data()) + (size_t)newData.data();
}
for (uint32_t i = 0; i < _commandLine._options.size(); ++i)
{
newOptions[cmdLine._commandLine._options.size() + i].arg =
(const char*)((size_t)_commandLine._options[i].arg - (size_t)_data.data()) + (size_t)newData.data() + cmdLine._data.size();
newOptions[cmdLine._commandLine._options.size() + i].val =
(const char*)((size_t)_commandLine._options[i].val - (size_t)_data.data()) + (size_t)newData.data() + cmdLine._data.size();
}
// Set the variables
_data = newData;
_commandLine._options = newOptions;
}
void append(const wchar_t* cmdLine)
{
if (!_commandLine._options.empty() != 0u)
{
CommandLineParser tmp;
tmp.set(cmdLine);
append(tmp);
}
else
{
set(cmdLine);
}
}
void append(int argc, char** argv)
{
if (!_commandLine._options.empty() != 0u)
{
CommandLineParser tmp;
tmp.set(argc, argv);
append(tmp);
}
else
{
set(argc, argv);
}
}
void append(const char* cmdLine)
{
if (!_commandLine._options.empty() != 0u)
{
CommandLineParser tmp;
tmp.set(cmdLine);
append(tmp);
}
else
{
set(cmdLine);
}
}
void append(const CommandLineParser& cmdLine)
{
if (cmdLine._commandLine._options.empty()) { return; }
std::vector<char> newData;
newData.resize(_data.size() + cmdLine._data.size());
std::vector<ParsedCommandLine::Option> newOptions;
newOptions.resize(_commandLine._options.size() + cmdLine._commandLine._options.size());
// copy the data
memcpy(newData.data(), _data.data(), _data.size());
memcpy(&newData[_data.size()], cmdLine._data.data(), cmdLine._data.size());
// Initialize the options
for (uint32_t i = 0; i < _commandLine._options.size(); ++i)
{
newOptions[i].arg = (const char*)((size_t)_commandLine._options[i].arg - (size_t)_data.data()) + (size_t)newData.data();
newOptions[i].val = (const char*)((size_t)_commandLine._options[i].val - (size_t)_data.data()) + (size_t)newData.data();
}
for (uint32_t i = 0; i < cmdLine._commandLine._options.size(); ++i)
{
newOptions[_commandLine._options.size() + i].arg =
(const char*)((size_t)cmdLine._commandLine._options[i].arg - (size_t)cmdLine._data.data()) + (size_t)newData.data() + _data.size();
newOptions[_commandLine._options.size() + i].val =
(const char*)((size_t)cmdLine._commandLine._options[i].val - (size_t)cmdLine._data.data()) + (size_t)newData.data() + _data.size();
}
// Set the variables
_data = newData;
_commandLine._options = newOptions;
}
protected:
void parseCmdLine(const char* const cmdLine)
{
size_t len;
uint32_t nIn, nOut;
bool bInQuotes;
ParsedCommandLine::Option opt;
if (cmdLine == nullptr) { return; }
// Take a copy of the original
len = strlen(cmdLine) + 1;
// Take a copy to be edited
_data.resize(len);
// Break the command line into options
bInQuotes = false;
opt.arg = nullptr;
opt.val = nullptr;
nIn = static_cast<uint32_t>(-1);
nOut = 0;
do {
++nIn;
if (cmdLine[nIn] == '"') { bInQuotes = !bInQuotes; }
else
{
if (bInQuotes && cmdLine[nIn] != 0)
{
if (opt.arg == nullptr) { opt.arg = &_data[nOut]; }
_data[nOut++] = cmdLine[nIn];
}
else
{
switch (cmdLine[nIn])
{
case '=':
_data[nOut++] = 0;
opt.val = &_data[nOut];
break;
case ' ':
case '\t':
case '\0':
_data[nOut++] = 0;
if ((opt.arg != nullptr) || (opt.val != nullptr))
{
// Add option to list
_commandLine._options.emplace_back(opt);
opt.arg = nullptr;
opt.val = nullptr;
}
break;
default:
if (opt.arg == nullptr) { opt.arg = &_data[nOut]; }
_data[nOut++] = cmdLine[nIn];
break;
}
}
}
} while (cmdLine[nIn] != 0);
}
void parseArgV(char* arg)
{
ParsedCommandLine::Option opt;
size_t j;
// Hunt for an = symbol
for (j = 0; (arg[j] != 0) && arg[j] != '='; ++j) { ; }
opt.arg = arg;
if (arg[j] != 0)
{
// terminate the arg std::string, set value std::string
arg[j] = 0;
opt.val = &arg[j + 1];
}
else
{
// no value specified
opt.val = nullptr;
}
// Add option to list
_commandLine._options.emplace_back(opt);
}
private:
uint32_t findArg(const char* arg) const
{
uint32_t i;
/*
Find an argument, case insensitive. Returns the index of the option
if found, or the number of options if not.
*/
for (i = 0; i < _commandLine._options.size(); ++i)
{
if (_stricmp(_commandLine._options[i].arg, arg) == 0) { break; }
}
return i;
}
bool readFlag(const char* arg, bool& bVal) const
{
uint32_t nIdx = findArg(arg);
if (nIdx == _commandLine._options.size()) { return false; }
// a flag must have no value
bVal = _commandLine._options[nIdx].val != nullptr ? false : true;
return true;
}
bool readUint(const char* arg, uint32_t& val) const
{
uint32_t nIdx = findArg(arg);
if (nIdx == _commandLine._options.size()) { return false; }
val = static_cast<uint32_t>(atoi(_commandLine._options[nIdx].val));
return true;
}
bool readFloat(const char* arg, float& val) const
{
uint32_t nIdx = findArg(arg);
if (nIdx == _commandLine._options.size()) { return false; }
val = static_cast<float>(atof(_commandLine._options[nIdx].val));
return true;
}
std::vector<char> _data;
ParsedCommandLine _commandLine;
};
} // namespace platform
typedef platform::CommandLineParser::ParsedCommandLine CommandLine;
} // namespace pvr