| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087 |
- /*
- * 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 "Command.h"
- #include "CustomStringPrefix.h"
- #include "HexConversion.h"
- #include "platform/PlatformManager.h"
- #include <functional>
- #include <netdb.h>
- #include <sstream>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <math.h> // For INFINITY
- #include <lib/core/CHIPSafeCasts.h>
- #include <lib/support/BytesToHex.h>
- #include <lib/support/CHIPMem.h>
- #include <lib/support/CodeUtils.h>
- #include <lib/support/SafeInt.h>
- #include <lib/support/ScopedBuffer.h>
- #include <lib/support/StringSplitter.h>
- #include <lib/support/logging/CHIPLogging.h>
- constexpr const char * kOptionalArgumentPrefix = "--";
- constexpr size_t kOptionalArgumentPrefixLength = 2;
- bool Command::InitArguments(int argc, char ** argv)
- {
- bool isValidCommand = false;
- size_t argvExtraArgsCount = (size_t) argc;
- size_t mandatoryArgsCount = 0;
- size_t optionalArgsCount = 0;
- for (auto & arg : mArgs)
- {
- if (arg.isOptional())
- {
- optionalArgsCount++;
- }
- else
- {
- mandatoryArgsCount++;
- argvExtraArgsCount--;
- }
- }
- VerifyOrExit((size_t)(argc) >= mandatoryArgsCount && (argvExtraArgsCount == 0 || (argvExtraArgsCount && optionalArgsCount)),
- ChipLogError(chipTool, "InitArgs: Wrong arguments number: %d instead of %u", argc,
- static_cast<unsigned int>(mandatoryArgsCount)));
- // Initialize mandatory arguments
- for (size_t i = 0; i < mandatoryArgsCount; i++)
- {
- char * arg = argv[i];
- if (!InitArgument(i, arg))
- {
- ExitNow();
- }
- }
- // Initialize optional arguments
- // Optional arguments expect a name and a value, so i is increased by 2 on every step.
- for (size_t i = mandatoryArgsCount; i < (size_t) argc; i += 2)
- {
- bool found = false;
- for (size_t j = mandatoryArgsCount; j < mandatoryArgsCount + optionalArgsCount; j++)
- {
- // optional arguments starts with kOptionalArgumentPrefix
- if (strlen(argv[i]) <= kOptionalArgumentPrefixLength &&
- strncmp(argv[i], kOptionalArgumentPrefix, kOptionalArgumentPrefixLength) != 0)
- {
- continue;
- }
- if (strcmp(argv[i] + strlen(kOptionalArgumentPrefix), mArgs[j].name) == 0)
- {
- found = true;
- VerifyOrExit((size_t) argc > (i + 1),
- ChipLogError(chipTool, "InitArgs: Optional argument %s missing value.", argv[i]));
- if (!InitArgument(j, argv[i + 1]))
- {
- ExitNow();
- }
- }
- }
- VerifyOrExit(found, ChipLogError(chipTool, "InitArgs: Optional argument %s does not exist.", argv[i]));
- }
- isValidCommand = true;
- exit:
- return isValidCommand;
- }
- static bool ParseAddressWithInterface(const char * addressString, Command::AddressWithInterface * address)
- {
- struct addrinfo hints;
- struct addrinfo * result;
- int ret;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_DGRAM;
- ret = getaddrinfo(addressString, nullptr, &hints, &result);
- if (ret < 0)
- {
- ChipLogError(chipTool, "Invalid address: %s", addressString);
- return false;
- }
- if (result->ai_family == AF_INET6)
- {
- struct sockaddr_in6 * addr = reinterpret_cast<struct sockaddr_in6 *>(result->ai_addr);
- address->address = ::chip::Inet::IPAddress::FromSockAddr(*addr);
- address->interfaceId = ::chip::Inet::InterfaceId(addr->sin6_scope_id);
- }
- #if INET_CONFIG_ENABLE_IPV4
- else if (result->ai_family == AF_INET)
- {
- address->address = ::chip::Inet::IPAddress::FromSockAddr(*reinterpret_cast<struct sockaddr_in *>(result->ai_addr));
- address->interfaceId = chip::Inet::InterfaceId::Null();
- }
- #endif // INET_CONFIG_ENABLE_IPV4
- else
- {
- ChipLogError(chipTool, "Unsupported address: %s", addressString);
- return false;
- }
- return true;
- }
- // The callback should return whether the argument is valid, for the non-null
- // case. It can't directly write to isValidArgument (by closing over it)
- // because in the nullable-and-null case we need to do that from this function,
- // via the return value.
- template <typename T>
- bool HandleNullableOptional(Argument & arg, char * argValue, std::function<bool(T * value)> callback)
- {
- if (arg.isOptional())
- {
- if (arg.isNullable())
- {
- arg.value = &(reinterpret_cast<chip::Optional<chip::app::DataModel::Nullable<T>> *>(arg.value)->Emplace());
- }
- else
- {
- arg.value = &(reinterpret_cast<chip::Optional<T> *>(arg.value)->Emplace());
- }
- }
- if (arg.isNullable())
- {
- auto * nullable = reinterpret_cast<chip::app::DataModel::Nullable<T> *>(arg.value);
- if (strcmp(argValue, "null") == 0)
- {
- nullable->SetNull();
- return true;
- }
- arg.value = &(nullable->SetNonNull());
- }
- return callback(reinterpret_cast<T *>(arg.value));
- }
- bool Command::InitArgument(size_t argIndex, char * argValue)
- {
- bool isValidArgument = false;
- bool isHexNotation = strncmp(argValue, "0x", 2) == 0 || strncmp(argValue, "0X", 2) == 0;
- Argument arg = mArgs.at(argIndex);
- // We have two places where we handle uint8_t-typed args (actual int8u and
- // bool args), so declare the handler function here so it can be reused.
- auto uint8Handler = [&](uint8_t * value) {
- // stringstream treats uint8_t as char, which is not what we want here.
- uint16_t tmpValue;
- std::stringstream ss;
- isHexNotation ? (ss << std::hex << argValue) : (ss << argValue);
- ss >> tmpValue;
- if (chip::CanCastTo<uint8_t>(tmpValue))
- {
- *value = static_cast<uint8_t>(tmpValue);
- uint64_t min = chip::CanCastTo<uint64_t>(arg.min) ? static_cast<uint64_t>(arg.min) : 0;
- uint64_t max = arg.max;
- return (!ss.fail() && ss.eof() && *value >= min && *value <= max);
- }
- return false;
- };
- switch (arg.type)
- {
- case ArgumentType::Complex: {
- // Complex arguments may be optional, but they are not currently supported via the <chip::Optional> class.
- // Instead, they must be explicitly specified as optional using the kOptional flag,
- // and the base TypedComplexArgument<T> class is still referenced.
- auto complexArgument = static_cast<ComplexArgument *>(arg.value);
- return CHIP_NO_ERROR == complexArgument->Parse(arg.name, argValue);
- }
- case ArgumentType::Custom: {
- auto customArgument = static_cast<CustomArgument *>(arg.value);
- return CHIP_NO_ERROR == customArgument->Parse(arg.name, argValue);
- }
- case ArgumentType::VectorString: {
- std::vector<std::string> vectorArgument;
- chip::StringSplitter splitter(argValue, ',');
- chip::CharSpan value;
- while (splitter.Next(value))
- {
- vectorArgument.push_back(std::string(value.data(), value.size()));
- }
- if (arg.flags == Argument::kOptional)
- {
- auto argument = static_cast<chip::Optional<std::vector<std::string>> *>(arg.value);
- argument->SetValue(vectorArgument);
- }
- else
- {
- auto argument = static_cast<std::vector<std::string> *>(arg.value);
- *argument = vectorArgument;
- }
- return true;
- }
- case ArgumentType::VectorBool: {
- // Currently only chip::Optional<std::vector<bool>> is supported.
- if (arg.flags != Argument::kOptional)
- {
- return false;
- }
- std::vector<bool> vectorArgument;
- std::stringstream ss(argValue);
- while (ss.good())
- {
- std::string valueAsString;
- getline(ss, valueAsString, ',');
- if (strcasecmp(valueAsString.c_str(), "true") == 0)
- {
- vectorArgument.push_back(true);
- }
- else if (strcasecmp(valueAsString.c_str(), "false") == 0)
- {
- vectorArgument.push_back(false);
- }
- else
- {
- return false;
- }
- }
- auto optionalArgument = static_cast<chip::Optional<std::vector<bool>> *>(arg.value);
- optionalArgument->SetValue(vectorArgument);
- return true;
- }
- case ArgumentType::Vector16:
- case ArgumentType::Vector32: {
- std::vector<uint64_t> values;
- uint64_t min = chip::CanCastTo<uint64_t>(arg.min) ? static_cast<uint64_t>(arg.min) : 0;
- uint64_t max = arg.max;
- std::stringstream ss(argValue);
- while (ss.good())
- {
- std::string valueAsString;
- getline(ss, valueAsString, ',');
- isHexNotation = strncmp(valueAsString.c_str(), "0x", 2) == 0 || strncmp(valueAsString.c_str(), "0X", 2) == 0;
- std::stringstream subss;
- isHexNotation ? subss << std::hex << valueAsString : subss << valueAsString;
- uint64_t value;
- subss >> value;
- VerifyOrReturnError(!subss.fail() && subss.eof() && value >= min && value <= max, false);
- values.push_back(value);
- }
- if (arg.type == ArgumentType::Vector16)
- {
- auto vectorArgument = static_cast<std::vector<uint16_t> *>(arg.value);
- for (uint64_t v : values)
- {
- vectorArgument->push_back(static_cast<uint16_t>(v));
- }
- }
- else if (arg.type == ArgumentType::Vector32 && arg.flags != Argument::kOptional)
- {
- auto vectorArgument = static_cast<std::vector<uint32_t> *>(arg.value);
- for (uint64_t v : values)
- {
- vectorArgument->push_back(static_cast<uint32_t>(v));
- }
- }
- else if (arg.type == ArgumentType::Vector32 && arg.flags == Argument::kOptional)
- {
- std::vector<uint32_t> vectorArgument;
- for (uint64_t v : values)
- {
- vectorArgument.push_back(static_cast<uint32_t>(v));
- }
- auto optionalArgument = static_cast<chip::Optional<std::vector<uint32_t>> *>(arg.value);
- optionalArgument->SetValue(vectorArgument);
- }
- else
- {
- return false;
- }
- return true;
- }
- case ArgumentType::VectorCustom: {
- auto vectorArgument = static_cast<std::vector<CustomArgument *> *>(arg.value);
- std::stringstream ss(argValue);
- while (ss.good())
- {
- std::string valueAsString;
- // By default the parameter separator is ";" in order to not collapse with the argument itself if it contains commas
- // (e.g a struct argument with multiple fields). In case one needs to use ";" it can be overriden with the following
- // environment variable.
- constexpr const char * kSeparatorVariable = "CHIPTOOL_CUSTOM_ARGUMENTS_SEPARATOR";
- char * getenvSeparatorVariableResult = getenv(kSeparatorVariable);
- getline(ss, valueAsString, getenvSeparatorVariableResult ? getenvSeparatorVariableResult[0] : ';');
- CustomArgument * customArgument = new CustomArgument();
- vectorArgument->push_back(customArgument);
- VerifyOrReturnError(CHIP_NO_ERROR == vectorArgument->back()->Parse(arg.name, valueAsString.c_str()), false);
- }
- return true;
- }
- case ArgumentType::String: {
- isValidArgument = HandleNullableOptional<char *>(arg, argValue, [&](auto * value) {
- *value = argValue;
- return true;
- });
- break;
- }
- case ArgumentType::CharString: {
- isValidArgument = HandleNullableOptional<chip::CharSpan>(arg, argValue, [&](auto * value) {
- *value = chip::Span<const char>(argValue, strlen(argValue));
- return true;
- });
- break;
- }
- case ArgumentType::OctetString: {
- isValidArgument = HandleNullableOptional<chip::ByteSpan>(arg, argValue, [&](auto * value) {
- // We support two ways to pass an octet string argument. If it happens
- // to be all-ASCII, you can just pass it in. Otherwise you can pass in
- // "hex:" followed by the hex-encoded bytes.
- size_t argLen = strlen(argValue);
- if (IsHexString(argValue))
- {
- // Hex-encoded. Decode it into a temporary buffer first, so if we
- // run into errors we can do correct "argument is not valid" logging
- // that actually shows the value that was passed in. After we
- // determine it's valid, modify the passed-in value to hold the
- // right bytes, so we don't need to worry about allocating storage
- // for this somewhere else. This works because the hex
- // representation is always longer than the octet string it encodes,
- // so we have enough space in argValue for the decoded version.
- chip::Platform::ScopedMemoryBuffer<uint8_t> buffer;
- size_t octetCount;
- CHIP_ERROR err = HexToBytes(
- chip::CharSpan(argValue + kHexStringPrefixLen, argLen - kHexStringPrefixLen),
- [&buffer](size_t allocSize) {
- buffer.Calloc(allocSize);
- return buffer.Get();
- },
- &octetCount);
- if (err != CHIP_NO_ERROR)
- {
- return false;
- }
- memcpy(argValue, buffer.Get(), octetCount);
- *value = chip::ByteSpan(chip::Uint8::from_char(argValue), octetCount);
- return true;
- }
- // Just ASCII. Check for the "str:" prefix.
- if (IsStrString(argValue))
- {
- // Skip the prefix
- argValue += kStrStringPrefixLen;
- argLen -= kStrStringPrefixLen;
- }
- *value = chip::ByteSpan(chip::Uint8::from_char(argValue), argLen);
- return true;
- });
- break;
- }
- case ArgumentType::Bool: {
- isValidArgument = HandleNullableOptional<bool>(arg, argValue, [&](auto * value) {
- // Start with checking for actual boolean values.
- if (strcasecmp(argValue, "true") == 0)
- {
- *value = true;
- return true;
- }
- if (strcasecmp(argValue, "false") == 0)
- {
- *value = false;
- return true;
- }
- // For backwards compat, keep accepting 0 and 1 for now as synonyms
- // for false and true. Since we set our min to 0 and max to 1 for
- // booleans, calling uint8Handler does the right thing in terms of
- // only allowing those two values.
- uint8_t temp = 0;
- if (!uint8Handler(&temp))
- {
- return false;
- }
- *value = (temp == 1);
- return true;
- });
- break;
- }
- case ArgumentType::Number_uint8: {
- isValidArgument = HandleNullableOptional<uint8_t>(arg, argValue, uint8Handler);
- break;
- }
- case ArgumentType::Number_uint16: {
- isValidArgument = HandleNullableOptional<uint16_t>(arg, argValue, [&](auto * value) {
- std::stringstream ss;
- isHexNotation ? ss << std::hex << argValue : ss << argValue;
- ss >> *value;
- uint64_t min = chip::CanCastTo<uint64_t>(arg.min) ? static_cast<uint64_t>(arg.min) : 0;
- uint64_t max = arg.max;
- return (!ss.fail() && ss.eof() && *value >= min && *value <= max);
- });
- break;
- }
- case ArgumentType::Number_uint32: {
- isValidArgument = HandleNullableOptional<uint32_t>(arg, argValue, [&](auto * value) {
- std::stringstream ss;
- isHexNotation ? ss << std::hex << argValue : ss << argValue;
- ss >> *value;
- uint64_t min = chip::CanCastTo<uint64_t>(arg.min) ? static_cast<uint64_t>(arg.min) : 0;
- uint64_t max = arg.max;
- return (!ss.fail() && ss.eof() && *value >= min && *value <= max);
- });
- break;
- }
- case ArgumentType::Number_uint64: {
- isValidArgument = HandleNullableOptional<uint64_t>(arg, argValue, [&](auto * value) {
- std::stringstream ss;
- isHexNotation ? ss << std::hex << argValue : ss << argValue;
- ss >> *value;
- uint64_t min = chip::CanCastTo<uint64_t>(arg.min) ? static_cast<uint64_t>(arg.min) : 0;
- uint64_t max = arg.max;
- return (!ss.fail() && ss.eof() && *value >= min && *value <= max);
- });
- break;
- }
- case ArgumentType::Number_int8: {
- isValidArgument = HandleNullableOptional<int8_t>(arg, argValue, [&](auto * value) {
- // stringstream treats int8_t as char, which is not what we want here.
- int16_t tmpValue;
- std::stringstream ss;
- isHexNotation ? ss << std::hex << argValue : ss << argValue;
- ss >> tmpValue;
- if (chip::CanCastTo<int8_t>(tmpValue))
- {
- *value = static_cast<int8_t>(tmpValue);
- int64_t min = arg.min;
- int64_t max = chip::CanCastTo<int64_t>(arg.max) ? static_cast<int64_t>(arg.max) : INT64_MAX;
- return (!ss.fail() && ss.eof() && *value >= min && *value <= max);
- }
- return false;
- });
- break;
- }
- case ArgumentType::Number_int16: {
- isValidArgument = HandleNullableOptional<int16_t>(arg, argValue, [&](auto * value) {
- std::stringstream ss;
- isHexNotation ? ss << std::hex << argValue : ss << argValue;
- ss >> *value;
- int64_t min = arg.min;
- int64_t max = chip::CanCastTo<int64_t>(arg.max) ? static_cast<int64_t>(arg.max) : INT64_MAX;
- return (!ss.fail() && ss.eof() && *value >= min && *value <= max);
- });
- break;
- }
- case ArgumentType::Number_int32: {
- isValidArgument = HandleNullableOptional<int32_t>(arg, argValue, [&](auto * value) {
- std::stringstream ss;
- isHexNotation ? ss << std::hex << argValue : ss << argValue;
- ss >> *value;
- int64_t min = arg.min;
- int64_t max = chip::CanCastTo<int64_t>(arg.max) ? static_cast<int64_t>(arg.max) : INT64_MAX;
- return (!ss.fail() && ss.eof() && *value >= min && *value <= max);
- });
- break;
- }
- case ArgumentType::Number_int64: {
- isValidArgument = HandleNullableOptional<int64_t>(arg, argValue, [&](auto * value) {
- std::stringstream ss;
- isHexNotation ? ss << std::hex << argValue : ss << argValue;
- ss >> *value;
- int64_t min = arg.min;
- int64_t max = chip::CanCastTo<int64_t>(arg.max) ? static_cast<int64_t>(arg.max) : INT64_MAX;
- return (!ss.fail() && ss.eof() && *value >= min && *value <= max);
- });
- break;
- }
- case ArgumentType::Float: {
- isValidArgument = HandleNullableOptional<float>(arg, argValue, [&](auto * value) {
- if (strcmp(argValue, "Infinity") == 0)
- {
- *value = INFINITY;
- return true;
- }
- if (strcmp(argValue, "-Infinity") == 0)
- {
- *value = -INFINITY;
- return true;
- }
- std::stringstream ss;
- ss << argValue;
- ss >> *value;
- return (!ss.fail() && ss.eof());
- });
- break;
- }
- case ArgumentType::Double: {
- isValidArgument = HandleNullableOptional<double>(arg, argValue, [&](auto * value) {
- if (strcmp(argValue, "Infinity") == 0)
- {
- *value = INFINITY;
- return true;
- }
- if (strcmp(argValue, "-Infinity") == 0)
- {
- *value = -INFINITY;
- return true;
- }
- std::stringstream ss;
- ss << argValue;
- ss >> *value;
- return (!ss.fail() && ss.eof());
- });
- break;
- }
- case ArgumentType::Address: {
- isValidArgument = HandleNullableOptional<AddressWithInterface>(
- arg, argValue, [&](auto * value) { return ParseAddressWithInterface(argValue, value); });
- break;
- }
- }
- if (!isValidArgument)
- {
- ChipLogError(chipTool, "InitArgs: Invalid argument %s: %s", arg.name, argValue);
- }
- return isValidArgument;
- }
- void Command::AddArgument(const char * name, const char * value, const char * desc)
- {
- ReadOnlyGlobalCommandArgument arg;
- arg.name = name;
- arg.value = value;
- arg.desc = desc;
- mReadOnlyGlobalCommandArgument.SetValue(arg);
- }
- size_t Command::AddArgument(const char * name, char ** value, const char * desc, uint8_t flags)
- {
- Argument arg;
- arg.type = ArgumentType::String;
- arg.name = name;
- arg.value = reinterpret_cast<void *>(value);
- arg.flags = flags;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, chip::CharSpan * value, const char * desc, uint8_t flags)
- {
- Argument arg;
- arg.type = ArgumentType::CharString;
- arg.name = name;
- arg.value = reinterpret_cast<void *>(value);
- arg.flags = flags;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, chip::ByteSpan * value, const char * desc, uint8_t flags)
- {
- Argument arg;
- arg.type = ArgumentType::OctetString;
- arg.name = name;
- arg.value = reinterpret_cast<void *>(value);
- arg.flags = flags;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, AddressWithInterface * out, const char * desc, uint8_t flags)
- {
- Argument arg;
- arg.type = ArgumentType::Address;
- arg.name = name;
- arg.value = reinterpret_cast<void *>(out);
- arg.flags = flags;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, std::vector<uint16_t> * value, const char * desc)
- {
- Argument arg;
- arg.type = ArgumentType::Vector16;
- arg.name = name;
- arg.value = static_cast<void *>(value);
- arg.min = min;
- arg.max = max;
- arg.flags = 0;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, std::vector<uint32_t> * value, const char * desc)
- {
- Argument arg;
- arg.type = ArgumentType::Vector32;
- arg.name = name;
- arg.value = static_cast<void *>(value);
- arg.min = min;
- arg.max = max;
- arg.flags = 0;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, chip::Optional<std::vector<uint32_t>> * value,
- const char * desc)
- {
- Argument arg;
- arg.type = ArgumentType::Vector32;
- arg.name = name;
- arg.value = static_cast<void *>(value);
- arg.min = min;
- arg.max = max;
- arg.flags = Argument::kOptional;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, chip::Optional<std::vector<bool>> * value,
- const char * desc)
- {
- Argument arg;
- arg.type = ArgumentType::VectorBool;
- arg.name = name;
- arg.value = static_cast<void *>(value);
- arg.min = min;
- arg.max = max;
- arg.flags = Argument::kOptional;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, ComplexArgument * value, const char * desc, uint8_t flags)
- {
- Argument arg;
- arg.type = ArgumentType::Complex;
- arg.name = name;
- arg.value = static_cast<void *>(value);
- arg.flags = flags;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, CustomArgument * value, const char * desc)
- {
- Argument arg;
- arg.type = ArgumentType::Custom;
- arg.name = name;
- arg.value = const_cast<void *>(reinterpret_cast<const void *>(value));
- arg.flags = 0;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, std::vector<CustomArgument *> * value, const char * desc)
- {
- Argument arg;
- arg.type = ArgumentType::VectorCustom;
- arg.name = name;
- arg.value = static_cast<void *>(value);
- arg.flags = 0;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, float min, float max, float * out, const char * desc, uint8_t flags)
- {
- Argument arg;
- arg.type = ArgumentType::Float;
- arg.name = name;
- arg.value = reinterpret_cast<void *>(out);
- arg.flags = flags;
- arg.desc = desc;
- // Ignore min/max for now; they're always +-Infinity anyway.
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, double min, double max, double * out, const char * desc, uint8_t flags)
- {
- Argument arg;
- arg.type = ArgumentType::Double;
- arg.name = name;
- arg.value = reinterpret_cast<void *>(out);
- arg.flags = flags;
- arg.desc = desc;
- // Ignore min/max for now; they're always +-Infinity anyway.
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, void * out, ArgumentType type, const char * desc,
- uint8_t flags)
- {
- Argument arg;
- arg.type = type;
- arg.name = name;
- arg.value = out;
- arg.min = min;
- arg.max = max;
- arg.flags = flags;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, int64_t min, uint64_t max, void * out, const char * desc, uint8_t flags)
- {
- Argument arg;
- arg.type = ArgumentType::Number_uint8;
- arg.name = name;
- arg.value = out;
- arg.min = min;
- arg.max = max;
- arg.flags = flags;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, std::vector<std::string> * value, const char * desc)
- {
- Argument arg;
- arg.type = ArgumentType::VectorString;
- arg.name = name;
- arg.value = static_cast<void *>(value);
- arg.flags = 0;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- size_t Command::AddArgument(const char * name, chip::Optional<std::vector<std::string>> * value, const char * desc)
- {
- Argument arg;
- arg.type = ArgumentType::VectorString;
- arg.name = name;
- arg.value = static_cast<void *>(value);
- arg.flags = Argument::kOptional;
- arg.desc = desc;
- return AddArgumentToList(std::move(arg));
- }
- const char * Command::GetArgumentName(size_t index) const
- {
- if (index < mArgs.size())
- {
- return mArgs.at(index).name;
- }
- return nullptr;
- }
- const char * Command::GetArgumentDescription(size_t index) const
- {
- if (index < mArgs.size())
- {
- return mArgs.at(index).desc;
- }
- return nullptr;
- }
- const char * Command::GetReadOnlyGlobalCommandArgument() const
- {
- if (GetAttribute())
- {
- return GetAttribute();
- }
- if (GetEvent())
- {
- return GetEvent();
- }
- return nullptr;
- }
- const char * Command::GetAttribute() const
- {
- if (mReadOnlyGlobalCommandArgument.HasValue())
- {
- return mReadOnlyGlobalCommandArgument.Value().value;
- }
- return nullptr;
- }
- const char * Command::GetEvent() const
- {
- if (mReadOnlyGlobalCommandArgument.HasValue())
- {
- return mReadOnlyGlobalCommandArgument.Value().value;
- }
- return nullptr;
- }
- size_t Command::AddArgumentToList(Argument && argument)
- {
- if (argument.isOptional() || mArgs.empty() || !mArgs.back().isOptional())
- {
- // Safe to just append.
- mArgs.emplace_back(std::move(argument));
- return mArgs.size();
- }
- // We're inserting a non-optional arg but we already have something optional
- // in the list. Insert before the first optional arg.
- for (auto cur = mArgs.cbegin(), end = mArgs.cend(); cur != end; ++cur)
- {
- if ((*cur).isOptional())
- {
- mArgs.emplace(cur, std::move(argument));
- return mArgs.size();
- }
- }
- // Never reached.
- VerifyOrDie(false);
- return 0;
- }
- namespace {
- template <typename T>
- void ResetOptionalArg(const Argument & arg)
- {
- VerifyOrDie(arg.isOptional());
- if (arg.isNullable())
- {
- reinterpret_cast<chip::Optional<chip::app::DataModel::Nullable<T>> *>(arg.value)->ClearValue();
- }
- else
- {
- reinterpret_cast<chip::Optional<T> *>(arg.value)->ClearValue();
- }
- }
- } // anonymous namespace
- void Command::ResetArguments()
- {
- for (const auto & arg : mArgs)
- {
- const ArgumentType type = arg.type;
- if (arg.isOptional())
- {
- // Must always clean these up so they don't carry over to the next
- // command invocation in interactive mode.
- switch (type)
- {
- case ArgumentType::Complex: {
- // Optional Complex arguments are not currently supported via the <chip::Optional> class.
- // Instead, they must be explicitly specified as optional using the kOptional flag,
- // and the base TypedComplexArgument<T> class is referenced.
- auto argument = static_cast<ComplexArgument *>(arg.value);
- argument->Reset();
- break;
- }
- case ArgumentType::Custom: {
- // No optional custom arguments so far.
- VerifyOrDie(false);
- break;
- }
- case ArgumentType::VectorString: {
- ResetOptionalArg<std::vector<std::string>>(arg);
- break;
- }
- case ArgumentType::VectorBool: {
- ResetOptionalArg<std::vector<bool>>(arg);
- break;
- }
- case ArgumentType::Vector16: {
- // No optional Vector16 arguments so far.
- VerifyOrDie(false);
- break;
- }
- case ArgumentType::Vector32: {
- ResetOptionalArg<std::vector<uint32_t>>(arg);
- break;
- }
- case ArgumentType::VectorCustom: {
- // No optional VectorCustom arguments so far.
- VerifyOrDie(false);
- break;
- }
- case ArgumentType::String: {
- ResetOptionalArg<char *>(arg);
- break;
- }
- case ArgumentType::CharString: {
- ResetOptionalArg<chip::CharSpan>(arg);
- break;
- }
- case ArgumentType::OctetString: {
- ResetOptionalArg<chip::ByteSpan>(arg);
- break;
- }
- case ArgumentType::Bool: {
- ResetOptionalArg<bool>(arg);
- break;
- }
- case ArgumentType::Number_uint8: {
- ResetOptionalArg<uint8_t>(arg);
- break;
- }
- case ArgumentType::Number_uint16: {
- ResetOptionalArg<uint16_t>(arg);
- break;
- }
- case ArgumentType::Number_uint32: {
- ResetOptionalArg<uint32_t>(arg);
- break;
- }
- case ArgumentType::Number_uint64: {
- ResetOptionalArg<uint64_t>(arg);
- break;
- }
- case ArgumentType::Number_int8: {
- ResetOptionalArg<int8_t>(arg);
- break;
- }
- case ArgumentType::Number_int16: {
- ResetOptionalArg<int16_t>(arg);
- break;
- }
- case ArgumentType::Number_int32: {
- ResetOptionalArg<int32_t>(arg);
- break;
- }
- case ArgumentType::Number_int64: {
- ResetOptionalArg<int64_t>(arg);
- break;
- }
- case ArgumentType::Float: {
- ResetOptionalArg<float>(arg);
- break;
- }
- case ArgumentType::Double: {
- ResetOptionalArg<double>(arg);
- break;
- }
- case ArgumentType::Address: {
- ResetOptionalArg<AddressWithInterface>(arg);
- break;
- }
- }
- }
- else
- {
- // Some non-optional arguments have state that needs to be cleaned
- // up too.
- if (type == ArgumentType::Vector16)
- {
- auto vectorArgument = static_cast<std::vector<uint16_t> *>(arg.value);
- vectorArgument->clear();
- }
- else if (type == ArgumentType::Vector32)
- {
- auto vectorArgument = static_cast<std::vector<uint32_t> *>(arg.value);
- vectorArgument->clear();
- }
- else if (type == ArgumentType::VectorCustom)
- {
- auto vectorArgument = static_cast<std::vector<CustomArgument *> *>(arg.value);
- for (auto & customArgument : *vectorArgument)
- {
- delete customArgument;
- }
- vectorArgument->clear();
- }
- else if (type == ArgumentType::Complex)
- {
- auto argument = static_cast<ComplexArgument *>(arg.value);
- argument->Reset();
- }
- }
- }
- }
|