From 6da369b5f283a0f8acc2e44af5b7e8dc440c8fe2 Mon Sep 17 00:00:00 2001 From: jerry Date: Wed, 24 Sep 2014 13:08:17 +0000 Subject: [PATCH 01/16] created a branch for refactoring args parsing [no-issue][no-build] From 2c16180eba850e831e3e94d54b1cbd4cf69684e5 Mon Sep 17 00:00:00 2001 From: jerry Date: Wed, 24 Sep 2014 13:21:07 +0000 Subject: [PATCH 02/16] test [no-issue] --- test.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test.txt diff --git a/test.txt b/test.txt new file mode 100644 index 00000000..e69de29b From a5db4dc8c5cb159f84b7421f1591e9c33494e73f Mon Sep 17 00:00:00 2001 From: jerry Date: Wed, 24 Sep 2014 13:21:58 +0000 Subject: [PATCH 03/16] removed test.txt [no-issue][no-build] --- test.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test.txt diff --git a/test.txt b/test.txt deleted file mode 100644 index e69de29b..00000000 From 685f53c7fc3f9e1045b75906640560edeb92f32c Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Tue, 21 Oct 2014 16:15:57 +0100 Subject: [PATCH 04/16] cleaned up .gitignore (removed old files) --- .gitignore | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 4ede8306..1ba25776 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,11 @@ -#Vim backup files -*~ -#Python compiled files *.pyc - -#Git-svn created .gitignore -/Release -/Debug -/vc90.pdb -/synergy.ncb -/synergy.vcproj.ADOBENET.ssbarnea.user /bin -/tool -/config.h -/tags - -#doxygen -/doc/doxygen -/doc/doxygen.cfg +/lib +/build +/ext/cryptopp562 +/ext/gmock-1.6.0 +/ext/gtest-1.6.0 +/src/gui/Makefile* +/src/gui/object_script* +/src/gui/tmp +/src/gui/ui_* From 0f926658dc9420e60a8b7b48e10aac039f4e4d60 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Mon, 20 Oct 2014 17:46:11 +0100 Subject: [PATCH 05/16] added getGitRevision function to get current git revision. --- ext/toolchain/commands1.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ext/toolchain/commands1.py b/ext/toolchain/commands1.py index ef492f2b..d245c55b 100644 --- a/ext/toolchain/commands1.py +++ b/ext/toolchain/commands1.py @@ -941,6 +941,24 @@ class InternalCommands: print self.find_revision() def find_revision(self): + return self.getGitRevision() + + def getGitRevision(self): + if sys.version_info < (2, 4): + raise Exception("Python 2.4 or greater required.") + else: + p = subprocess.Popen( + ["git", "log", "--pretty=format:%h", "-n", "1"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + stdout, stderr = p.communicate() + + if p.returncode != 0: + raise Exception('Could not get revision - git info failed with code: ' + str(p.returncode)) + + return stdout + + def find_revision_svn(self): if sys.version_info < (2, 4): stdout = commands.getoutput('svn info') else: @@ -1403,7 +1421,7 @@ class InternalCommands: def dist_name_rev(self, type): # find the version number (we're puting the rev in after this) pattern = '(.*\d+\.\d+\.\d+)(.*)' - replace = '\g<1>-r' + self.find_revision() + '\g<2>' + replace = '\g<1>-' + self.find_revision() + '\g<2>' return re.sub(pattern, replace, self.dist_name(type)) def dist_usage(self): From b85432aeeeebb95189db8f47a0fc25fbc3e76ded Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Mon, 20 Oct 2014 19:06:25 +0100 Subject: [PATCH 06/16] changed svn export to git export --- ext/toolchain/commands1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/toolchain/commands1.py b/ext/toolchain/commands1.py index d245c55b..6b18fcf0 100644 --- a/ext/toolchain/commands1.py +++ b/ext/toolchain/commands1.py @@ -1192,7 +1192,7 @@ class InternalCommands: shutil.rmtree(exportPath) print 'Exporting repository to: ' + exportPath - err = os.system('svn export . ' + exportPath) + err = os.system('git archive master | tar -x -C ' + exportPath) if err != 0: raise Exception('Repository export failed: ' + str(err)) From 90aa90f19f7ff6df0132af5a74a59631c24b81ed Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Mon, 20 Oct 2014 19:26:57 +0100 Subject: [PATCH 07/16] created dist src export path --- ext/toolchain/commands1.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/toolchain/commands1.py b/ext/toolchain/commands1.py index 6b18fcf0..0540bcb4 100644 --- a/ext/toolchain/commands1.py +++ b/ext/toolchain/commands1.py @@ -1192,6 +1192,7 @@ class InternalCommands: shutil.rmtree(exportPath) print 'Exporting repository to: ' + exportPath + os.mkdir(exportPath) err = os.system('git archive master | tar -x -C ' + exportPath) if err != 0: raise Exception('Repository export failed: ' + str(err)) From fe95ec5bc870fb02c11d6658001be5089c219088 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Wed, 22 Oct 2014 13:55:39 +0100 Subject: [PATCH 08/16] added branch name to package names now that buildbot builds branches, it'll be handy to see that branch name in the package name. --- ext/toolchain/commands1.py | 40 ++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/ext/toolchain/commands1.py b/ext/toolchain/commands1.py index 0540bcb4..8888b7bb 100644 --- a/ext/toolchain/commands1.py +++ b/ext/toolchain/commands1.py @@ -946,17 +946,32 @@ class InternalCommands: def getGitRevision(self): if sys.version_info < (2, 4): raise Exception("Python 2.4 or greater required.") - else: - p = subprocess.Popen( - ["git", "log", "--pretty=format:%h", "-n", "1"], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - stdout, stderr = p.communicate() - - if p.returncode != 0: - raise Exception('Could not get revision - git info failed with code: ' + str(p.returncode)) - return stdout + p = subprocess.Popen( + ["git", "log", "--pretty=format:%h", "-n", "1"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + stdout, stderr = p.communicate() + + if p.returncode != 0: + raise Exception('Could not get revision, git error: ' + str(p.returncode)) + + return stdout.strip() + + def getGitBranchName(self): + if sys.version_info < (2, 4): + raise Exception("Python 2.4 or greater required.") + + p = subprocess.Popen( + ["git", "rev-parse", "--abbrev-ref", "HEAD"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + stdout, stderr = p.communicate() + + if p.returncode != 0: + raise Exception('Could not get branch name, git error: ' + str(p.returncode)) + + return stdout.strip() def find_revision_svn(self): if sys.version_info < (2, 4): @@ -1422,9 +1437,10 @@ class InternalCommands: def dist_name_rev(self, type): # find the version number (we're puting the rev in after this) pattern = '(.*\d+\.\d+\.\d+)(.*)' - replace = '\g<1>-' + self.find_revision() + '\g<2>' + replace = "\g<1>-%s@%s\g<2>" % ( + self.getGitBranchName(), self.getGitRevision()) return re.sub(pattern, replace, self.dist_name(type)) - + def dist_usage(self): print ('Usage: %s package [package-type]\n' '\n' From 5a6bdfb5e6fd46b1d26e62e99be2136b218daf02 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Wed, 22 Oct 2014 14:06:15 +0100 Subject: [PATCH 09/16] fixed "hm dist src" command to support branches also allowed non-unix platforms to run src --- ext/toolchain/commands1.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ext/toolchain/commands1.py b/ext/toolchain/commands1.py index 8888b7bb..04ac8c96 100644 --- a/ext/toolchain/commands1.py +++ b/ext/toolchain/commands1.py @@ -1019,10 +1019,7 @@ class InternalCommands: moveExt = '' if type == 'src': - if sys.platform in ['linux2', 'darwin']: - self.distSrc() - else: - package_unsupported = True + self.distSrc() elif type == 'rpm': if sys.platform == 'linux2': @@ -1206,11 +1203,15 @@ class InternalCommands: print "Removing existing export..." shutil.rmtree(exportPath) - print 'Exporting repository to: ' + exportPath os.mkdir(exportPath) - err = os.system('git archive master | tar -x -C ' + exportPath) + + cmd = "git archive %s | tar -x -C %s" % ( + self.getGitBranchName(), exportPath) + + print 'Exporting repository to: ' + exportPath + err = os.system(cmd) if err != 0: - raise Exception('Repository export failed: ' + str(err)) + raise Exception('Repository export failed: ' + str(err)) packagePath = '../' + self.getGenerator().binDir + '/' + name + '.tar.gz' From 326901ef86b26a9af8f5534bcc49468bf80c055b Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Wed, 22 Oct 2014 14:56:57 +0100 Subject: [PATCH 10/16] changed @ to - in package name --- ext/toolchain/commands1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/toolchain/commands1.py b/ext/toolchain/commands1.py index 04ac8c96..1eee3a41 100644 --- a/ext/toolchain/commands1.py +++ b/ext/toolchain/commands1.py @@ -1438,7 +1438,7 @@ class InternalCommands: def dist_name_rev(self, type): # find the version number (we're puting the rev in after this) pattern = '(.*\d+\.\d+\.\d+)(.*)' - replace = "\g<1>-%s@%s\g<2>" % ( + replace = "\g<1>-%s-%s\g<2>" % ( self.getGitBranchName(), self.getGitRevision()) return re.sub(pattern, replace, self.dist_name(type)) From d2814a423ca982cfa18eb05c0e5e51d6eff6e486 Mon Sep 17 00:00:00 2001 From: Xinyu Hou Date: Wed, 22 Oct 2014 16:27:38 +0100 Subject: [PATCH 11/16] Parse arg refactoring #4124 Extracted platform specific argument parsing code. --- src/lib/base/Log.h | 1 + src/lib/synergy/App.h | 2 - src/lib/synergy/ArgParser.cpp | 87 +++++++++++++++++++++++++++++++++++ src/lib/synergy/ArgParser.h | 38 +++++++++++++++ src/lib/synergy/ArgsBase.cpp | 3 +- src/lib/synergy/ArgsBase.h | 1 + 6 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 src/lib/synergy/ArgParser.cpp create mode 100644 src/lib/synergy/ArgParser.h diff --git a/src/lib/base/Log.h b/src/lib/base/Log.h index bbcc742e..d8cc5eee 100644 --- a/src/lib/base/Log.h +++ b/src/lib/base/Log.h @@ -26,6 +26,7 @@ #include #define CLOG (CLog::getInstance()) +#define BYE "\nTry `%s --help' for more information." class ILogOutputter; class CThread; diff --git a/src/lib/synergy/App.h b/src/lib/synergy/App.h index a3c328e3..2ce02d6e 100644 --- a/src/lib/synergy/App.h +++ b/src/lib/synergy/App.h @@ -125,8 +125,6 @@ private: CSocketMultiplexer* m_socketMultiplexer; }; -#define BYE "\nTry `%s --help' for more information." - #if WINAPI_MSWINDOWS #define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_) #else diff --git a/src/lib/synergy/ArgParser.cpp b/src/lib/synergy/ArgParser.cpp new file mode 100644 index 00000000..ad207ec4 --- /dev/null +++ b/src/lib/synergy/ArgParser.cpp @@ -0,0 +1,87 @@ +/* + * 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/ArgParser.h" + +#include "synergy/ArgsBase.h" +#include "base/Log.h" + +CArgsBase* CArgParser::m_argsBase = NULL; + +bool +CArgParser::parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* const* argv, int& i) +{ +#if WINAPI_MSWINDOWS + if (isArg(i, argc, argv, NULL, "--service")) { + LOG((CLOG_WARN "obsolete argument --service, use synergyd instead.")); + argsBase.m_shouldExit = true; + } + else if (isArg(i, argc, argv, NULL, "--exit-pause")) { + argsBase.m_pauseOnExit = true; + } + else if (isArg(i, argc, argv, NULL, "--stop-on-desk-switch")) { + argsBase.m_stopOnDeskSwitch = true; + } + else { + // option not supported here + return false; + } + + return true; +#elif WINAPI_XWINDOWS + if (CArgumentParser::isArg(i, argc, argv, "-display", "--display", 1)) { + // use alternative display + argsBase.m_display = argv[++i]; + } + + else if (CArgumentParser::isArg(i, argc, argv, NULL, "--no-xinitthreads")) { + argsBase.m_disableXInitThreads = true; + } + + else { + // option not supported here + return false; + } + + return true; +#elif WINAPI_CARBON + // no options for carbon + return false; +#endif +} + +bool +CArgParser::isArg( + int argi, int argc, const char* const* argv, + const char* name1, const char* name2, + int minRequiredParameters) +{ + if ((name1 != NULL && strcmp(argv[argi], name1) == 0) || + (name2 != NULL && strcmp(argv[argi], name2) == 0)) { + // match. check args left. + if (argi + minRequiredParameters >= argc) { + LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE, + argsBase().m_pname, argv[argi], argsBase().m_pname)); + argsBase().m_shouldExit = true; + return false; + } + return true; + } + + // no match + return false; +} diff --git a/src/lib/synergy/ArgParser.h b/src/lib/synergy/ArgParser.h new file mode 100644 index 00000000..96320e26 --- /dev/null +++ b/src/lib/synergy/ArgParser.h @@ -0,0 +1,38 @@ +/* + * 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 "base/String.h" +#include "common/stdvector.h" + +class CArgsBase; + +class CArgParser { + +public: + bool parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* const* argv, int& i); + + static bool isArg(int argi, int argc, const char* const* argv, + const char* name1, const char* name2, + int minRequiredParameters = 0); +private: + static CArgsBase& argsBase() { return *m_argsBase; } + +private: + static CArgsBase* m_argsBase; +}; diff --git a/src/lib/synergy/ArgsBase.cpp b/src/lib/synergy/ArgsBase.cpp index 77090fab..e093764c 100644 --- a/src/lib/synergy/ArgsBase.cpp +++ b/src/lib/synergy/ArgsBase.cpp @@ -39,7 +39,8 @@ m_logFile(NULL), m_display(NULL), m_disableTray(false), m_enableIpc(false), -m_enableDragDrop(false) +m_enableDragDrop(false), +m_shouldExit(false) { } diff --git a/src/lib/synergy/ArgsBase.h b/src/lib/synergy/ArgsBase.h index 2bc744bc..ec8f8e86 100644 --- a/src/lib/synergy/ArgsBase.h +++ b/src/lib/synergy/ArgsBase.h @@ -46,4 +46,5 @@ public: #if WINAPI_XWINDOWS bool m_disableXInitThreads; #endif + bool m_shouldExit; }; From f9f2d8e8afd11e0020ab4ba886c5588dce78bbf0 Mon Sep 17 00:00:00 2001 From: Xinyu Hou Date: Wed, 22 Oct 2014 16:35:28 +0100 Subject: [PATCH 12/16] 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; +}; From e26ccfdce6e5f70d1523ed518ceb9a66ee87cd64 Mon Sep 17 00:00:00 2001 From: Xinyu Hou Date: Wed, 22 Oct 2014 16:52:08 +0100 Subject: [PATCH 13/16] Parse arg refactoring #4124 Added unit testing --- src/lib/synergy/App.cpp | 1 + src/test/mock/synergy/MockApp.h | 44 +++ src/test/mock/synergy/MockArgParser.h | 33 ++ src/test/unittests/CMakeLists.txt | 2 +- src/test/unittests/synergy/ArgParserTests.cpp | 207 +++++++++++ .../synergy/ClientArgsParsingTests.cpp | 95 +++++ .../synergy/GenericArgsParsingTests.cpp | 332 ++++++++++++++++++ .../synergy/ServerArgsParsingTests.cpp | 66 ++++ 8 files changed, 779 insertions(+), 1 deletion(-) create mode 100644 src/test/mock/synergy/MockApp.h create mode 100644 src/test/mock/synergy/MockArgParser.h create mode 100644 src/test/unittests/synergy/ArgParserTests.cpp create mode 100644 src/test/unittests/synergy/ClientArgsParsingTests.cpp create mode 100644 src/test/unittests/synergy/GenericArgsParsingTests.cpp create mode 100644 src/test/unittests/synergy/ServerArgsParsingTests.cpp diff --git a/src/lib/synergy/App.cpp b/src/lib/synergy/App.cpp index e9e5e237..3cedabd6 100644 --- a/src/lib/synergy/App.cpp +++ b/src/lib/synergy/App.cpp @@ -67,6 +67,7 @@ CApp::CApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, CApp::~CApp() { + s_instance = nullptr; delete m_args; } diff --git a/src/test/mock/synergy/MockApp.h b/src/test/mock/synergy/MockApp.h new file mode 100644 index 00000000..da71258f --- /dev/null +++ b/src/test/mock/synergy/MockApp.h @@ -0,0 +1,44 @@ +/* + * 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 + +#define TEST_ENV + +#include "synergy/App.h" + +#include "test/global/gmock.h" + +class CMockApp : public CApp +{ +public: + CMockApp() : CApp(NULL, NULL, NULL) { } + + MOCK_METHOD0(help, void()); + MOCK_METHOD0(loadConfig, void()); + MOCK_METHOD1(loadConfig, bool(const CString&)); + MOCK_CONST_METHOD0(daemonInfo, const char*()); + MOCK_CONST_METHOD0(daemonName, const char*()); + MOCK_METHOD2(parseArgs, void(int, const char* const*)); + MOCK_METHOD0(version, void()); + MOCK_METHOD2(standardStartup, int(int, char**)); + MOCK_METHOD4(runInner, int(int, char**, ILogOutputter*, StartupFunc)); + MOCK_METHOD0(startNode, void()); + MOCK_METHOD0(mainLoop, int()); + MOCK_METHOD2(foregroundStartup, int(int, char**)); + MOCK_METHOD0(createScreen, CScreen*()); +}; diff --git a/src/test/mock/synergy/MockArgParser.h b/src/test/mock/synergy/MockArgParser.h new file mode 100644 index 00000000..05224a0a --- /dev/null +++ b/src/test/mock/synergy/MockArgParser.h @@ -0,0 +1,33 @@ +/* + * 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 + +#define TEST_ENV + +#include "synergy/ArgParser.h" + +#include "test/global/gmock.h" + +class CMockArgParser : public CArgParser +{ +public: + CMockArgParser() : CArgParser(NULL) { } + + MOCK_METHOD3(parseGenericArgs, bool(int, const char* const*, int&)); + MOCK_METHOD0(checkUnexpectedArgs, bool()); +}; diff --git a/src/test/unittests/CMakeLists.txt b/src/test/unittests/CMakeLists.txt index 65cf309b..e71d5b78 100644 --- a/src/test/unittests/CMakeLists.txt +++ b/src/test/unittests/CMakeLists.txt @@ -49,4 +49,4 @@ endif() add_executable(unittests ${sources}) target_link_libraries(unittests - arch base client server common io net platform server synergy mt gtest gmock cryptopp ${libs}) + arch base client server common io net platform server synergy mt ipc gtest gmock cryptopp ${libs}) diff --git a/src/test/unittests/synergy/ArgParserTests.cpp b/src/test/unittests/synergy/ArgParserTests.cpp new file mode 100644 index 00000000..42808d8c --- /dev/null +++ b/src/test/unittests/synergy/ArgParserTests.cpp @@ -0,0 +1,207 @@ +/* + * 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/ArgParser.h" +#include "synergy/ArgsBase.h" + +#include "test/global/gtest.h" + +TEST(CArgParserTests, isArg_abbreviationsArg_returnTrue) +{ + int i = 1; + const int argc = 2; + const char* argv[argc] = { "stub", "-t" }; + bool result = CArgParser::isArg(i, argc, argv, "-t", NULL); + + EXPECT_EQ(true, result); +} + +TEST(CArgParserTests, isArg_fullArg_returnTrue) +{ + int i = 1; + const int argc = 2; + const char* argv[argc] = { "stub", "--test" }; + bool result = CArgParser::isArg(i, argc, argv, NULL, "--test"); + + EXPECT_EQ(true, result); +} + +TEST(CArgParserTests, isArg_missingArgs_returnFalse) +{ + int i = 1; + const int argc = 2; + const char* argv[argc] = { "stub", "-t" }; + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + bool result = CArgParser::isArg(i, argc, argv, "-t", NULL, 1); + + EXPECT_FALSE(result); + EXPECT_EQ(true, argsBase.m_shouldExit); +} + +TEST(CArgParserTests, searchDoubleQuotes_doubleQuotedArg_returnTrue) +{ + CString command("\"stub\""); + size_t left = 0; + size_t right = 0; + + bool result = CArgParser::searchDoubleQuotes(command, left, right); + + EXPECT_EQ(true, result); + EXPECT_EQ(0, left); + EXPECT_EQ(5, right); +} + +TEST(CArgParserTests, searchDoubleQuotes_noDoubleQuotedArg_returnfalse) +{ + CString command("stub"); + size_t left = 0; + size_t right = 0; + + bool result = CArgParser::searchDoubleQuotes(command, left, right); + + EXPECT_FALSE(result); + EXPECT_EQ(0, left); + EXPECT_EQ(0, right); +} + +TEST(CArgParserTests, searchDoubleQuotes_oneDoubleQuoteArg_returnfalse) +{ + CString command("\"stub"); + size_t left = 0; + size_t right = 0; + + bool result = CArgParser::searchDoubleQuotes(command, left, right); + + EXPECT_FALSE(result); + EXPECT_EQ(0, left); + EXPECT_EQ(0, right); +} + +TEST(CArgParserTests, splitCommandString_oneArg_returnArgv) +{ + CString command("stub"); + std::vector argv; + + CArgParser::splitCommandString(command, argv); + + EXPECT_EQ(1, argv.size()); + EXPECT_EQ("stub", argv.at(0)); +} + +TEST(CArgParserTests, splitCommandString_twoArgs_returnArgv) +{ + CString command("stub1 stub2"); + std::vector argv; + + CArgParser::splitCommandString(command, argv); + + EXPECT_EQ(2, argv.size()); + EXPECT_EQ("stub1", argv.at(0)); + EXPECT_EQ("stub2", argv.at(1)); +} + +TEST(CArgParserTests, splitCommandString_doubleQuotedArgs_returnArgv) +{ + CString command("\"stub1\" stub2 \"stub3\""); + std::vector argv; + + CArgParser::splitCommandString(command, argv); + + EXPECT_EQ(3, argv.size()); + EXPECT_EQ("stub1", argv.at(0)); + EXPECT_EQ("stub2", argv.at(1)); + EXPECT_EQ("stub3", argv.at(2)); +} + +TEST(CArgParserTests, splitCommandString_spaceDoubleQuotedArgs_returnArgv) +{ + CString command("\"stub1\" stub2 \"stub3 space\""); + std::vector argv; + + CArgParser::splitCommandString(command, argv); + + EXPECT_EQ(3, argv.size()); + EXPECT_EQ("stub1", argv.at(0)); + EXPECT_EQ("stub2", argv.at(1)); + EXPECT_EQ("stub3 space", argv.at(2)); +} + +TEST(CArgParserTests, getArgv_stringArray_return2DArray) +{ + std::vector argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + argArray.push_back("stub3 space"); + const char** argv = CArgParser::getArgv(argArray); + + CString row1(argv[0]); + CString row2(argv[1]); + CString row3(argv[2]); + + EXPECT_EQ("stub1", row1); + EXPECT_EQ("stub2", row2); + EXPECT_EQ("stub3 space", row3); + + delete[] argv; +} + +TEST(CArgParserTests, assembleCommand_stringArray_returnCommand) +{ + std::vector argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + CString command = CArgParser::assembleCommand(argArray); + + EXPECT_EQ("stub1 stub2", command); +} + +TEST(CArgParserTests, assembleCommand_ignoreSecondArg_returnCommand) +{ + std::vector argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + CString command = CArgParser::assembleCommand(argArray, "stub2"); + + EXPECT_EQ("stub1", command); +} + +TEST(CArgParserTests, assembleCommand_ignoreSecondArgWithOneParameter_returnCommand) +{ + std::vector argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + argArray.push_back("stub3"); + argArray.push_back("stub4"); + CString command = CArgParser::assembleCommand(argArray, "stub2", 1); + + EXPECT_EQ("stub1 stub4", command); +} + +TEST(CArgParserTests, assembleCommand_stringArrayWithSpace_returnCommand) +{ + std::vector argArray; + argArray.push_back("stub1 space"); + argArray.push_back("stub2"); + argArray.push_back("stub3 space"); + CString command = CArgParser::assembleCommand(argArray); + + EXPECT_EQ("\"stub1 space\" stub2 \"stub3 space\"", command); +} + diff --git a/src/test/unittests/synergy/ClientArgsParsingTests.cpp b/src/test/unittests/synergy/ClientArgsParsingTests.cpp new file mode 100644 index 00000000..1cc1e67b --- /dev/null +++ b/src/test/unittests/synergy/ClientArgsParsingTests.cpp @@ -0,0 +1,95 @@ +/* + * 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/ArgParser.h" +#include "synergy/ClientArgs.h" +#include "test/mock/synergy/MockArgParser.h" + +#include "test/global/gtest.h" + +using ::testing::_; +using ::testing::Invoke; +using ::testing::NiceMock; + +bool +client_stubParseGenericArgs(int, const char* const*, int&) +{ + return false; +} + +bool +client_stubCheckUnexpectedArgs() +{ + return false; +} + +TEST(CClientArgsParsingTests, parseClientArgs_yScrollArg_setYScroll) +{ + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + CClientArgs clientArgs; + const int argc = 3; + const char* kYScrollCmd[argc] = { "stub", "--yscroll", "1" }; + + argParser.parseClientArgs(clientArgs, argc, kYScrollCmd); + + EXPECT_EQ(1, clientArgs.m_yscroll); +} + +TEST(CClientArgsParsingTests, parseClientArgs_addressArg_setSynergyAddress) +{ + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + CClientArgs clientArgs; + const int argc = 2; + const char* kAddressCmd[argc] = { "stub", "mock_address" }; + + bool result = argParser.parseClientArgs(clientArgs, argc, kAddressCmd); + + EXPECT_EQ("mock_address", clientArgs.m_synergyAddress); + EXPECT_EQ(true, result); +} + +TEST(CClientArgsParsingTests, parseClientArgs_noAddressArg_returnFalse) +{ + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + CClientArgs clientArgs; + const int argc = 1; + const char* kNoAddressCmd[argc] = { "stub" }; + + bool result = argParser.parseClientArgs(clientArgs, argc, kNoAddressCmd); + + EXPECT_FALSE(result); +} + +TEST(CClientArgsParsingTests, parseClientArgs_unrecognizedArg_returnFalse) +{ + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + CClientArgs clientArgs; + const int argc = 3; + const char* kUnrecognizedCmd[argc] = { "stub", "mock_arg", "mock_address"}; + + bool result = argParser.parseClientArgs(clientArgs, argc, kUnrecognizedCmd); + + EXPECT_FALSE(result); +} diff --git a/src/test/unittests/synergy/GenericArgsParsingTests.cpp b/src/test/unittests/synergy/GenericArgsParsingTests.cpp new file mode 100644 index 00000000..4d3f585b --- /dev/null +++ b/src/test/unittests/synergy/GenericArgsParsingTests.cpp @@ -0,0 +1,332 @@ +/* + * 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/ArgParser.h" +#include "synergy/ArgsBase.h" +#include "test/mock/synergy/MockApp.h" + +#include "test/global/gtest.h" + +using namespace synergy; +using ::testing::_; +using ::testing::Invoke; +using ::testing::NiceMock; + +bool g_helpShowed = false; +bool g_versionShowed = false; + +void +showMockHelp() +{ + g_helpShowed = true; +} + +void +showMockVersion() +{ + g_versionShowed = true; +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_logLevelCmd_setLogLevel) +{ + int i = 1; + const int argc = 3; + const char* kLogLevelCmd[argc] = { "stub", "--debug", "DEBUG" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kLogLevelCmd, i); + + CString logFilter(argsBase.m_logFilter); + + EXPECT_EQ("DEBUG", logFilter); + EXPECT_EQ(2, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_logFileCmd_saveLogFilename) +{ + int i = 1; + const int argc = 3; + const char* kLogFileCmd[argc] = { "stub", "--log", "mock_filename" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kLogFileCmd, i); + + CString logFile(argsBase.m_logFile); + + EXPECT_EQ("mock_filename", logFile); + EXPECT_EQ(2, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_logFileCmdWithSpace_saveLogFilename) +{ + int i = 1; + const int argc = 3; + const char* kLogFileCmdWithSpace[argc] = { "stub", "--log", "mo ck_filename" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kLogFileCmdWithSpace, i); + + CString logFile(argsBase.m_logFile); + + EXPECT_EQ("mo ck_filename", logFile); + EXPECT_EQ(2, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_noDeamonCmd_daemonFalse) +{ + int i = 1; + const int argc = 2; + const char* kNoDeamonCmd[argc] = { "stub", "-f" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNoDeamonCmd, i); + + EXPECT_FALSE(argsBase.m_daemon); + EXPECT_EQ(1, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_deamonCmd_daemonTrue) +{ + int i = 1; + const int argc = 2; + const char* kDeamonCmd[argc] = { "stub", "--daemon" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kDeamonCmd, i); + + EXPECT_EQ(true, argsBase.m_daemon); + EXPECT_EQ(1, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_nameCmd_saveName) +{ + int i = 1; + const int argc = 3; + const char* kNameCmd[argc] = { "stub", "--name", "mock" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNameCmd, i); + + EXPECT_EQ("mock", argsBase.m_name); + EXPECT_EQ(2, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_noRestartCmd_restartFalse) +{ + int i = 1; + const int argc = 2; + const char* kNoRestartCmd[argc] = { "stub", "--no-restart" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNoRestartCmd, i); + + EXPECT_FALSE(argsBase.m_restartable); + EXPECT_EQ(1, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_restartCmd_restartTrue) +{ + int i = 1; + const int argc = 2; + const char* kRestartCmd[argc] = { "stub", "--restart" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kRestartCmd, i); + + EXPECT_EQ(true, argsBase.m_restartable); + EXPECT_EQ(1, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_backendCmd_backendTrue) +{ + int i = 1; + const int argc = 2; + const char* kBackendCmd[argc] = { "stub", "-z" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kBackendCmd, i); + + EXPECT_EQ(true, argsBase.m_backend); + EXPECT_EQ(1, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_noHookCmd_noHookTrue) +{ + int i = 1; + const int argc = 2; + const char* kNoHookCmd[argc] = { "stub", "--no-hooks" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNoHookCmd, i); + + EXPECT_EQ(true, argsBase.m_noHooks); + EXPECT_EQ(1, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_helpCmd_showHelp) +{ + g_helpShowed = false; + int i = 1; + const int argc = 2; + const char* kHelpCmd[argc] = { "stub", "--help" }; + + NiceMock app; + CArgParser argParser(&app); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + ON_CALL(app, help()).WillByDefault(Invoke(showMockHelp)); + + argParser.parseGenericArgs(argc, kHelpCmd, i); + + EXPECT_EQ(true, g_helpShowed); + EXPECT_EQ(1, i); +} + + +TEST(CGenericArgsParsingTests, parseGenericArgs_versionCmd_showVersion) +{ + g_versionShowed = false; + int i = 1; + const int argc = 2; + const char* kVersionCmd[argc] = { "stub", "--version" }; + + NiceMock app; + CArgParser argParser(&app); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + ON_CALL(app, version()).WillByDefault(Invoke(showMockVersion)); + + argParser.parseGenericArgs(argc, kVersionCmd, i); + + EXPECT_EQ(true, g_versionShowed); + EXPECT_EQ(1, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_noTrayCmd_disableTrayTrue) +{ + int i = 1; + const int argc = 2; + const char* kNoTrayCmd[argc] = { "stub", "--no-tray" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kNoTrayCmd, i); + + EXPECT_EQ(true, argsBase.m_disableTray); + EXPECT_EQ(1, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_ipcCmd_enableIpcTrue) +{ + int i = 1; + const int argc = 2; + const char* kIpcCmd[argc] = { "stub", "--ipc" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kIpcCmd, i); + + EXPECT_EQ(true, argsBase.m_enableIpc); + EXPECT_EQ(1, i); +} + +TEST(CGenericArgsParsingTests, parseGenericArgs_cryptoPassCmd_savePassword) +{ + int i = 1; + const int argc = 3; + const char* kCryptoPassCmd[argc] = { "stub", "--crypto-pass", "mock_password" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kCryptoPassCmd, i); + + EXPECT_EQ("mock_password", argsBase.m_crypto.m_pass); + EXPECT_EQ(1, argsBase.m_crypto.m_mode); // 1 == kCfb + EXPECT_EQ(2, i); +} + +#ifndef WINAPI_XWINDOWS +TEST(CGenericArgsParsingTests, parseGenericArgs_dragDropCmdOnNonLinux_enableDragDropTrue) +{ + int i = 1; + const int argc = 2; + const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kDragDropCmd, i); + + EXPECT_EQ(true, argsBase.m_enableDragDrop); + EXPECT_EQ(1, i); +} +#endif + +#ifdef WINAPI_XWINDOWS +TEST(CGenericArgsParsingTests, parseGenericArgs_dragDropCmdOnLinux_enableDragDropFalse) +{ + int i = 1; + const int argc = 2; + const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" }; + + CArgParser argParser(NULL); + CArgsBase argsBase; + argParser.setArgsBase(argsBase); + + argParser.parseGenericArgs(argc, kDragDropCmd, i); + + EXPECT_FALSE(argsBase.m_enableDragDrop); + EXPECT_EQ(1, i); +} +#endif diff --git a/src/test/unittests/synergy/ServerArgsParsingTests.cpp b/src/test/unittests/synergy/ServerArgsParsingTests.cpp new file mode 100644 index 00000000..5e57733b --- /dev/null +++ b/src/test/unittests/synergy/ServerArgsParsingTests.cpp @@ -0,0 +1,66 @@ +/* + * 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/ArgParser.h" +#include "synergy/ServerArgs.h" +#include "test/mock/synergy/MockArgParser.h" + +#include "test/global/gtest.h" + +using ::testing::_; +using ::testing::Invoke; +using ::testing::NiceMock; + +bool +server_stubParseGenericArgs(int, const char* const*, int&) +{ + return false; +} + +bool +server_stubCheckUnexpectedArgs() +{ + return false; +} + +TEST(CServerArgsParsingTests, parseServerArgs_addressArg_setSynergyAddress) +{ + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); + CServerArgs serverArgs; + const int argc = 3; + const char* kAddressCmd[argc] = { "stub", "--address", "mock_address" }; + + argParser.parseServerArgs(serverArgs, argc, kAddressCmd); + + EXPECT_EQ("mock_address", serverArgs.m_synergyAddress); +} + +TEST(CServerArgsParsingTests, parseServerArgs_configArg_setConfigFile) +{ + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); + CServerArgs serverArgs; + const int argc = 3; + const char* kConfigCmd[argc] = { "stub", "--config", "mock_configFile" }; + + argParser.parseServerArgs(serverArgs, argc, kConfigCmd); + + EXPECT_EQ("mock_configFile", serverArgs.m_configFile); +} From 943a355359ff2b3007f3e9a106a3f3e1028cf3e3 Mon Sep 17 00:00:00 2001 From: Xinyu Hou Date: Thu, 23 Oct 2014 11:30:51 +0100 Subject: [PATCH 14/16] Parse arg refactoring #4124 Used argParser to parse arguments and removed the old code --- src/lib/synergy/App.cpp | 213 ++--------------------- src/lib/synergy/App.h | 7 - src/lib/synergy/AppUtil.cpp | 7 - src/lib/synergy/AppUtil.h | 3 +- src/lib/synergy/ClientApp.cpp | 117 +++---------- src/lib/synergy/ClientApp.h | 19 +- src/lib/synergy/IApp.h | 3 - src/lib/synergy/IAppUtil.h | 1 - src/lib/synergy/ServerApp.cpp | 100 +++-------- src/lib/synergy/ServerApp.h | 17 +- src/lib/synergy/unix/AppUtilUnix.cpp | 25 --- src/lib/synergy/unix/AppUtilUnix.h | 1 - src/lib/synergy/win32/AppUtilWindows.cpp | 23 --- src/lib/synergy/win32/AppUtilWindows.h | 2 - 14 files changed, 80 insertions(+), 458 deletions(-) diff --git a/src/lib/synergy/App.cpp b/src/lib/synergy/App.cpp index 3cedabd6..7f7d4305 100644 --- a/src/lib/synergy/App.cpp +++ b/src/lib/synergy/App.cpp @@ -17,6 +17,7 @@ */ #include "synergy/App.h" + #include "base/Log.h" #include "common/Version.h" #include "synergy/protocol_types.h" @@ -51,6 +52,10 @@ CApp* CApp::s_instance = nullptr; +// +// CApp +// + CApp::CApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, CArgsBase* args) : m_bye(&exit), m_taskBarReceiver(NULL), @@ -71,202 +76,6 @@ CApp::~CApp() delete m_args; } -bool -CApp::isArg( - int argi, int argc, const char* const* argv, - const char* name1, const char* name2, - int minRequiredParameters) -{ - if ((name1 != NULL && strcmp(argv[argi], name1) == 0) || - (name2 != NULL && strcmp(argv[argi], name2) == 0)) { - // match. check args left. - if (argi + minRequiredParameters >= argc) { - LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE, - argsBase().m_pname, argv[argi], argsBase().m_pname)); - m_bye(kExitArgs); - } - return true; - } - - // no match - return false; -} - -bool -CApp::parseArg(const int& argc, const char* const* argv, int& i) -{ - if (appUtil().parseArg(argc, argv, i)) { - // handled by platform util - return true; - } - - else 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")) { - help(); - m_bye(kExitSuccess); - } - - else if (isArg(i, argc, argv, NULL, "--version")) { - version(); - m_bye(kExitSuccess); - } - - 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; -} - -void -CApp::parseArgs(int argc, const char* const* argv, int& i) -{ - // about these use of assert() here: - // previously an /analyze warning was displayed if we only used assert and - // did not return on failure. however, this warning does not appear to show - // any more (could be because new compiler args have been added). - // the asserts are programmer benefit only; the os should never pass 0 args, - // because the first is always the binary name. the only way assert would - // evaluate to true, is if this parse function were implemented incorrectly, - // which is unlikely because it's old code and has a specific use. - // we should avoid using anything other than assert here, because it will - // look like important code, which it's not really. - assert(argsBase().m_pname != NULL); - assert(argv != NULL); - assert(argc >= 1); - - // set defaults - argsBase().m_name = ARCH->getHostName(); - - // parse options - for (i = 1; i < argc; ++i) { - - if (parseArg(argc, argv, i)) { - continue; - } - - else if (isArg(i, argc, argv, "--", NULL)) { - // remaining arguments are not options - ++i; - break; - } - - else if (argv[i][0] == '-') { - std::cerr << "Unrecognized option: " << argv[i] << std::endl; - m_bye(kExitArgs); - } - - else { - // this and remaining arguments are not options - break; - } - } - -#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)); - m_bye(kExitArgs); - } -#endif -} - void CApp::version() { @@ -364,6 +173,18 @@ CApp::initApp(int argc, const char** argv) // parse command line parseArgs(argc, argv); + // set log filter + if (!CLOG->setFilter(argsBase().m_logFilter)) { + LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE, + argsBase().m_pname, argsBase().m_logFilter, argsBase().m_pname)); + m_bye(kExitArgs); + } + loggingFilterWarning(); + + if (argsBase().m_enableDragDrop) { + LOG((CLOG_INFO "drag and drop enabled")); + } + // setup file logging after parsing args setupFileLogging(); diff --git a/src/lib/synergy/App.h b/src/lib/synergy/App.h index 2ce02d6e..e389aa23 100644 --- a/src/lib/synergy/App.h +++ b/src/lib/synergy/App.h @@ -70,11 +70,6 @@ public: // TODO: this is old C code - use inheritance to normalize void (*m_bye)(int); - // Returns true if argv[argi] is equal to name1 or name2. - bool isArg(int argi, int argc, const char* const* argv, - const char* name1, const char* name2, - int minRequiredParameters = 0); - static CApp& instance() { assert(s_instance != nullptr); return *s_instance; } // If --log was specified in args, then add a file logger. @@ -105,8 +100,6 @@ private: void handleIpcMessage(const CEvent&, void*); protected: - virtual void parseArgs(int argc, const char* const* argv, int &i); - virtual bool parseArg(const int& argc, const char* const* argv, int& i); void initIpcClient(); void cleanupIpcClient(); void runEventsLoop(void*); diff --git a/src/lib/synergy/AppUtil.cpp b/src/lib/synergy/AppUtil.cpp index c7e301d8..af60fea0 100644 --- a/src/lib/synergy/AppUtil.cpp +++ b/src/lib/synergy/AppUtil.cpp @@ -30,13 +30,6 @@ CAppUtil::~CAppUtil() { } -bool -CAppUtil::parseArg(const int& argc, const char* const* argv, int& i) -{ - // no common platform args (yet) - return false; -} - void CAppUtil::adoptApp(IApp* app) { diff --git a/src/lib/synergy/AppUtil.h b/src/lib/synergy/AppUtil.h index 70aca030..fa105d64 100644 --- a/src/lib/synergy/AppUtil.h +++ b/src/lib/synergy/AppUtil.h @@ -25,8 +25,7 @@ class CAppUtil : public IAppUtil { public: CAppUtil(); virtual ~CAppUtil(); - - virtual bool parseArg(const int& argc, const char* const* argv, int& i); + virtual void adoptApp(IApp* app); IApp& app() const; virtual void exitApp(int code) { throw XExitApp(code); } diff --git a/src/lib/synergy/ClientApp.cpp b/src/lib/synergy/ClientApp.cpp index cb2ac4e6..0449d416 100644 --- a/src/lib/synergy/ClientApp.cpp +++ b/src/lib/synergy/ClientApp.cpp @@ -19,9 +19,11 @@ #include "synergy/ClientApp.h" #include "client/Client.h" +#include "synergy/ArgParser.h" #include "synergy/protocol_types.h" #include "synergy/Screen.h" #include "synergy/XScreen.h" +#include "synergy/ClientArgs.h" #include "net/NetworkAddress.h" #include "net/TCPSocketFactory.h" #include "net/SocketMultiplexer.h" @@ -61,9 +63,10 @@ #define RETRY_TIME 1.0 CClientApp::CClientApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver) : - CApp(events, createTaskBarReceiver, new CArgs()), + CApp(events, createTaskBarReceiver, new CClientArgs()), m_client(NULL), - m_clientScreen(NULL) + m_clientScreen(NULL), + m_serverAddress(NULL) { } @@ -71,97 +74,35 @@ CClientApp::~CClientApp() { } -CClientApp::CArgs::CArgs() : -m_yscroll(0), -m_serverAddress(NULL) -{ -} - -CClientApp::CArgs::~CArgs() -{ -} - -bool -CClientApp::parseArg(const int& argc, const char* const* argv, int& i) -{ - if (CApp::parseArg(argc, argv, i)) { - // found common arg - return true; - } - - 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 { - // option not supported here - return false; - } - - // argument was valid - return true; -} - void CClientApp::parseArgs(int argc, const char* const* argv) { - // asserts values, sets defaults, and parses args - int i; - CApp::parseArgs(argc, argv, i); + CArgParser argParser(this); + bool result = argParser.parseClientArgs(args(), argc, argv); - // 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)); + if (!result || args().m_shouldExit) { m_bye(kExitArgs); } - if (i + 1 != argc) { - LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, - args().m_pname, argv[i], args().m_pname)); - m_bye(kExitArgs); - } - - // save server address - try { - *args().m_serverAddress = CNetworkAddress(argv[i], kDefaultPort); - args().m_serverAddress->resolve(); - } - catch (XSocketAddress& e) { - // allow an address that we can't look up if we're restartable. - // we'll try to resolve the address each time we connect to the - // server. a bad port will never get better. patch by Brent - // Priddy. - if (!args().m_restartable || e.getError() == XSocketAddress::kBadPort) { - LOG((CLOG_PRINT "%s: %s" BYE, - args().m_pname, e.what(), args().m_pname)); - m_bye(kExitFailed); + else { + // save server address + if (!args().m_synergyAddress.empty()) { + try { + *m_serverAddress = CNetworkAddress(args().m_synergyAddress, kDefaultPort); + m_serverAddress->resolve(); + } + catch (XSocketAddress& e) { + // allow an address that we can't look up if we're restartable. + // we'll try to resolve the address each time we connect to the + // server. a bad port will never get better. patch by Brent + // Priddy. + if (!args().m_restartable || e.getError() == XSocketAddress::kBadPort) { + LOG((CLOG_PRINT "%s: %s" BYE, + args().m_pname, e.what(), args().m_pname)); + m_bye(kExitFailed); + } + } } } - - // set log filter - if (!CLOG->setFilter(args().m_logFilter)) { - LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE, - args().m_pname, args().m_logFilter, args().m_pname)); - m_bye(kExitArgs); - } - - // identify system - LOG((CLOG_INFO "%s Client on %s %s", kAppVersion, ARCH->getOSName().c_str(), ARCH->getPlatformName().c_str())); - - if (args().m_enableDragDrop) { - LOG((CLOG_INFO "drag and drop enabled")); - } - - loggingFilterWarning(); } void @@ -460,7 +401,7 @@ CClientApp::startClient() if (m_clientScreen == NULL) { clientScreen = openClientScreen(); m_client = openClient(args().m_name, - *args().m_serverAddress, clientScreen, args().m_crypto); + *m_serverAddress, clientScreen, args().m_crypto); m_clientScreen = clientScreen; LOG((CLOG_NOTE "started client")); } @@ -590,7 +531,7 @@ int CClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) { // general initialization - args().m_serverAddress = new CNetworkAddress; + m_serverAddress = new CNetworkAddress; args().m_pname = ARCH->getBasename(argv[0]); // install caller's output filter @@ -612,7 +553,7 @@ CClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFun delete m_taskBarReceiver; } - delete args().m_serverAddress; + delete m_serverAddress; throw; } diff --git a/src/lib/synergy/ClientApp.h b/src/lib/synergy/ClientApp.h index c643e464..67e83bf8 100644 --- a/src/lib/synergy/ClientApp.h +++ b/src/lib/synergy/ClientApp.h @@ -19,26 +19,17 @@ #pragma once #include "synergy/App.h" -#include "synergy/ArgsBase.h" class CScreen; class CEvent; class CClient; class CNetworkAddress; class CThread; +class CClientArgs; +class CCryptoOptions; class CClientApp : public CApp { public: - class CArgs : public CArgsBase { - public: - CArgs(); - ~CArgs(); - - public: - int m_yscroll; - CNetworkAddress* m_serverAddress; - }; - CClientApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver); virtual ~CClientApp(); @@ -49,7 +40,7 @@ public: void help(); // Returns arguments that are common and for client. - CArgs& args() const { return (CArgs&)argsBase(); } + CClientArgs& args() const { return (CClientArgs&)argsBase(); } const char* daemonName() const; const char* daemonInfo() const; @@ -84,11 +75,9 @@ public: static CClientApp& instance() { return (CClientApp&)CApp::instance(); } CClient* getClientPtr() { return m_client; } - -private: - virtual bool parseArg(const int& argc, const char* const* argv, int& i); private: CClient* m_client; CScreen* m_clientScreen; + CNetworkAddress* m_serverAddress; }; diff --git a/src/lib/synergy/IApp.h b/src/lib/synergy/IApp.h index c9bf853c..d43ca8f1 100644 --- a/src/lib/synergy/IApp.h +++ b/src/lib/synergy/IApp.h @@ -32,9 +32,6 @@ class IApp : public IInterface { public: virtual void setByeFunc(void(*bye)(int)) = 0; - virtual bool isArg(int argi, int argc, const char* const* argv, - const char* name1, const char* name2, - int minRequiredParameters = 0) = 0; virtual CArgsBase& argsBase() const = 0; virtual int standardStartup(int argc, char** argv) = 0; virtual int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) = 0; diff --git a/src/lib/synergy/IAppUtil.h b/src/lib/synergy/IAppUtil.h index 3cb20aa5..f089d423 100644 --- a/src/lib/synergy/IAppUtil.h +++ b/src/lib/synergy/IAppUtil.h @@ -23,7 +23,6 @@ class IAppUtil : public IInterface { public: - virtual bool parseArg(const int& argc, const char* const* argv, int& i) = 0; virtual void adoptApp(IApp* app) = 0; virtual IApp& app() const = 0; virtual int run(int argc, char** argv) = 0; diff --git a/src/lib/synergy/ServerApp.cpp b/src/lib/synergy/ServerApp.cpp index 03295dd2..dce8500c 100644 --- a/src/lib/synergy/ServerApp.cpp +++ b/src/lib/synergy/ServerApp.cpp @@ -22,9 +22,11 @@ #include "server/ClientListener.h" #include "server/ClientProxy.h" #include "server/PrimaryClient.h" +#include "synergy/ArgParser.h" #include "synergy/Screen.h" #include "synergy/XScreen.h" #include "synergy/ServerTaskBarReceiver.h" +#include "synergy/ServerArgs.h" #include "net/SocketMultiplexer.h" #include "net/TCPSocketFactory.h" #include "net/XSocket.h" @@ -63,13 +65,14 @@ // CServerApp::CServerApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver) : - CApp(events, createTaskBarReceiver, new CArgs()), + CApp(events, createTaskBarReceiver, new CServerArgs()), m_server(NULL), m_serverState(kUninitialized), m_serverScreen(NULL), m_primaryClient(NULL), m_listener(NULL), - m_timer(NULL) + m_timer(NULL), + m_synergyAddress(NULL) { } @@ -77,82 +80,29 @@ CServerApp::~CServerApp() { } -CServerApp::CArgs::CArgs() : -m_synergyAddress(NULL), -m_config(NULL) -{ -} - -CServerApp::CArgs::~CArgs() -{ -} - -bool -CServerApp::parseArg(const int& argc, const char* const* argv, int& i) -{ - if (CApp::parseArg(argc, argv, i)) { - // found common arg - return true; - } - - else if (isArg(i, argc, argv, "-a", "--address", 1)) { - // save listen address - try { - *args().m_synergyAddress = CNetworkAddress(argv[i + 1], - kDefaultPort); - args().m_synergyAddress->resolve(); - } - catch (XSocketAddress& e) { - LOG((CLOG_PRINT "%s: %s" BYE, - args().m_pname, e.what(), args().m_pname)); - m_bye(kExitArgs); - } - ++i; - } - - else if (isArg(i, argc, argv, "-c", "--config", 1)) { - // save configuration file path - args().m_configFile = argv[++i]; - } - - else { - // option not supported here - return false; - } - - // argument was valid - return true; -} - void CServerApp::parseArgs(int argc, const char* const* argv) { - // asserts values, sets defaults, and parses args - int i; - CApp::parseArgs(argc, argv, i); + CArgParser argParser(this); + bool result = argParser.parseServerArgs(args(), argc, argv); - // no non-option arguments are allowed - if (i != argc) { - LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, - args().m_pname, argv[i], args().m_pname)); + if (!result || args().m_shouldExit) { m_bye(kExitArgs); } - - // set log filter - if (!CLOG->setFilter(args().m_logFilter)) { - LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE, - args().m_pname, args().m_logFilter, args().m_pname)); - m_bye(kExitArgs); + else { + if (!args().m_synergyAddress.empty()) { + try { + *m_synergyAddress = CNetworkAddress(args().m_synergyAddress, + kDefaultPort); + m_synergyAddress->resolve(); + } + catch (XSocketAddress& e) { + LOG((CLOG_PRINT "%s: %s" BYE, + args().m_pname, e.what(), args().m_pname)); + m_bye(kExitArgs); + } + } } - - // identify system - LOG((CLOG_INFO "%s Server on %s %s", kAppVersion, ARCH->getOSName().c_str(), ARCH->getPlatformName().c_str())); - - if (args().m_enableDragDrop) { - LOG((CLOG_INFO "drag and drop enabled")); - } - - loggingFilterWarning(); } void @@ -742,8 +692,8 @@ CServerApp::mainLoop() // set the contact address, if provided, in the config. // otherwise, if the config doesn't have an address, use // the default. - if (args().m_synergyAddress->isValid()) { - args().m_config->setSynergyAddress(*args().m_synergyAddress); + if (m_synergyAddress->isValid()) { + args().m_config->setSynergyAddress(*m_synergyAddress); } else if (!args().m_config->getSynergyAddress().isValid()) { args().m_config->setSynergyAddress(CNetworkAddress(kDefaultPort)); @@ -839,7 +789,7 @@ int CServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) { // general initialization - args().m_synergyAddress = new CNetworkAddress; + m_synergyAddress = new CNetworkAddress; args().m_config = new CConfig(m_events); args().m_pname = ARCH->getBasename(argv[0]); @@ -858,7 +808,7 @@ CServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFun } delete args().m_config; - delete args().m_synergyAddress; + delete m_synergyAddress; return result; } diff --git a/src/lib/synergy/ServerApp.h b/src/lib/synergy/ServerApp.h index b17f654b..83020ad7 100644 --- a/src/lib/synergy/ServerApp.h +++ b/src/lib/synergy/ServerApp.h @@ -18,6 +18,7 @@ #pragma once +#include "synergy/ArgsBase.h" #include "synergy/App.h" #include "base/String.h" #include "server/Config.h" @@ -44,20 +45,10 @@ class CClientListener; class CEventQueueTimer; class ILogOutputter; class IEventQueue; +class CServerArgs; class CServerApp : public CApp { public: - class CArgs : public CArgsBase { - public: - CArgs(); - ~CArgs(); - - public: - CString m_configFile; - CNetworkAddress* m_synergyAddress; - CConfig* m_config; - }; - CServerApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver); virtual ~CServerApp(); @@ -68,7 +59,7 @@ public: void help(); // Returns arguments that are common and for server. - CArgs& args() const { return (CArgs&)argsBase(); } + CServerArgs& args() const { return (CServerArgs&)argsBase(); } const char* daemonName() const; const char* daemonInfo() const; @@ -120,9 +111,9 @@ public: CPrimaryClient* m_primaryClient; CClientListener* m_listener; CEventQueueTimer* m_timer; + CNetworkAddress* m_synergyAddress; private: - virtual bool parseArg(const int& argc, const char* const* argv, int& i); void handleScreenSwitched(const CEvent&, void* data); }; diff --git a/src/lib/synergy/unix/AppUtilUnix.cpp b/src/lib/synergy/unix/AppUtilUnix.cpp index 9445c5cc..786dbef2 100644 --- a/src/lib/synergy/unix/AppUtilUnix.cpp +++ b/src/lib/synergy/unix/AppUtilUnix.cpp @@ -27,31 +27,6 @@ CAppUtilUnix::~CAppUtilUnix() { } -bool -CAppUtilUnix::parseArg(const int& argc, const char* const* argv, int& i) -{ -#if WINAPI_XWINDOWS - if (app().isArg(i, argc, argv, "-display", "--display", 1)) { - // use alternative display - app().argsBase().m_display = argv[++i]; - } - - else if (app().isArg(i, argc, argv, NULL, "--no-xinitthreads")) { - app().argsBase().m_disableXInitThreads = true; - } - - else { - // option not supported here - return false; - } - - return true; -#else - // no options for carbon - return false; -#endif -} - int standardStartupStatic(int argc, char** argv) { diff --git a/src/lib/synergy/unix/AppUtilUnix.h b/src/lib/synergy/unix/AppUtilUnix.h index eb2bbd3a..4b0bb8e3 100644 --- a/src/lib/synergy/unix/AppUtilUnix.h +++ b/src/lib/synergy/unix/AppUtilUnix.h @@ -29,7 +29,6 @@ public: CAppUtilUnix(IEventQueue* events); virtual ~CAppUtilUnix(); - bool parseArg(const int& argc, const char* const* argv, int& i); int run(int argc, char** argv); void startNode(); }; diff --git a/src/lib/synergy/win32/AppUtilWindows.cpp b/src/lib/synergy/win32/AppUtilWindows.cpp index 72e94766..2230f128 100644 --- a/src/lib/synergy/win32/AppUtilWindows.cpp +++ b/src/lib/synergy/win32/AppUtilWindows.cpp @@ -58,29 +58,6 @@ BOOL WINAPI CAppUtilWindows::consoleHandler(DWORD) return TRUE; } -bool -CAppUtilWindows::parseArg(const int& argc, const char* const* argv, int& i) -{ - if (app().isArg(i, argc, argv, NULL, "--service")) { - - LOG((CLOG_WARN "obsolete argument --service, use synergyd instead.")); - app().bye(kExitFailed); - } - else if (app().isArg(i, argc, argv, NULL, "--exit-pause")) { - - app().argsBase().m_pauseOnExit = true; - } - else if (app().isArg(i, argc, argv, NULL, "--stop-on-desk-switch")) { - app().argsBase().m_stopOnDeskSwitch = true; - } - else { - // option not supported here - return false; - } - - return true; -} - static int mainLoopStatic() diff --git a/src/lib/synergy/win32/AppUtilWindows.h b/src/lib/synergy/win32/AppUtilWindows.h index 10c8e7c5..c51a09a6 100644 --- a/src/lib/synergy/win32/AppUtilWindows.h +++ b/src/lib/synergy/win32/AppUtilWindows.h @@ -38,8 +38,6 @@ public: CAppUtilWindows(IEventQueue* events); virtual ~CAppUtilWindows(); - bool parseArg(const int& argc, const char* const* argv, int& i); - int daemonNTStartup(int, char**); int daemonNTMainLoop(int argc, const char** argv); From a71ebc78b37120aad8508fbd3aa0daffe30088df Mon Sep 17 00:00:00 2001 From: Xinyu Hou Date: Thu, 23 Oct 2014 11:37:59 +0100 Subject: [PATCH 15/16] Parse arg refactoring #4124 Fixed compile error on Linux --- src/lib/synergy/ArgParser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/synergy/ArgParser.cpp b/src/lib/synergy/ArgParser.cpp index 7ab7ab9a..c7ae05f3 100644 --- a/src/lib/synergy/ArgParser.cpp +++ b/src/lib/synergy/ArgParser.cpp @@ -134,12 +134,12 @@ CArgParser::parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* c return true; #elif WINAPI_XWINDOWS - if (CArgumentParser::isArg(i, argc, argv, "-display", "--display", 1)) { + if (isArg(i, argc, argv, "-display", "--display", 1)) { // use alternative display argsBase.m_display = argv[++i]; } - else if (CArgumentParser::isArg(i, argc, argv, NULL, "--no-xinitthreads")) { + else if (isArg(i, argc, argv, NULL, "--no-xinitthreads")) { argsBase.m_disableXInitThreads = true; } From a32cb413429a914292c1457a12753650c0f241fb Mon Sep 17 00:00:00 2001 From: Xinyu Hou Date: Thu, 23 Oct 2014 12:09:09 +0100 Subject: [PATCH 16/16] Parse arg refactoring #4124 Used argParser in DaemonApp. --- src/lib/synergy/DaemonApp.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/lib/synergy/DaemonApp.cpp b/src/lib/synergy/DaemonApp.cpp index e8e8007b..43bab0cb 100644 --- a/src/lib/synergy/DaemonApp.cpp +++ b/src/lib/synergy/DaemonApp.cpp @@ -22,6 +22,9 @@ #include "synergy/DaemonApp.h" #include "synergy/App.h" +#include "synergy/ArgParser.h" +#include "synergy/ServerArgs.h" +#include "synergy/ClientArgs.h" #include "ipc/IpcClientProxy.h" #include "ipc/IpcMessage.h" #include "ipc/IpcLogOutputter.h" @@ -301,13 +304,29 @@ CDaemonApp::handleIpcMessage(const CEvent& e, void*) if (!command.empty()) { LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); - CString debugArg("--debug"); - UInt32 debugArgPos = static_cast(command.find(debugArg)); - if (debugArgPos != CString::npos) { - UInt32 from = debugArgPos + static_cast(debugArg.size()) + 1; - UInt32 nextSpace = static_cast(command.find(" ", from)); - CString logLevel(command.substr(from, nextSpace - from)); + std::vector argsArray; + CArgParser::splitCommandString(command, argsArray); + CArgParser argParser(NULL); + const char** argv = argParser.getArgv(argsArray); + CServerArgs serverArgs; + CClientArgs clientArgs; + int argc = static_cast(argsArray.size()); + bool server = argsArray[0].find("synergys") != CString::npos ? true : false; + CArgsBase* argBase = NULL; + + if (server) { + argParser.parseServerArgs(serverArgs, argc, argv); + argBase = &serverArgs; + } + else { + argParser.parseClientArgs(clientArgs, argc, argv); + argBase = &clientArgs; + } + + delete[] argv; + CString logLevel(argBase->m_logFilter); + if (!logLevel.empty()) { try { // change log level based on that in the command string // and change to that log level now.