Remove cli functionality from bitcoind
As it says on the tin. It was deprecated in version 0.9, and at some point it should be removed. Removes the dependency of bitcoind on libbitcoin-cli.a. Move some functions that used to be shared but are now only used in bitcoin-cli.cpp to that file. After this change, an error is printed (and exit code 1 is returned) when the user tries to send RPC commands using bitcoind.
This commit is contained in:
parent
0cafb63025
commit
b750cf1fb9
5 changed files with 160 additions and 196 deletions
|
@ -171,7 +171,6 @@ nodist_libbitcoin_common_a_SOURCES = $(srcdir)/obj/build.h
|
||||||
# bitcoind binary #
|
# bitcoind binary #
|
||||||
bitcoind_LDADD = \
|
bitcoind_LDADD = \
|
||||||
libbitcoin_server.a \
|
libbitcoin_server.a \
|
||||||
libbitcoin_cli.a \
|
|
||||||
libbitcoin_common.a \
|
libbitcoin_common.a \
|
||||||
$(LIBLEVELDB) \
|
$(LIBLEVELDB) \
|
||||||
$(LIBMEMENV)
|
$(LIBMEMENV)
|
||||||
|
|
|
@ -12,6 +12,32 @@
|
||||||
|
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
|
|
||||||
|
using namespace boost;
|
||||||
|
using namespace boost::asio;
|
||||||
|
using namespace json_spirit;
|
||||||
|
|
||||||
|
std::string HelpMessageCli()
|
||||||
|
{
|
||||||
|
string strUsage;
|
||||||
|
strUsage += _("Options:") + "\n";
|
||||||
|
strUsage += " -? " + _("This help message") + "\n";
|
||||||
|
strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n";
|
||||||
|
strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n";
|
||||||
|
strUsage += " -testnet " + _("Use the test network") + "\n";
|
||||||
|
strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be "
|
||||||
|
"solved instantly. This is intended for regression testing tools and app development.") + "\n";
|
||||||
|
strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n";
|
||||||
|
strUsage += " -rpcport=<port> " + _("Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)") + "\n";
|
||||||
|
strUsage += " -rpcwait " + _("Wait for RPC server to start") + "\n";
|
||||||
|
strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
|
||||||
|
strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
|
||||||
|
|
||||||
|
strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
|
||||||
|
strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
|
||||||
|
|
||||||
|
return strUsage;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Start
|
// Start
|
||||||
|
@ -49,7 +75,7 @@ static bool AppInitRPC(int argc, char* argv[])
|
||||||
" bitcoin-cli [options] help " + _("List commands") + "\n" +
|
" bitcoin-cli [options] help " + _("List commands") + "\n" +
|
||||||
" bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
|
" bitcoin-cli [options] help <command> " + _("Get help for a command") + "\n";
|
||||||
|
|
||||||
strUsage += "\n" + HelpMessageCli(true);
|
strUsage += "\n" + HelpMessageCli();
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stdout, "%s", strUsage.c_str());
|
fprintf(stdout, "%s", strUsage.c_str());
|
||||||
|
@ -58,6 +84,136 @@ static bool AppInitRPC(int argc, char* argv[])
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object CallRPC(const string& strMethod, const Array& params)
|
||||||
|
{
|
||||||
|
if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
|
||||||
|
throw runtime_error(strprintf(
|
||||||
|
_("You must set rpcpassword=<password> in the configuration file:\n%s\n"
|
||||||
|
"If the file does not exist, create it with owner-readable-only file permissions."),
|
||||||
|
GetConfigFile().string().c_str()));
|
||||||
|
|
||||||
|
// Connect to localhost
|
||||||
|
bool fUseSSL = GetBoolArg("-rpcssl", false);
|
||||||
|
asio::io_service io_service;
|
||||||
|
ssl::context context(io_service, ssl::context::sslv23);
|
||||||
|
context.set_options(ssl::context::no_sslv2);
|
||||||
|
asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
|
||||||
|
SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
|
||||||
|
iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
|
||||||
|
|
||||||
|
bool fWait = GetBoolArg("-rpcwait", false); // -rpcwait means try until server has started
|
||||||
|
do {
|
||||||
|
bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(Params().RPCPort())));
|
||||||
|
if (fConnected) break;
|
||||||
|
if (fWait)
|
||||||
|
MilliSleep(1000);
|
||||||
|
else
|
||||||
|
throw runtime_error("couldn't connect to server");
|
||||||
|
} while (fWait);
|
||||||
|
|
||||||
|
// HTTP basic authentication
|
||||||
|
string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
|
||||||
|
map<string, string> mapRequestHeaders;
|
||||||
|
mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
|
||||||
|
|
||||||
|
// Send request
|
||||||
|
string strRequest = JSONRPCRequest(strMethod, params, 1);
|
||||||
|
string strPost = HTTPPost(strRequest, mapRequestHeaders);
|
||||||
|
stream << strPost << std::flush;
|
||||||
|
|
||||||
|
// Receive HTTP reply status
|
||||||
|
int nProto = 0;
|
||||||
|
int nStatus = ReadHTTPStatus(stream, nProto);
|
||||||
|
|
||||||
|
// Receive HTTP reply message headers and body
|
||||||
|
map<string, string> mapHeaders;
|
||||||
|
string strReply;
|
||||||
|
ReadHTTPMessage(stream, mapHeaders, strReply, nProto);
|
||||||
|
|
||||||
|
if (nStatus == HTTP_UNAUTHORIZED)
|
||||||
|
throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
|
||||||
|
else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
|
||||||
|
throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
|
||||||
|
else if (strReply.empty())
|
||||||
|
throw runtime_error("no response from server");
|
||||||
|
|
||||||
|
// Parse reply
|
||||||
|
Value valReply;
|
||||||
|
if (!read_string(strReply, valReply))
|
||||||
|
throw runtime_error("couldn't parse reply from server");
|
||||||
|
const Object& reply = valReply.get_obj();
|
||||||
|
if (reply.empty())
|
||||||
|
throw runtime_error("expected reply to have result, error and id properties");
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CommandLineRPC(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
string strPrint;
|
||||||
|
int nRet = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Skip switches
|
||||||
|
while (argc > 1 && IsSwitchChar(argv[1][0]))
|
||||||
|
{
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method
|
||||||
|
if (argc < 2)
|
||||||
|
throw runtime_error("too few parameters");
|
||||||
|
string strMethod = argv[1];
|
||||||
|
|
||||||
|
// Parameters default to strings
|
||||||
|
std::vector<std::string> strParams(&argv[2], &argv[argc]);
|
||||||
|
Array params = RPCConvertValues(strMethod, strParams);
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
Object reply = CallRPC(strMethod, params);
|
||||||
|
|
||||||
|
// Parse reply
|
||||||
|
const Value& result = find_value(reply, "result");
|
||||||
|
const Value& error = find_value(reply, "error");
|
||||||
|
|
||||||
|
if (error.type() != null_type)
|
||||||
|
{
|
||||||
|
// Error
|
||||||
|
strPrint = "error: " + write_string(error, false);
|
||||||
|
int code = find_value(error.get_obj(), "code").get_int();
|
||||||
|
nRet = abs(code);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Result
|
||||||
|
if (result.type() == null_type)
|
||||||
|
strPrint = "";
|
||||||
|
else if (result.type() == str_type)
|
||||||
|
strPrint = result.get_str();
|
||||||
|
else
|
||||||
|
strPrint = write_string(result, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (boost::thread_interrupted) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (std::exception& e) {
|
||||||
|
strPrint = string("error: ") + e.what();
|
||||||
|
nRet = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
PrintExceptionContinue(NULL, "CommandLineRPC()");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strPrint != "")
|
||||||
|
{
|
||||||
|
fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
|
||||||
|
}
|
||||||
|
return nRet;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
SetupEnvironment();
|
SetupEnvironment();
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include "rpcserver.h"
|
#include "rpcserver.h"
|
||||||
#include "rpcclient.h"
|
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "noui.h"
|
#include "noui.h"
|
||||||
|
@ -94,14 +93,9 @@ bool AppInit(int argc, char* argv[])
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strUsage += "\n" + _("Usage:") + "\n" +
|
strUsage += "\n" + _("Usage:") + "\n" +
|
||||||
" bitcoind [options] " + _("Start Bitcoin Core Daemon") + "\n" +
|
" bitcoind [options] " + _("Start Bitcoin Core Daemon") + "\n";
|
||||||
_("Usage (deprecated, use bitcoin-cli):") + "\n" +
|
|
||||||
" bitcoind [options] <command> [params] " + _("Send command to Bitcoin Core") + "\n" +
|
|
||||||
" bitcoind [options] help " + _("List commands") + "\n" +
|
|
||||||
" bitcoind [options] help <command> " + _("Get help for a command") + "\n";
|
|
||||||
|
|
||||||
strUsage += "\n" + HelpMessage(HMM_BITCOIND);
|
strUsage += "\n" + HelpMessage(HMM_BITCOIND);
|
||||||
strUsage += "\n" + HelpMessageCli(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stdout, "%s", strUsage.c_str());
|
fprintf(stdout, "%s", strUsage.c_str());
|
||||||
|
@ -116,8 +110,8 @@ bool AppInit(int argc, char* argv[])
|
||||||
|
|
||||||
if (fCommandLine)
|
if (fCommandLine)
|
||||||
{
|
{
|
||||||
int ret = CommandLineRPC(argc, argv);
|
fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n");
|
||||||
exit(ret);
|
exit(1);
|
||||||
}
|
}
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
fDaemon = GetBoolArg("-daemon", false);
|
fDaemon = GetBoolArg("-daemon", false);
|
||||||
|
|
|
@ -12,86 +12,9 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <boost/asio/ssl.hpp>
|
|
||||||
#include <boost/bind.hpp>
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <boost/foreach.hpp>
|
|
||||||
#include <boost/iostreams/concepts.hpp>
|
|
||||||
#include <boost/iostreams/stream.hpp>
|
|
||||||
#include <boost/shared_ptr.hpp>
|
|
||||||
#include "json/json_spirit_writer_template.h"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace boost;
|
|
||||||
using namespace boost::asio;
|
|
||||||
using namespace json_spirit;
|
using namespace json_spirit;
|
||||||
|
|
||||||
Object CallRPC(const string& strMethod, const Array& params)
|
|
||||||
{
|
|
||||||
if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
|
|
||||||
throw runtime_error(strprintf(
|
|
||||||
_("You must set rpcpassword=<password> in the configuration file:\n%s\n"
|
|
||||||
"If the file does not exist, create it with owner-readable-only file permissions."),
|
|
||||||
GetConfigFile().string().c_str()));
|
|
||||||
|
|
||||||
// Connect to localhost
|
|
||||||
bool fUseSSL = GetBoolArg("-rpcssl", false);
|
|
||||||
asio::io_service io_service;
|
|
||||||
ssl::context context(io_service, ssl::context::sslv23);
|
|
||||||
context.set_options(ssl::context::no_sslv2);
|
|
||||||
asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
|
|
||||||
SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
|
|
||||||
iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
|
|
||||||
|
|
||||||
bool fWait = GetBoolArg("-rpcwait", false); // -rpcwait means try until server has started
|
|
||||||
do {
|
|
||||||
bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(Params().RPCPort())));
|
|
||||||
if (fConnected) break;
|
|
||||||
if (fWait)
|
|
||||||
MilliSleep(1000);
|
|
||||||
else
|
|
||||||
throw runtime_error("couldn't connect to server");
|
|
||||||
} while (fWait);
|
|
||||||
|
|
||||||
// HTTP basic authentication
|
|
||||||
string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
|
|
||||||
map<string, string> mapRequestHeaders;
|
|
||||||
mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
|
|
||||||
|
|
||||||
// Send request
|
|
||||||
string strRequest = JSONRPCRequest(strMethod, params, 1);
|
|
||||||
string strPost = HTTPPost(strRequest, mapRequestHeaders);
|
|
||||||
stream << strPost << std::flush;
|
|
||||||
|
|
||||||
// Receive HTTP reply status
|
|
||||||
int nProto = 0;
|
|
||||||
int nStatus = ReadHTTPStatus(stream, nProto);
|
|
||||||
|
|
||||||
// Receive HTTP reply message headers and body
|
|
||||||
map<string, string> mapHeaders;
|
|
||||||
string strReply;
|
|
||||||
ReadHTTPMessage(stream, mapHeaders, strReply, nProto);
|
|
||||||
|
|
||||||
if (nStatus == HTTP_UNAUTHORIZED)
|
|
||||||
throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
|
|
||||||
else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
|
|
||||||
throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
|
|
||||||
else if (strReply.empty())
|
|
||||||
throw runtime_error("no response from server");
|
|
||||||
|
|
||||||
// Parse reply
|
|
||||||
Value valReply;
|
|
||||||
if (!read_string(strReply, valReply))
|
|
||||||
throw runtime_error("couldn't parse reply from server");
|
|
||||||
const Object& reply = valReply.get_obj();
|
|
||||||
if (reply.empty())
|
|
||||||
throw runtime_error("expected reply to have result, error and id properties");
|
|
||||||
|
|
||||||
return reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void ConvertTo(Value& value, bool fAllowNull=false)
|
void ConvertTo(Value& value, bool fAllowNull=false)
|
||||||
{
|
{
|
||||||
|
@ -182,101 +105,3 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CommandLineRPC(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
string strPrint;
|
|
||||||
int nRet = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Skip switches
|
|
||||||
while (argc > 1 && IsSwitchChar(argv[1][0]))
|
|
||||||
{
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method
|
|
||||||
if (argc < 2)
|
|
||||||
throw runtime_error("too few parameters");
|
|
||||||
string strMethod = argv[1];
|
|
||||||
|
|
||||||
// Parameters default to strings
|
|
||||||
std::vector<std::string> strParams(&argv[2], &argv[argc]);
|
|
||||||
Array params = RPCConvertValues(strMethod, strParams);
|
|
||||||
|
|
||||||
// Execute
|
|
||||||
Object reply = CallRPC(strMethod, params);
|
|
||||||
|
|
||||||
// Parse reply
|
|
||||||
const Value& result = find_value(reply, "result");
|
|
||||||
const Value& error = find_value(reply, "error");
|
|
||||||
|
|
||||||
if (error.type() != null_type)
|
|
||||||
{
|
|
||||||
// Error
|
|
||||||
strPrint = "error: " + write_string(error, false);
|
|
||||||
int code = find_value(error.get_obj(), "code").get_int();
|
|
||||||
nRet = abs(code);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Result
|
|
||||||
if (result.type() == null_type)
|
|
||||||
strPrint = "";
|
|
||||||
else if (result.type() == str_type)
|
|
||||||
strPrint = result.get_str();
|
|
||||||
else
|
|
||||||
strPrint = write_string(result, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (boost::thread_interrupted) {
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (std::exception& e) {
|
|
||||||
strPrint = string("error: ") + e.what();
|
|
||||||
nRet = EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
PrintExceptionContinue(NULL, "CommandLineRPC()");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strPrint != "")
|
|
||||||
{
|
|
||||||
fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
|
|
||||||
}
|
|
||||||
return nRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string HelpMessageCli(bool mainProgram)
|
|
||||||
{
|
|
||||||
string strUsage;
|
|
||||||
if(mainProgram)
|
|
||||||
{
|
|
||||||
strUsage += _("Options:") + "\n";
|
|
||||||
strUsage += " -? " + _("This help message") + "\n";
|
|
||||||
strUsage += " -conf=<file> " + _("Specify configuration file (default: bitcoin.conf)") + "\n";
|
|
||||||
strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n";
|
|
||||||
strUsage += " -testnet " + _("Use the test network") + "\n";
|
|
||||||
strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be "
|
|
||||||
"solved instantly. This is intended for regression testing tools and app development.") + "\n";
|
|
||||||
} else {
|
|
||||||
strUsage += _("RPC client options:") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
strUsage += " -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n";
|
|
||||||
strUsage += " -rpcport=<port> " + _("Connect to JSON-RPC on <port> (default: 8332 or testnet: 18332)") + "\n";
|
|
||||||
strUsage += " -rpcwait " + _("Wait for RPC server to start") + "\n";
|
|
||||||
|
|
||||||
if(mainProgram)
|
|
||||||
{
|
|
||||||
strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
|
|
||||||
strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
|
|
||||||
|
|
||||||
strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
|
|
||||||
strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return strUsage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -10,16 +10,6 @@
|
||||||
#include "json/json_spirit_utils.h"
|
#include "json/json_spirit_utils.h"
|
||||||
#include "json/json_spirit_writer_template.h"
|
#include "json/json_spirit_writer_template.h"
|
||||||
|
|
||||||
int CommandLineRPC(int argc, char *argv[]);
|
|
||||||
|
|
||||||
json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams);
|
json_spirit::Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams);
|
||||||
|
|
||||||
/** Show help message for bitcoin-cli.
|
|
||||||
* The mainProgram argument is used to determine whether to show this message as main program
|
|
||||||
* (and include some common options) or as sub-header of another help message.
|
|
||||||
*
|
|
||||||
* @note the argument can be removed once bitcoin-cli functionality is removed from bitcoind
|
|
||||||
*/
|
|
||||||
std::string HelpMessageCli(bool mainProgram);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue