| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- /*
- * Copyright (c) 2020 Project CHIP Authors
- * All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- #include "Commands.h"
- #include "Command.h"
- #include <algorithm>
- #include <iomanip>
- #include <sstream>
- #include <string>
- #include <lib/support/Base64.h>
- #include <lib/support/CHIPMem.h>
- #include <lib/support/CodeUtils.h>
- #include <platform/CHIPDeviceConfig.h>
- #include <platform/KeyValueStoreManager.h>
- #include "../clusters/JsonParser.h"
- namespace {
- char kInteractiveModeName[] = "";
- constexpr size_t kInteractiveModeArgumentsMaxLength = 32;
- constexpr const char * kOptionalArgumentPrefix = "--";
- constexpr const char * kJsonClusterKey = "cluster";
- constexpr const char * kJsonCommandKey = "command";
- constexpr const char * kJsonCommandSpecifierKey = "command_specifier";
- constexpr const char * kJsonArgumentsKey = "arguments";
- #if !CHIP_DISABLE_PLATFORM_KVS
- template <typename T>
- struct HasInitWithString
- {
- template <typename U>
- static constexpr auto check(U *) -> typename std::is_same<decltype(std::declval<U>().Init("")), CHIP_ERROR>::type;
- template <typename>
- static constexpr std::false_type check(...);
- typedef decltype(check<std::remove_reference_t<T>>(nullptr)) type;
- public:
- static constexpr bool value = type::value;
- };
- // Template so we can do conditional enabling
- template <typename T, std::enable_if_t<HasInitWithString<T>::value, int> = 0>
- static void UseStorageDirectory(T & storageManagerImpl, const char * storageDirectory)
- {
- std::string platformKVS = std::string(storageDirectory) + "/chip_tool_kvs";
- storageManagerImpl.Init(platformKVS.c_str());
- }
- template <typename T, std::enable_if_t<!HasInitWithString<T>::value, int> = 0>
- static void UseStorageDirectory(T & storageManagerImpl, const char * storageDirectory)
- {}
- #endif // !CHIP_DISABLE_PLATFORM_KVS
- bool GetArgumentsFromJson(Command * command, Json::Value & value, bool optional, std::vector<std::string> & outArgs)
- {
- auto memberNames = value.getMemberNames();
- std::vector<std::string> args;
- for (size_t i = 0; i < command->GetArgumentsCount(); i++)
- {
- auto argName = command->GetArgumentName(i);
- auto memberNamesIterator = memberNames.begin();
- while (memberNamesIterator != memberNames.end())
- {
- auto memberName = *memberNamesIterator;
- if (strcasecmp(argName, memberName.c_str()) != 0)
- {
- memberNamesIterator++;
- continue;
- }
- if (command->GetArgumentIsOptional(i) != optional)
- {
- memberNamesIterator = memberNames.erase(memberNamesIterator);
- continue;
- }
- if (optional)
- {
- args.push_back(std::string(kOptionalArgumentPrefix) + argName);
- }
- auto argValue = value[memberName].asString();
- args.push_back(std::move(argValue));
- memberNamesIterator = memberNames.erase(memberNamesIterator);
- break;
- }
- }
- if (memberNames.size())
- {
- auto memberName = memberNames.front();
- ChipLogError(chipTool, "The argument \"\%s\" is not supported.", memberName.c_str());
- return false;
- }
- outArgs = args;
- return true;
- };
- // Check for arguments with a starting '"' but no ending '"': those
- // would indicate that people are using double-quoting, not single
- // quoting, on arguments with spaces.
- static void DetectAndLogMismatchedDoubleQuotes(int argc, char ** argv)
- {
- for (int curArg = 0; curArg < argc; ++curArg)
- {
- char * arg = argv[curArg];
- if (!arg)
- {
- continue;
- }
- auto len = strlen(arg);
- if (len == 0)
- {
- continue;
- }
- if (arg[0] == '"' && arg[len - 1] != '"')
- {
- ChipLogError(chipTool,
- "Mismatched '\"' detected in argument: '%s'. Use single quotes to delimit arguments with spaces "
- "in them: 'x y', not \"x y\".",
- arg);
- }
- }
- }
- } // namespace
- void Commands::Register(const char * commandSetName, commands_list commandsList, const char * helpText, bool isCluster)
- {
- VerifyOrDieWithMsg(isCluster || helpText != nullptr, chipTool, "Non-cluster command sets must have help text");
- mCommandSets[commandSetName].isCluster = isCluster;
- mCommandSets[commandSetName].helpText = helpText;
- for (auto & command : commandsList)
- {
- mCommandSets[commandSetName].commands.push_back(std::move(command));
- }
- }
- int Commands::Run(int argc, char ** argv)
- {
- CHIP_ERROR err = CHIP_NO_ERROR;
- err = chip::Platform::MemoryInit();
- VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init Memory failure: %s", chip::ErrorStr(err)));
- #ifdef CONFIG_USE_LOCAL_STORAGE
- err = mStorage.Init();
- VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init Storage failure: %s", chip::ErrorStr(err)));
- chip::Logging::SetLogFilter(mStorage.GetLoggingLevel());
- #endif // CONFIG_USE_LOCAL_STORAGE
- err = RunCommand(argc, argv);
- VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(chipTool, "Run command failure: %s", chip::ErrorStr(err)));
- exit:
- return (err == CHIP_NO_ERROR) ? EXIT_SUCCESS : EXIT_FAILURE;
- }
- int Commands::RunInteractive(const char * command, const chip::Optional<char *> & storageDirectory)
- {
- std::vector<std::string> arguments;
- VerifyOrReturnValue(DecodeArgumentsFromInteractiveMode(command, arguments), EXIT_FAILURE);
- if (arguments.size() > (kInteractiveModeArgumentsMaxLength - 1 /* for interactive mode name */))
- {
- ChipLogError(chipTool, "Too many arguments. Ignoring.");
- arguments.resize(kInteractiveModeArgumentsMaxLength - 1);
- }
- int argc = 0;
- char * argv[kInteractiveModeArgumentsMaxLength] = {};
- argv[argc++] = kInteractiveModeName;
- std::string commandStr;
- for (auto & arg : arguments)
- {
- argv[argc] = new char[arg.size() + 1];
- strcpy(argv[argc++], arg.c_str());
- commandStr += arg;
- commandStr += " ";
- }
- ChipLogProgress(chipTool, "Command: %s", commandStr.c_str());
- auto err = RunCommand(argc, argv, true, storageDirectory);
- // Do not delete arg[0]
- for (auto i = 1; i < argc; i++)
- {
- delete[] argv[i];
- }
- return (err == CHIP_NO_ERROR) ? EXIT_SUCCESS : EXIT_FAILURE;
- }
- CHIP_ERROR Commands::RunCommand(int argc, char ** argv, bool interactive,
- const chip::Optional<char *> & interactiveStorageDirectory)
- {
- Command * command = nullptr;
- if (argc <= 1)
- {
- ChipLogError(chipTool, "Missing cluster or command set name");
- ShowCommandSets(argv[0]);
- return CHIP_ERROR_INVALID_ARGUMENT;
- }
- auto commandSetIter = GetCommandSet(argv[1]);
- if (commandSetIter == mCommandSets.end())
- {
- ChipLogError(chipTool, "Unknown cluster or command set: %s", argv[1]);
- ShowCommandSets(argv[0]);
- return CHIP_ERROR_INVALID_ARGUMENT;
- }
- auto & commandList = commandSetIter->second.commands;
- auto * helpText = commandSetIter->second.helpText;
- if (argc <= 2)
- {
- ChipLogError(chipTool, "Missing command name");
- ShowCommandSet(argv[0], argv[1], commandList, helpText);
- return CHIP_ERROR_INVALID_ARGUMENT;
- }
- bool isGlobalCommand = IsGlobalCommand(argv[2]);
- if (!isGlobalCommand)
- {
- command = GetCommand(commandList, argv[2]);
- if (command == nullptr)
- {
- ChipLogError(chipTool, "Unknown command: %s", argv[2]);
- ShowCommandSet(argv[0], argv[1], commandList, helpText);
- return CHIP_ERROR_INVALID_ARGUMENT;
- }
- }
- else if (IsEventCommand(argv[2]))
- {
- if (argc <= 3)
- {
- ChipLogError(chipTool, "Missing event name");
- ShowClusterEvents(argv[0], argv[1], argv[2], commandList);
- return CHIP_ERROR_INVALID_ARGUMENT;
- }
- command = GetGlobalCommand(commandList, argv[2], argv[3]);
- if (command == nullptr)
- {
- ChipLogError(chipTool, "Unknown event: %s", argv[3]);
- ShowClusterEvents(argv[0], argv[1], argv[2], commandList);
- return CHIP_ERROR_INVALID_ARGUMENT;
- }
- }
- else
- {
- if (argc <= 3)
- {
- ChipLogError(chipTool, "Missing attribute name");
- ShowClusterAttributes(argv[0], argv[1], argv[2], commandList);
- return CHIP_ERROR_INVALID_ARGUMENT;
- }
- command = GetGlobalCommand(commandList, argv[2], argv[3]);
- if (command == nullptr)
- {
- ChipLogError(chipTool, "Unknown attribute: %s", argv[3]);
- ShowClusterAttributes(argv[0], argv[1], argv[2], commandList);
- return CHIP_ERROR_INVALID_ARGUMENT;
- }
- }
- int argumentsPosition = isGlobalCommand ? 4 : 3;
- if (!command->InitArguments(argc - argumentsPosition, &argv[argumentsPosition]))
- {
- if (interactive)
- {
- DetectAndLogMismatchedDoubleQuotes(argc - argumentsPosition, &argv[argumentsPosition]);
- }
- ShowCommand(argv[0], argv[1], command);
- return CHIP_ERROR_INVALID_ARGUMENT;
- }
- if (interactive)
- {
- return command->RunAsInteractive(interactiveStorageDirectory);
- }
- // Now that the command is initialized, get our storage from it as needed
- // and set up our loging level.
- #ifdef CONFIG_USE_LOCAL_STORAGE
- CHIP_ERROR err = mStorage.Init(nullptr, command->GetStorageDirectory().ValueOr(nullptr));
- if (err != CHIP_NO_ERROR)
- {
- ChipLogError(Controller, "Init Storage failure: %s", chip::ErrorStr(err));
- return err;
- }
- chip::Logging::SetLogFilter(mStorage.GetLoggingLevel());
- #if !CHIP_DISABLE_PLATFORM_KVS
- UseStorageDirectory(chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl(), mStorage.GetDirectory());
- #endif // !CHIP_DISABLE_PLATFORM_KVS
- #endif // CONFIG_USE_LOCAL_STORAGE
- return command->Run();
- }
- Commands::CommandSetMap::iterator Commands::GetCommandSet(std::string commandSetName)
- {
- for (auto & commandSet : mCommandSets)
- {
- std::string key(commandSet.first);
- std::transform(key.begin(), key.end(), key.begin(), ::tolower);
- if (key.compare(commandSetName) == 0)
- {
- return mCommandSets.find(commandSet.first);
- }
- }
- return mCommandSets.end();
- }
- Command * Commands::GetCommand(CommandsVector & commands, std::string commandName)
- {
- for (auto & command : commands)
- {
- if (commandName.compare(command->GetName()) == 0)
- {
- return command.get();
- }
- }
- return nullptr;
- }
- Command * Commands::GetGlobalCommand(CommandsVector & commands, std::string commandName, std::string attributeName)
- {
- for (auto & command : commands)
- {
- if (commandName.compare(command->GetName()) == 0 && attributeName.compare(command->GetAttribute()) == 0)
- {
- return command.get();
- }
- }
- return nullptr;
- }
- bool Commands::IsAttributeCommand(std::string commandName) const
- {
- return commandName.compare("read") == 0 || commandName.compare("write") == 0 || commandName.compare("force-write") == 0 ||
- commandName.compare("subscribe") == 0;
- }
- bool Commands::IsEventCommand(std::string commandName) const
- {
- return commandName.compare("read-event") == 0 || commandName.compare("subscribe-event") == 0;
- }
- bool Commands::IsGlobalCommand(std::string commandName) const
- {
- return IsAttributeCommand(commandName) || IsEventCommand(commandName);
- }
- void Commands::ShowCommandSetOverview(std::string commandSetName, const CommandSet & commandSet)
- {
- std::transform(commandSetName.begin(), commandSetName.end(), commandSetName.begin(),
- [](unsigned char c) { return std::tolower(c); });
- fprintf(stderr, " | * %-82s|\n", commandSetName.c_str());
- ShowHelpText(commandSet.helpText);
- }
- void Commands::ShowCommandSets(std::string executable)
- {
- fprintf(stderr, "Usage:\n");
- fprintf(stderr, " %s cluster_name command_name [param1 param2 ...]\n", executable.c_str());
- fprintf(stderr, "or:\n");
- fprintf(stderr, " %s command_set_name command_name [param1 param2 ...]\n", executable.c_str());
- fprintf(stderr, "\n");
- // Table of clusters
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- fprintf(stderr, " | Clusters: |\n");
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- for (auto & commandSet : mCommandSets)
- {
- if (commandSet.second.isCluster)
- {
- ShowCommandSetOverview(commandSet.first, commandSet.second);
- }
- }
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- fprintf(stderr, "\n");
- // Table of command sets
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- fprintf(stderr, " | Command sets: |\n");
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- for (auto & commandSet : mCommandSets)
- {
- if (!commandSet.second.isCluster)
- {
- ShowCommandSetOverview(commandSet.first, commandSet.second);
- }
- }
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- }
- void Commands::ShowCommandSet(std::string executable, std::string commandSetName, CommandsVector & commands, const char * helpText)
- {
- fprintf(stderr, "Usage:\n");
- fprintf(stderr, " %s %s command_name [param1 param2 ...]\n", executable.c_str(), commandSetName.c_str());
- if (helpText)
- {
- fprintf(stderr, "\n%s\n", helpText);
- }
- fprintf(stderr, "\n");
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- fprintf(stderr, " | Commands: |\n");
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- bool readCommand = false;
- bool writeCommand = false;
- bool writeOverrideCommand = false;
- bool subscribeCommand = false;
- bool readEventCommand = false;
- bool subscribeEventCommand = false;
- for (auto & command : commands)
- {
- bool shouldPrint = true;
- if (IsGlobalCommand(command->GetName()))
- {
- if (strcmp(command->GetName(), "read") == 0 && !readCommand)
- {
- readCommand = true;
- }
- else if (strcmp(command->GetName(), "write") == 0 && !writeCommand)
- {
- writeCommand = true;
- }
- else if (strcmp(command->GetName(), "force-write") == 0 && !writeOverrideCommand)
- {
- writeOverrideCommand = true;
- }
- else if (strcmp(command->GetName(), "subscribe") == 0 && !subscribeCommand)
- {
- subscribeCommand = true;
- }
- else if (strcmp(command->GetName(), "read-event") == 0 && !readEventCommand)
- {
- readEventCommand = true;
- }
- else if (strcmp(command->GetName(), "subscribe-event") == 0 && !subscribeEventCommand)
- {
- subscribeEventCommand = true;
- }
- else
- {
- shouldPrint = false;
- }
- }
- if (shouldPrint)
- {
- fprintf(stderr, " | * %-82s|\n", command->GetName());
- ShowHelpText(command->GetHelpText());
- }
- }
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- }
- void Commands::ShowClusterAttributes(std::string executable, std::string clusterName, std::string commandName,
- CommandsVector & commands)
- {
- fprintf(stderr, "Usage:\n");
- fprintf(stderr, " %s %s %s attribute-name [param1 param2 ...]\n", executable.c_str(), clusterName.c_str(),
- commandName.c_str());
- fprintf(stderr, "\n");
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- fprintf(stderr, " | Attributes: |\n");
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- for (auto & command : commands)
- {
- if (commandName.compare(command->GetName()) == 0)
- {
- fprintf(stderr, " | * %-82s|\n", command->GetAttribute());
- }
- }
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- }
- void Commands::ShowClusterEvents(std::string executable, std::string clusterName, std::string commandName,
- CommandsVector & commands)
- {
- fprintf(stderr, "Usage:\n");
- fprintf(stderr, " %s %s %s event-name [param1 param2 ...]\n", executable.c_str(), clusterName.c_str(), commandName.c_str());
- fprintf(stderr, "\n");
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- fprintf(stderr, " | Events: |\n");
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- for (auto & command : commands)
- {
- if (commandName.compare(command->GetName()) == 0)
- {
- fprintf(stderr, " | * %-82s|\n", command->GetEvent());
- }
- }
- fprintf(stderr, " +-------------------------------------------------------------------------------------+\n");
- }
- void Commands::ShowCommand(std::string executable, std::string clusterName, Command * command)
- {
- fprintf(stderr, "Usage:\n");
- std::string arguments;
- std::string description;
- arguments += command->GetName();
- if (command->GetReadOnlyGlobalCommandArgument())
- {
- arguments += ' ';
- arguments += command->GetReadOnlyGlobalCommandArgument();
- }
- size_t argumentsCount = command->GetArgumentsCount();
- for (size_t i = 0; i < argumentsCount; i++)
- {
- std::string arg;
- bool isOptional = command->GetArgumentIsOptional(i);
- if (isOptional)
- {
- arg += "[--";
- }
- arg += command->GetArgumentName(i);
- if (isOptional)
- {
- arg += "]";
- }
- arguments += " ";
- arguments += arg;
- const char * argDescription = command->GetArgumentDescription(i);
- if ((argDescription != nullptr) && (strlen(argDescription) > 0))
- {
- description += "\n";
- description += arg;
- description += ":\n ";
- description += argDescription;
- description += "\n";
- }
- }
- fprintf(stderr, " %s %s %s\n", executable.c_str(), clusterName.c_str(), arguments.c_str());
- if (command->GetHelpText())
- {
- fprintf(stderr, "\n%s\n", command->GetHelpText());
- }
- if (description.size() > 0)
- {
- fprintf(stderr, "%s\n", description.c_str());
- }
- }
- bool Commands::DecodeArgumentsFromInteractiveMode(const char * command, std::vector<std::string> & args)
- {
- // Remote clients may not know the ordering of arguments, so instead of a strict ordering arguments can
- // be passed in as a json payload encoded in base64 and are reordered on the fly.
- return IsJsonString(command) ? DecodeArgumentsFromBase64EncodedJson(command, args)
- : DecodeArgumentsFromStringStream(command, args);
- }
- bool Commands::DecodeArgumentsFromBase64EncodedJson(const char * json, std::vector<std::string> & args)
- {
- Json::Value jsonValue;
- bool parsed = JsonParser::ParseCustomArgument(json, json + kJsonStringPrefixLen, jsonValue);
- VerifyOrReturnValue(parsed, false, ChipLogError(chipTool, "Error while parsing json."));
- VerifyOrReturnValue(jsonValue.isObject(), false, ChipLogError(chipTool, "Unexpected json type."));
- VerifyOrReturnValue(jsonValue.isMember(kJsonClusterKey), false,
- ChipLogError(chipTool, "'%s' key not found in json.", kJsonClusterKey));
- VerifyOrReturnValue(jsonValue.isMember(kJsonCommandKey), false,
- ChipLogError(chipTool, "'%s' key not found in json.", kJsonCommandKey));
- VerifyOrReturnValue(jsonValue.isMember(kJsonArgumentsKey), false,
- ChipLogError(chipTool, "'%s' key not found in json.", kJsonArgumentsKey));
- VerifyOrReturnValue(IsBase64String(jsonValue[kJsonArgumentsKey].asString().c_str()), false,
- ChipLogError(chipTool, "'arguments' is not a base64 string."));
- auto clusterName = jsonValue[kJsonClusterKey].asString();
- auto commandName = jsonValue[kJsonCommandKey].asString();
- auto arguments = jsonValue[kJsonArgumentsKey].asString();
- auto clusterIter = GetCommandSet(clusterName);
- VerifyOrReturnValue(clusterIter != mCommandSets.end(), false,
- ChipLogError(chipTool, "Cluster '%s' is not supported.", clusterName.c_str()));
- auto & commandList = clusterIter->second.commands;
- auto command = GetCommand(commandList, commandName);
- if (jsonValue.isMember(kJsonCommandSpecifierKey) && IsGlobalCommand(commandName))
- {
- auto commandSpecifierName = jsonValue[kJsonCommandSpecifierKey].asString();
- command = GetGlobalCommand(commandList, commandName, commandSpecifierName);
- }
- VerifyOrReturnValue(nullptr != command, false, ChipLogError(chipTool, "Unknown command."));
- auto encodedData = arguments.c_str();
- encodedData += kBase64StringPrefixLen;
- size_t encodedDataSize = strlen(encodedData);
- size_t expectedMaxDecodedSize = BASE64_MAX_DECODED_LEN(encodedDataSize);
- chip::Platform::ScopedMemoryBuffer<uint8_t> decodedData;
- VerifyOrReturnValue(decodedData.Calloc(expectedMaxDecodedSize + 1 /* for null */), false);
- size_t decodedDataSize = chip::Base64Decode(encodedData, static_cast<uint16_t>(encodedDataSize), decodedData.Get());
- VerifyOrReturnValue(decodedDataSize != 0, false, ChipLogError(chipTool, "Error while decoding base64 data."));
- decodedData.Get()[decodedDataSize] = '\0';
- Json::Value jsonArguments;
- bool parsedArguments = JsonParser::ParseCustomArgument(encodedData, chip::Uint8::to_char(decodedData.Get()), jsonArguments);
- VerifyOrReturnValue(parsedArguments, false, ChipLogError(chipTool, "Error while parsing json."));
- VerifyOrReturnValue(jsonArguments.isObject(), false, ChipLogError(chipTool, "Unexpected json type, expects and object."));
- std::vector<std::string> mandatoryArguments;
- std::vector<std::string> optionalArguments;
- VerifyOrReturnValue(GetArgumentsFromJson(command, jsonArguments, false /* addOptional */, mandatoryArguments), false);
- VerifyOrReturnValue(GetArgumentsFromJson(command, jsonArguments, true /* addOptional */, optionalArguments), false);
- args.push_back(std::move(clusterName));
- args.push_back(std::move(commandName));
- if (jsonValue.isMember(kJsonCommandSpecifierKey))
- {
- auto commandSpecifierName = jsonValue[kJsonCommandSpecifierKey].asString();
- args.push_back(std::move(commandSpecifierName));
- }
- args.insert(args.end(), mandatoryArguments.begin(), mandatoryArguments.end());
- args.insert(args.end(), optionalArguments.begin(), optionalArguments.end());
- return true;
- }
- bool Commands::DecodeArgumentsFromStringStream(const char * command, std::vector<std::string> & args)
- {
- std::string arg;
- std::stringstream ss(command);
- while (ss >> std::quoted(arg, '\''))
- {
- args.push_back(std::move(arg));
- }
- return true;
- }
- void Commands::ShowHelpText(const char * helpText)
- {
- if (helpText == nullptr)
- {
- return;
- }
- // We leave 82 chars for command/cluster names. The help text starts
- // two chars further to the right, so there are 80 chars left
- // for it.
- if (strlen(helpText) > 80)
- {
- // Add "..." at the end to indicate truncation, and only
- // show the first 77 chars, since that's what will fit.
- fprintf(stderr, " | - %.77s...|\n", helpText);
- }
- else
- {
- fprintf(stderr, " | - %-80s|\n", helpText);
- }
- }
|