From f9f2d8e8afd11e0020ab4ba886c5588dce78bbf0 Mon Sep 17 00:00:00 2001 From: Xinyu Hou Date: Wed, 22 Oct 2014 16:35:28 +0100 Subject: [PATCH] Parse arg refactoring #4124 Implemented argParser class. --- src/lib/synergy/ArgParser.cpp | 344 +++++++++++++++++++++++++++++++++ src/lib/synergy/ArgParser.h | 23 +++ src/lib/synergy/ArgsBase.cpp | 3 +- src/lib/synergy/ArgsBase.h | 1 + src/lib/synergy/ClientArgs.cpp | 23 +++ src/lib/synergy/ClientArgs.h | 30 +++ src/lib/synergy/ServerArgs.cpp | 25 +++ src/lib/synergy/ServerArgs.h | 32 +++ 8 files changed, 480 insertions(+), 1 deletion(-) create mode 100644 src/lib/synergy/ClientArgs.cpp create mode 100644 src/lib/synergy/ClientArgs.h create mode 100644 src/lib/synergy/ServerArgs.cpp create mode 100644 src/lib/synergy/ServerArgs.h diff --git a/src/lib/synergy/ArgParser.cpp b/src/lib/synergy/ArgParser.cpp index ad207ec4..7ab7ab9a 100644 --- a/src/lib/synergy/ArgParser.cpp +++ b/src/lib/synergy/ArgParser.cpp @@ -17,11 +17,102 @@ #include "synergy/ArgParser.h" +#include "synergy/App.h" +#include "synergy/ServerArgs.h" +#include "synergy/ClientArgs.h" #include "synergy/ArgsBase.h" #include "base/Log.h" 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 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 } +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 CArgParser::isArg( int argi, int argc, const char* const* argv, @@ -85,3 +275,157 @@ CArgParser::isArg( // no match return false; } + +void +CArgParser::splitCommandString(CString& command, std::vector& 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& 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& argsArray, CString ignoreArg, int parametersRequired) +{ + CString result; + + for (std::vector::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; +} diff --git a/src/lib/synergy/ArgParser.h b/src/lib/synergy/ArgParser.h index 96320e26..a9cc04eb 100644 --- a/src/lib/synergy/ArgParser.h +++ b/src/lib/synergy/ArgParser.h @@ -20,19 +20,42 @@ #include "base/String.h" #include "common/stdvector.h" +class CServerArgs; +class CClientArgs; +class CToolArgs; class CArgsBase; +class CApp; class CArgParser { 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 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, const char* name1, const char* name2, int minRequiredParameters = 0); + static void splitCommandString(CString& command, std::vector& 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& argsArray); + static CString assembleCommand(std::vector& argsArray, + CString ignoreArg = "", int parametersRequired = 0); + private: + void updateCommonArgs(const char* const* argv); + bool checkUnexpectedArgs(); + static CArgsBase& argsBase() { return *m_argsBase; } private: + CApp* m_app; + static CArgsBase* m_argsBase; }; diff --git a/src/lib/synergy/ArgsBase.cpp b/src/lib/synergy/ArgsBase.cpp index e093764c..b03dfbc3 100644 --- a/src/lib/synergy/ArgsBase.cpp +++ b/src/lib/synergy/ArgsBase.cpp @@ -40,7 +40,8 @@ m_display(NULL), m_disableTray(false), m_enableIpc(false), m_enableDragDrop(false), -m_shouldExit(false) +m_shouldExit(false), +m_synergyAddress() { } diff --git a/src/lib/synergy/ArgsBase.h b/src/lib/synergy/ArgsBase.h index ec8f8e86..4405d459 100644 --- a/src/lib/synergy/ArgsBase.h +++ b/src/lib/synergy/ArgsBase.h @@ -47,4 +47,5 @@ public: bool m_disableXInitThreads; #endif bool m_shouldExit; + CString m_synergyAddress; }; diff --git a/src/lib/synergy/ClientArgs.cpp b/src/lib/synergy/ClientArgs.cpp new file mode 100644 index 00000000..55a8d2b9 --- /dev/null +++ b/src/lib/synergy/ClientArgs.cpp @@ -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 . + */ + +#include "synergy/ClientArgs.h" + +CClientArgs::CClientArgs() : + m_yscroll(0) +{ +} diff --git a/src/lib/synergy/ClientArgs.h b/src/lib/synergy/ClientArgs.h new file mode 100644 index 00000000..9c9e68af --- /dev/null +++ b/src/lib/synergy/ClientArgs.h @@ -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 . + */ + +#pragma once + +#include "synergy/ArgsBase.h" + +class CNetworkAddress; + +class CClientArgs : public CArgsBase { +public: + CClientArgs(); + +public: + int m_yscroll; +}; diff --git a/src/lib/synergy/ServerArgs.cpp b/src/lib/synergy/ServerArgs.cpp new file mode 100644 index 00000000..fb0d48f3 --- /dev/null +++ b/src/lib/synergy/ServerArgs.cpp @@ -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 . + */ + +#include "synergy/ServerArgs.h" + +CServerArgs::CServerArgs() : + m_configFile(), + m_config(NULL) +{ +} + diff --git a/src/lib/synergy/ServerArgs.h b/src/lib/synergy/ServerArgs.h new file mode 100644 index 00000000..d516209a --- /dev/null +++ b/src/lib/synergy/ServerArgs.h @@ -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 . + */ + +#pragma once + +#include "synergy/ArgsBase.h" + +class CNetworkAddress; +class CConfig; + +class CServerArgs : public CArgsBase { +public: + CServerArgs(); + +public: + CString m_configFile; + CConfig* m_config; +};