Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions doc/release-notes-33540.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
### Tools and Utilities

Command-line tools
------------------

- Command-line options may now be specified after non-option arguments. For example, `bitcoin-cli getblockchaininfo -rpcwait` now behaves the same as `bitcoin-cli -rpcwait getblockchaininfo`, matching common GNU-style option parsing behavior.

- Options beginning with a double dash (`--`) that appear after the RPC method name are interpreted as RPC named parameters. Other option prefixes, such as single dashes (`-`) and Windows-style forward slashes (`/`), continue to be interpreted as command-line options.
24 changes: 15 additions & 9 deletions src/bitcoin-cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ static int AppInitRPC(int argc, char* argv[])
"\nIt can be used to query network information, manage wallets, create or broadcast transactions, and control the " CLIENT_NAME " server.\n"
"\nUse the \"help\" command to list all commands. Use \"help <command>\" to show help for that command.\n"
"The -named option allows you to specify parameters using the key=value format, eliminating the need to pass unused positional parameters.\n"
"[options] can be specified before or after the commands.\n"
"\n"
"Usage: bitcoin-cli [options] <command> [params]\n"
"or: bitcoin-cli [options] -named <command> [name=value]...\n"
Expand Down Expand Up @@ -1055,7 +1056,7 @@ static void ParseError(const UniValue& error, std::string& strPrint, int& nRet)
strPrint += ("error message:\n" + err_msg.get_str());
}
if (err_code.isNum() && err_code.getInt<int>() == RPC_WALLET_NOT_SPECIFIED) {
strPrint += " Or for the CLI, specify the \"-rpcwallet=<walletname>\" option before the command";
strPrint += " Or for the CLI, specify the \"-rpcwallet=<walletname>\" option before or after the command";
strPrint += " (run \"bitcoin-cli -h\" for help or \"bitcoin-cli listwallets\" to see which wallets are currently loaded).";
}
} else {
Expand Down Expand Up @@ -1261,16 +1262,21 @@ static void SetGenerateToAddressArgs(const std::string& address, std::vector<std
args.emplace(args.begin() + 1, address);
}

static int CommandLineRPC(int argc, char *argv[])
std::vector<std::string> GetCommandArgs() {
std::optional<const ArgsManager::Command> command = gArgs.GetCommand();

// Return command args if command is present, otherwise return an empty vector
if (command.has_value()) {
return command->args;
}
return {};
}

static int CommandLineRPC()
{
std::string strPrint;
int nRet = 0;
try {
// Skip switches
while (argc > 1 && IsSwitchChar(argv[1][0])) {
argc--;
argv++;
}
std::string rpcPass;
if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
NO_STDIN_ECHO();
Expand All @@ -1286,7 +1292,7 @@ static int CommandLineRPC(int argc, char *argv[])
}
gArgs.ForceSetArg("-rpcpassword", rpcPass);
}
std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
std::vector<std::string> args = GetCommandArgs();
if (gArgs.GetBoolArg("-stdinwalletpassphrase", false)) {
NO_STDIN_ECHO();
std::string walletPass;
Expand Down Expand Up @@ -1404,7 +1410,7 @@ MAIN_FUNCTION

int ret = EXIT_FAILURE;
try {
ret = CommandLineRPC(argc, argv);
ret = CommandLineRPC();
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "CommandLineRPC()");
Expand Down
30 changes: 18 additions & 12 deletions src/bitcoin-tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -797,35 +797,41 @@ static int CommandLineRawTx(int argc, char* argv[])
std::string strPrint;
int nRet = 0;
try {
// Skip switches; Permit common stdin convention "-"
while (argc > 1 && IsSwitchChar(argv[1][0]) &&
(argv[1][1] != 0)) {
argc--;
argv++;
std::vector<std::string> args;
if (const auto command{gArgs.GetCommand()}) {
args = command->args;
} else {
// Skip switches; Permit common stdin convention "-"
while (argc > 1 && IsSwitchChar(argv[1][0]) &&
(argv[1][1] != 0)) {
argc--;
argv++;
}
args.assign(argv + 1, argv + argc);
}

CMutableTransaction tx;
int startArg;
size_t startArg;

if (!fCreateBlank) {
// require at least one param
if (argc < 2)
if (args.empty())
throw std::runtime_error("too few parameters");

// param: hex-encoded bitcoin transaction
std::string strHexTx(argv[1]);
std::string strHexTx(args[0]);
if (strHexTx == "-") // "-" implies standard input
strHexTx = readStdin();

if (!DecodeHexTx(tx, strHexTx, true))
throw std::runtime_error("invalid transaction encoding");

startArg = 2;
} else
startArg = 1;
} else
startArg = 0;

for (int i = startArg; i < argc; i++) {
std::string arg = argv[i];
for (size_t i{startArg}; i < args.size(); ++i) {
const std::string& arg{args[i]};
std::string key, value;
size_t eqpos = arg.find('=');
if (eqpos == std::string::npos)
Expand Down
Loading
Loading