Parse arg refactoring #4124

Implemented argParser class.
This commit is contained in:
Xinyu Hou 2014-10-22 16:35:28 +01:00
parent d2814a423c
commit f9f2d8e8af
8 changed files with 480 additions and 1 deletions

View File

@ -17,11 +17,102 @@
#include "synergy/ArgParser.h" #include "synergy/ArgParser.h"
#include "synergy/App.h"
#include "synergy/ServerArgs.h"
#include "synergy/ClientArgs.h"
#include "synergy/ArgsBase.h" #include "synergy/ArgsBase.h"
#include "base/Log.h" #include "base/Log.h"
CArgsBase* CArgParser::m_argsBase = NULL; CArgsBase* CArgParser::m_argsBase = NULL;
CArgParser::CArgParser(CApp* app) :
m_app(app)
{
}
bool
CArgParser::parseServerArgs(CServerArgs& args, int argc, const char* const* argv)
{
setArgsBase(args);
updateCommonArgs(argv);
for (int i = 1; i < argc; ++i) {
if (parsePlatformArg(args, argc, argv, i)) {
continue;
}
else if (parseGenericArgs(argc, argv, i)) {
continue;
}
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
// save listen address
args.m_synergyAddress = argv[++i];
}
else if (isArg(i, argc, argv, "-c", "--config", 1)) {
// save configuration file path
args.m_configFile = argv[++i];
}
else {
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], args.m_pname));
return false;
}
}
if (checkUnexpectedArgs()) {
return false;
}
return true;
}
bool
CArgParser::parseClientArgs(CClientArgs& args, int argc, const char* const* argv)
{
setArgsBase(args);
updateCommonArgs(argv);
int i;
for (i = 1; i < argc; ++i) {
if (parsePlatformArg(args, argc, argv, i)) {
continue;
}
else if (parseGenericArgs(argc, argv, i)) {
continue;
}
else if (isArg(i, argc, argv, NULL, "--camp")) {
// ignore -- included for backwards compatibility
}
else if (isArg(i, argc, argv, NULL, "--no-camp")) {
// ignore -- included for backwards compatibility
}
else if (isArg(i, argc, argv, NULL, "--yscroll", 1)) {
// define scroll
args.m_yscroll = atoi(argv[++i]);
}
else {
if (i + 1 == argc) {
args.m_synergyAddress = argv[i];
return true;
}
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], args.m_pname));
return false;
}
}
// exactly one non-option argument (server-address)
if (i == argc) {
LOG((CLOG_PRINT "%s: a server address or name is required" BYE,
args.m_pname, args.m_pname));
return false;
}
if (checkUnexpectedArgs()) {
return false;
}
return true;
}
bool bool
CArgParser::parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* const* argv, int& i) CArgParser::parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* const* argv, int& i)
{ {
@ -64,6 +155,105 @@ CArgParser::parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* c
#endif #endif
} }
bool
CArgParser::parseGenericArgs(int argc, const char* const* argv, int& i)
{
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
// change logging level
argsBase().m_logFilter = argv[++i];
}
else if (isArg(i, argc, argv, "-l", "--log", 1)) {
argsBase().m_logFile = argv[++i];
}
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
// not a daemon
argsBase().m_daemon = false;
}
else if (isArg(i, argc, argv, NULL, "--daemon")) {
// daemonize
argsBase().m_daemon = true;
}
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
// save screen name
argsBase().m_name = argv[++i];
}
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
// don't try to restart
argsBase().m_restartable = false;
}
else if (isArg(i, argc, argv, NULL, "--restart")) {
// try to restart
argsBase().m_restartable = true;
}
else if (isArg(i, argc, argv, "-z", NULL)) {
argsBase().m_backend = true;
}
else if (isArg(i, argc, argv, NULL, "--no-hooks")) {
argsBase().m_noHooks = true;
}
else if (isArg(i, argc, argv, "-h", "--help")) {
if (m_app) {
m_app->help();
}
argsBase().m_shouldExit = true;
}
else if (isArg(i, argc, argv, NULL, "--version")) {
if (m_app) {
m_app->version();
}
argsBase().m_shouldExit = true;
}
else if (isArg(i, argc, argv, NULL, "--no-tray")) {
argsBase().m_disableTray = true;
}
else if (isArg(i, argc, argv, NULL, "--ipc")) {
argsBase().m_enableIpc = true;
}
else if (isArg(i, argc, argv, NULL, "--server")) {
// HACK: stop error happening when using portable (synergyp)
}
else if (isArg(i, argc, argv, NULL, "--client")) {
// HACK: stop error happening when using portable (synergyp)
}
else if (isArg(i, argc, argv, NULL, "--crypto-pass")) {
argsBase().m_crypto.m_pass = argv[++i];
argsBase().m_crypto.setMode("cfb");
}
else if (isArg(i, argc, argv, NULL, "--enable-drag-drop")) {
bool useDragDrop = true;
#ifdef WINAPI_XWINDOWS
useDragDrop = false;
LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported on linux."));
#endif
#ifdef WINAPI_MSWINDOWS
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if (osvi.dwMajorVersion < 6) {
useDragDrop = false;
LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported below vista."));
}
#endif
if (useDragDrop) {
argsBase().m_enableDragDrop = true;
}
}
else {
// option not supported here
return false;
}
return true;
}
bool bool
CArgParser::isArg( CArgParser::isArg(
int argi, int argc, const char* const* argv, int argi, int argc, const char* const* argv,
@ -85,3 +275,157 @@ CArgParser::isArg(
// no match // no match
return false; return false;
} }
void
CArgParser::splitCommandString(CString& command, std::vector<CString>& argv)
{
if (command.empty()) {
return ;
}
size_t leftDoubleQuote = 0;
size_t rightDoubleQuote = 0;
searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote);
size_t startPos = 0;
size_t space = command.find(" ", startPos);
while (space != CString::npos) {
bool ignoreThisSpace = false;
// check if the space is between two double quotes
if (space > leftDoubleQuote && space < rightDoubleQuote) {
ignoreThisSpace = true;
}
else if (space > rightDoubleQuote){
searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote, rightDoubleQuote + 1);
}
if (!ignoreThisSpace) {
CString subString = command.substr(startPos, space - startPos);
removeDoubleQuotes(subString);
argv.push_back(subString);
}
// find next space
if (ignoreThisSpace) {
space = command.find(" ", rightDoubleQuote + 1);
}
else {
startPos = space + 1;
space = command.find(" ", startPos);
}
}
CString subString = command.substr(startPos, command.size());
removeDoubleQuotes(subString);
argv.push_back(subString);
}
bool
CArgParser::searchDoubleQuotes(CString& command, size_t& left, size_t& right, size_t startPos)
{
bool result = false;
left = CString::npos;
right = CString::npos;
left = command.find("\"", startPos);
if (left != CString::npos) {
right = command.find("\"", left + 1);
if (right != CString::npos) {
result = true;
}
}
if (!result) {
left = 0;
right = 0;
}
return result;
}
void
CArgParser::removeDoubleQuotes(CString& arg)
{
// if string is surrounded by double quotes, remove them
if (arg[0] == '\"' &&
arg[arg.size() - 1] == '\"') {
arg = arg.substr(1, arg.size() - 2);
}
}
const char**
CArgParser::getArgv(std::vector<CString>& argsArray)
{
size_t argc = argsArray.size();
// caller is responsible for deleting the outer array only
// we use the c string pointers from argsArray and assign
// them to the inner array. So caller only need to use
// delete[] to delete the outer array
const char** argv = new const char*[argc];
for (size_t i = 0; i < argc; i++) {
argv[i] = argsArray[i].c_str();
}
return argv;
}
CString
CArgParser::assembleCommand(std::vector<CString>& argsArray, CString ignoreArg, int parametersRequired)
{
CString result;
for (std::vector<CString>::iterator it = argsArray.begin(); it != argsArray.end(); ++it) {
if (it->compare(ignoreArg) == 0) {
it = it + parametersRequired;
continue;
}
// if there is a space in this arg, use double quotes surround it
if ((*it).find(" ") != CString::npos) {
(*it).insert(0, "\"");
(*it).push_back('\"');
}
result.append(*it);
// add space to saperate args
result.append(" ");
}
if (!result.empty()) {
// remove the tail space
result = result.substr(0, result.size() - 1);
}
return result;
}
void
CArgParser::updateCommonArgs(const char* const* argv)
{
argsBase().m_name = ARCH->getHostName();
argsBase().m_pname = ARCH->getBasename(argv[0]);
}
bool
CArgParser::checkUnexpectedArgs()
{
#if SYSAPI_WIN32
// suggest that user installs as a windows service. when launched as
// service, process should automatically detect that it should run in
// daemon mode.
if (argsBase().m_daemon) {
LOG((CLOG_ERR
"the --daemon argument is not supported on windows. "
"instead, install %s as a service (--service install)",
argsBase().m_pname));
return true;
}
#endif
return false;
}

View File

@ -20,19 +20,42 @@
#include "base/String.h" #include "base/String.h"
#include "common/stdvector.h" #include "common/stdvector.h"
class CServerArgs;
class CClientArgs;
class CToolArgs;
class CArgsBase; class CArgsBase;
class CApp;
class CArgParser { class CArgParser {
public: public:
CArgParser(CApp* app);
bool parseServerArgs(CServerArgs& args, int argc, const char* const* argv);
bool parseClientArgs(CClientArgs& args, int argc, const char* const* argv);
bool parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* const* argv, int& i); bool parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* const* argv, int& i);
bool parseGenericArgs(int argc, const char* const* argv, int& i);
void setArgsBase(CArgsBase& argsBase) { m_argsBase = &argsBase; }
static bool isArg(int argi, int argc, const char* const* argv, static bool isArg(int argi, int argc, const char* const* argv,
const char* name1, const char* name2, const char* name1, const char* name2,
int minRequiredParameters = 0); int minRequiredParameters = 0);
static void splitCommandString(CString& command, std::vector<CString>& argv);
static bool searchDoubleQuotes(CString& command, size_t& left,
size_t& right, size_t startPos = 0);
static void removeDoubleQuotes(CString& arg);
static const char** getArgv(std::vector<CString>& argsArray);
static CString assembleCommand(std::vector<CString>& argsArray,
CString ignoreArg = "", int parametersRequired = 0);
private: private:
void updateCommonArgs(const char* const* argv);
bool checkUnexpectedArgs();
static CArgsBase& argsBase() { return *m_argsBase; } static CArgsBase& argsBase() { return *m_argsBase; }
private: private:
CApp* m_app;
static CArgsBase* m_argsBase; static CArgsBase* m_argsBase;
}; };

View File

@ -40,7 +40,8 @@ m_display(NULL),
m_disableTray(false), m_disableTray(false),
m_enableIpc(false), m_enableIpc(false),
m_enableDragDrop(false), m_enableDragDrop(false),
m_shouldExit(false) m_shouldExit(false),
m_synergyAddress()
{ {
} }

View File

@ -47,4 +47,5 @@ public:
bool m_disableXInitThreads; bool m_disableXInitThreads;
#endif #endif
bool m_shouldExit; bool m_shouldExit;
CString m_synergyAddress;
}; };

View File

@ -0,0 +1,23 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2014 Synergy Si, Inc.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package 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/>.
*/
#include "synergy/ClientArgs.h"
CClientArgs::CClientArgs() :
m_yscroll(0)
{
}

View File

@ -0,0 +1,30 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2014 Synergy Si, Inc.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package 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/>.
*/
#pragma once
#include "synergy/ArgsBase.h"
class CNetworkAddress;
class CClientArgs : public CArgsBase {
public:
CClientArgs();
public:
int m_yscroll;
};

View File

@ -0,0 +1,25 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2014 Synergy Si, Inc.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package 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/>.
*/
#include "synergy/ServerArgs.h"
CServerArgs::CServerArgs() :
m_configFile(),
m_config(NULL)
{
}

View File

@ -0,0 +1,32 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2014 Synergy Si, Inc.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package 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/>.
*/
#pragma once
#include "synergy/ArgsBase.h"
class CNetworkAddress;
class CConfig;
class CServerArgs : public CArgsBase {
public:
CServerArgs();
public:
CString m_configFile;
CConfig* m_config;
};