|
|
|
@ -47,32 +47,205 @@
@@ -47,32 +47,205 @@
|
|
|
|
|
|
|
|
|
|
namespace |
|
|
|
|
{ |
|
|
|
|
bool isBoolEnvVarSetToTrue(const QProcessEnvironment &env, const QString &var) |
|
|
|
|
// Base option class. Encapsulates name operations.
|
|
|
|
|
class Option |
|
|
|
|
{ |
|
|
|
|
QString val = env.value(var); |
|
|
|
|
// we accept "1" and "true" (upper or lower cased) as boolean 'true' values
|
|
|
|
|
return (val == QLatin1String("1") || val.toUpper() == QLatin1String("TRUE")); |
|
|
|
|
protected: |
|
|
|
|
constexpr Option(const char *name, char shortcut = 0) |
|
|
|
|
: m_name {name} |
|
|
|
|
, m_shortcut {shortcut} |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QString fullParameter() const |
|
|
|
|
{ |
|
|
|
|
return QLatin1String("--") + QLatin1String(m_name); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QString shortcutParameter() const |
|
|
|
|
{ |
|
|
|
|
return QLatin1String("-") + QLatin1Char(m_shortcut); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool hasShortcut() const |
|
|
|
|
{ |
|
|
|
|
return m_shortcut != 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QString envVarName() const |
|
|
|
|
{ |
|
|
|
|
return QLatin1String("QBT_") |
|
|
|
|
+ QString(QLatin1String(m_name)).toUpper().replace(QLatin1Char('-'), QLatin1Char('_')); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static QString padUsageText(const QString &usage) |
|
|
|
|
{ |
|
|
|
|
const int TAB_WIDTH = 8; |
|
|
|
|
QString res = QLatin1String("\t") + usage; |
|
|
|
|
if (usage.size() < 2 * TAB_WIDTH) |
|
|
|
|
return res + QLatin1String("\t\t"); |
|
|
|
|
else |
|
|
|
|
return res + QLatin1String("\t"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
const char *m_name; |
|
|
|
|
const char m_shortcut; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Boolean option.
|
|
|
|
|
class BoolOption: protected Option |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
constexpr BoolOption(const char *name, char shortcut = 0) |
|
|
|
|
: Option {name, shortcut} |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool operator==(const QString &arg) const |
|
|
|
|
{ |
|
|
|
|
return (hasShortcut() && ((arg.size() == 2) && (arg == shortcutParameter()))) |
|
|
|
|
|| (arg == fullParameter()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool value(const QProcessEnvironment &env) const |
|
|
|
|
{ |
|
|
|
|
QString val = env.value(envVarName()); |
|
|
|
|
// we accept "1" and "true" (upper or lower cased) as boolean 'true' values
|
|
|
|
|
return (val == QLatin1String("1") || val.toUpper() == QLatin1String("TRUE")); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QString usage() const |
|
|
|
|
{ |
|
|
|
|
QString res; |
|
|
|
|
if (hasShortcut()) |
|
|
|
|
res += shortcutParameter() + QLatin1String(" | "); |
|
|
|
|
res += fullParameter(); |
|
|
|
|
return padUsageText(res); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
inline bool operator==(const QString &s, const BoolOption &o) |
|
|
|
|
{ |
|
|
|
|
return o == s; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int readIntlEnvVar(const QProcessEnvironment &env, const QString &var, int defaultValue) |
|
|
|
|
// Option with string value. May not have a shortcut
|
|
|
|
|
struct StringOption: protected Option |
|
|
|
|
{ |
|
|
|
|
QString val = env.value(var); |
|
|
|
|
if (val.isEmpty()) return defaultValue; |
|
|
|
|
bool ok; |
|
|
|
|
int res = val.toInt(&ok); |
|
|
|
|
if (!ok) { |
|
|
|
|
qDebug() << QObject::tr("Expected integer number in environment variable '%1', but got '%2'") |
|
|
|
|
.arg(var).arg(val); |
|
|
|
|
return defaultValue; |
|
|
|
|
} |
|
|
|
|
return res; |
|
|
|
|
public: |
|
|
|
|
constexpr StringOption(const char *name) |
|
|
|
|
: Option {name, 0} |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool operator==(const QString &arg) const |
|
|
|
|
{ |
|
|
|
|
return arg.startsWith(parameterAssignment()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QString value(const QString &arg) const |
|
|
|
|
{ |
|
|
|
|
QStringList parts = arg.split(QLatin1Char('=')); |
|
|
|
|
if (parts.size() == 2) |
|
|
|
|
return unquote(parts[1]); |
|
|
|
|
throw CommandLineParameterError(QObject::tr("Parameter '%1' must follow syntax '%1=%2'", |
|
|
|
|
"e.g. Parameter '--webui-port' must follow syntax '--webui-port=value'") |
|
|
|
|
.arg(fullParameter()).arg(QLatin1String("<value>"))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QString value(const QProcessEnvironment &env, const QString &defaultValue = QString()) const |
|
|
|
|
{ |
|
|
|
|
QString val = env.value(envVarName()); |
|
|
|
|
return val.isEmpty() ? defaultValue : unquote(val); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QString usage(const QString &valueName) const |
|
|
|
|
{ |
|
|
|
|
return padUsageText(parameterAssignment() + QLatin1Char('<') + valueName + QLatin1Char('>')); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
QString parameterAssignment() const |
|
|
|
|
{ |
|
|
|
|
return fullParameter() + QLatin1Char('='); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static QString unquote(const QString &s) |
|
|
|
|
{ |
|
|
|
|
auto isStringQuoted = |
|
|
|
|
[](const QString &s, QChar quoteChar) |
|
|
|
|
{ |
|
|
|
|
return (s.startsWith(quoteChar) && s.endsWith(quoteChar)); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if ((s.size() >= 2) && (isStringQuoted(s, QLatin1Char('\'')) || isStringQuoted(s, QLatin1Char('"')))) |
|
|
|
|
return s.mid(1, s.size() - 2); |
|
|
|
|
return s; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
inline bool operator==(const QString &s, const StringOption &o) |
|
|
|
|
{ |
|
|
|
|
return o == s; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QString envVarNameForParameter(const char *parameterName) |
|
|
|
|
// Option with integer value. May not have a shortcut
|
|
|
|
|
class IntOption: protected StringOption |
|
|
|
|
{ |
|
|
|
|
return QLatin1String("QBT_") + |
|
|
|
|
QString(QLatin1String(parameterName)).toUpper().replace(QLatin1Char('-'), QLatin1Char('_')); |
|
|
|
|
public: |
|
|
|
|
constexpr IntOption(const char *name) |
|
|
|
|
: StringOption {name} |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
using StringOption::operator==; |
|
|
|
|
using StringOption::usage; |
|
|
|
|
|
|
|
|
|
int value(const QString &arg) const |
|
|
|
|
{ |
|
|
|
|
QString val = StringOption::value(arg); |
|
|
|
|
bool ok = false; |
|
|
|
|
int res = val.toInt(&ok); |
|
|
|
|
if (!ok) |
|
|
|
|
throw CommandLineParameterError(QObject::tr("Parameter '%1' must follow syntax '%1=%2'", |
|
|
|
|
"e.g. Parameter '--webui-port' must follow syntax '--webui-port=<value>'") |
|
|
|
|
.arg(fullParameter()).arg(QLatin1String("<integer value>"))); |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int value(const QProcessEnvironment &env, int defaultValue) const |
|
|
|
|
{ |
|
|
|
|
QString val = env.value(envVarName()); |
|
|
|
|
if (val.isEmpty()) return defaultValue; |
|
|
|
|
|
|
|
|
|
bool ok; |
|
|
|
|
int res = val.toInt(&ok); |
|
|
|
|
if (!ok) { |
|
|
|
|
qDebug() << QObject::tr("Expected integer number in environment variable '%1', but got '%2'") |
|
|
|
|
.arg(envVarName()).arg(val); |
|
|
|
|
return defaultValue; |
|
|
|
|
} |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
inline bool operator==(const QString &s, const IntOption &o) |
|
|
|
|
{ |
|
|
|
|
return o == s; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
constexpr const BoolOption SHOW_HELP_OPTION = {"help", 'h'}; |
|
|
|
|
constexpr const BoolOption SHOW_VERSION_OPTION = {"version", 'v'}; |
|
|
|
|
#ifdef DISABLE_GUI |
|
|
|
|
constexpr const BoolOption DAEMON_OPTION = {"daemon", 'd'}; |
|
|
|
|
#else |
|
|
|
|
constexpr const BoolOption NO_SPLASH_OPTION = {"no-splash"}; |
|
|
|
|
#endif |
|
|
|
|
constexpr const IntOption WEBUI_PORT_OPTION = {"webui-port"}; |
|
|
|
|
constexpr const StringOption PROFILE_OPTION = {"profile"}; |
|
|
|
|
constexpr const StringOption CONFIGURATION_OPTION = {"configuration"}; |
|
|
|
|
constexpr const BoolOption PORTABLE_OPTION = {"portable"}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &env) |
|
|
|
@ -81,14 +254,14 @@ QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &en
@@ -81,14 +254,14 @@ QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &en
|
|
|
|
|
, showVersion(false) |
|
|
|
|
#endif |
|
|
|
|
#ifndef DISABLE_GUI |
|
|
|
|
, noSplash(isBoolEnvVarSetToTrue(env, envVarNameForParameter("no-splash"))) |
|
|
|
|
, noSplash(NO_SPLASH_OPTION.value(env)) |
|
|
|
|
#else |
|
|
|
|
, shouldDaemonize(isBoolEnvVarSetToTrue(env, envVarNameForParameter("daemon"))) |
|
|
|
|
, shouldDaemonize(DAEMON_OPTION.value(env)) |
|
|
|
|
#endif |
|
|
|
|
, webUiPort(readIntlEnvVar(env, envVarNameForParameter("webui-port"), -1)) |
|
|
|
|
, profileDir(env.value(envVarNameForParameter("profile"))) |
|
|
|
|
, portableMode(isBoolEnvVarSetToTrue(env, envVarNameForParameter("portable"))) |
|
|
|
|
, configurationName(env.value(envVarNameForParameter("configuration"))) |
|
|
|
|
, webUiPort(WEBUI_PORT_OPTION.value(env, -1)) |
|
|
|
|
, profileDir(PROFILE_OPTION.value(env)) |
|
|
|
|
, portableMode(PORTABLE_OPTION.value(env)) |
|
|
|
|
, configurationName(CONFIGURATION_OPTION.value(env)) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -102,45 +275,37 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
@@ -102,45 +275,37 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args)
|
|
|
|
|
if ((arg.startsWith("--") && !arg.endsWith(".torrent")) |
|
|
|
|
|| (arg.startsWith("-") && (arg.size() == 2))) { |
|
|
|
|
// Parse known parameters
|
|
|
|
|
if ((arg == QLatin1String("-h")) || (arg == QLatin1String("--help"))) { |
|
|
|
|
if ((arg == SHOW_HELP_OPTION)) { |
|
|
|
|
result.showHelp = true; |
|
|
|
|
} |
|
|
|
|
#ifndef Q_OS_WIN |
|
|
|
|
else if ((arg == QLatin1String("-v")) || (arg == QLatin1String("--version"))) { |
|
|
|
|
else if (arg == SHOW_VERSION_OPTION) { |
|
|
|
|
result.showVersion = true; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
else if (arg.startsWith(QLatin1String("--webui-port="))) { |
|
|
|
|
QStringList parts = arg.split(QLatin1Char('=')); |
|
|
|
|
if (parts.size() == 2) { |
|
|
|
|
bool ok = false; |
|
|
|
|
result.webUiPort = parts.last().toInt(&ok); |
|
|
|
|
if (!ok || (result.webUiPort < 1) || (result.webUiPort > 65535)) |
|
|
|
|
throw CommandLineParameterError(QObject::tr("%1 must specify the correct port (1 to 65535).") |
|
|
|
|
.arg(QLatin1String("--webui-port"))); |
|
|
|
|
} |
|
|
|
|
else if (arg == WEBUI_PORT_OPTION) { |
|
|
|
|
result.webUiPort = WEBUI_PORT_OPTION.value(arg); |
|
|
|
|
if ((result.webUiPort < 1) || (result.webUiPort > 65535)) |
|
|
|
|
throw CommandLineParameterError(QObject::tr("%1 must specify the correct port (1 to 65535).") |
|
|
|
|
.arg(QLatin1String("--webui-port"))); |
|
|
|
|
} |
|
|
|
|
#ifndef DISABLE_GUI |
|
|
|
|
else if (arg == QLatin1String("--no-splash")) { |
|
|
|
|
else if (arg == NO_SPLASH_OPTION) { |
|
|
|
|
result.noSplash = true; |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
else if ((arg == QLatin1String("-d")) || (arg == QLatin1String("--daemon"))) { |
|
|
|
|
else if (arg == DAEMON_OPTION) { |
|
|
|
|
result.shouldDaemonize = true; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
else if (arg == QLatin1String("--profile")) { |
|
|
|
|
QStringList parts = arg.split(QLatin1Char('=')); |
|
|
|
|
if (parts.size() == 2) |
|
|
|
|
result.profileDir = parts.last(); |
|
|
|
|
else if (arg == PROFILE_OPTION) { |
|
|
|
|
result.profileDir = PROFILE_OPTION.value(arg); |
|
|
|
|
} |
|
|
|
|
else if (arg == QLatin1String("--portable")) { |
|
|
|
|
else if (arg == PORTABLE_OPTION) { |
|
|
|
|
result.portableMode = true; |
|
|
|
|
} |
|
|
|
|
else if (arg == QLatin1String("--configuration")) { |
|
|
|
|
QStringList parts = arg.split(QLatin1Char('=')); |
|
|
|
|
if (parts.size() == 2) |
|
|
|
|
result.configurationName = parts.last(); |
|
|
|
|
else if (arg == CONFIGURATION_OPTION) { |
|
|
|
|
result.configurationName = CONFIGURATION_OPTION.value(arg); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
// Unknown argument
|
|
|
|
@ -185,20 +350,20 @@ QString makeUsage(const QString &prgName)
@@ -185,20 +350,20 @@ QString makeUsage(const QString &prgName)
|
|
|
|
|
|
|
|
|
|
stream << QObject::tr("Options:") << '\n'; |
|
|
|
|
#ifndef Q_OS_WIN |
|
|
|
|
stream << "\t-v | --version\t\t" << QObject::tr("Displays program version and exit") << '\n'; |
|
|
|
|
stream << SHOW_VERSION_OPTION.usage() << QObject::tr("Displays program version and exit") << '\n'; |
|
|
|
|
#endif |
|
|
|
|
stream << "\t-h | --help\t\t" << QObject::tr("Displays this help message and exit") << '\n'; |
|
|
|
|
stream << "\t--webui-port=<port>\t" |
|
|
|
|
stream << SHOW_HELP_OPTION.usage() << QObject::tr("Displays this help message and exit") << '\n'; |
|
|
|
|
stream << WEBUI_PORT_OPTION.usage(QLatin1String("port")) |
|
|
|
|
<< QObject::tr("Changes the Web UI port") |
|
|
|
|
<< '\n'; |
|
|
|
|
#ifndef DISABLE_GUI |
|
|
|
|
stream << "\t--no-splash\t\t" << QObject::tr("Disable splash screen") << '\n'; |
|
|
|
|
stream << NO_SPLASH_OPTION.usage() << QObject::tr("Disable splash screen") << '\n'; |
|
|
|
|
#else |
|
|
|
|
stream << "\t-d | --daemon\t\t" << QObject::tr("Run in daemon-mode (background)") << '\n'; |
|
|
|
|
stream << DAEMON_OPTION.usage() << QObject::tr("Run in daemon-mode (background)") << '\n'; |
|
|
|
|
#endif |
|
|
|
|
stream << "\t--profile=<dir>\t\t" << QObject::tr("Store configuration files in <dir>") << '\n'; |
|
|
|
|
stream << "\t--portable\t\t" << QObject::tr("Shortcut for --profile=<exe dir>/profile") << '\n'; |
|
|
|
|
stream << "\t--configuration=<name>\t" << QObject::tr("Store configuration files in directories qBittorrent_<name>") |
|
|
|
|
stream << PROFILE_OPTION.usage(QLatin1String("dir")) << QObject::tr("Store configuration files in <dir>") << '\n'; |
|
|
|
|
stream << PORTABLE_OPTION.usage() << QObject::tr("Shortcut for --profile=<exe dir>/profile") << '\n'; |
|
|
|
|
stream << CONFIGURATION_OPTION.usage(QLatin1String("name")) << QObject::tr("Store configuration files in directories qBittorrent_<name>") |
|
|
|
|
<< '\n'; |
|
|
|
|
stream << "\tfiles or urls\t\t" << QObject::tr("Downloads the torrents passed by the user") << '\n' |
|
|
|
|
<< '\n'; |
|
|
|
|