[string] introduce StringWriter class (#6564)

This commit moves methods of String out of the header file to save code
size.

Since most use cases of String writers ignores errors, this commit
changes the return of writers to the Writer object itself for chained
writes.
This commit is contained in:
Yakun Xu
2021-05-05 21:52:59 -07:00
committed by GitHub
parent 26cdf63231
commit b39f5b6dd2
18 changed files with 284 additions and 278 deletions
+21 -14
View File
@@ -59,6 +59,7 @@ static void Log(otLogLevel aLogLevel,
va_list aArgs) va_list aArgs)
{ {
ot::String<OPENTHREAD_CONFIG_LOG_MAX_SIZE> logString; ot::String<OPENTHREAD_CONFIG_LOG_MAX_SIZE> logString;
ot::StringWriter writer(logString);
#if OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE #if OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE
VerifyOrExit(otLoggingGetLevel() >= aLogLevel); VerifyOrExit(otLoggingGetLevel() >= aLogLevel);
@@ -96,16 +97,18 @@ static void Log(otLogLevel aLogLevel,
break; break;
} }
IgnoreError(logString.Append("%s", levelStr)); writer.Append("%s", levelStr);
} }
#endif // OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL #endif // OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL
IgnoreError(logString.Append("%s", aRegionPrefix)); writer.Append("%s", aRegionPrefix);
VerifyOrExit(logString.AppendVarArgs(aFormat, aArgs) != ot::kErrorInvalidArgs); writer.AppendVarArgs(aFormat, aArgs);
otPlatLog(aLogLevel, aLogRegion, "%s" OPENTHREAD_CONFIG_LOG_SUFFIX, logString.AsCString()); otPlatLog(aLogLevel, aLogRegion, "%s" OPENTHREAD_CONFIG_LOG_SUFFIX, logString.AsCString());
#if OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE
exit: exit:
return; return;
#endif
} }
#if OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_CRIT #if OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_CRIT
@@ -232,26 +235,29 @@ enum : uint8_t
static void DumpLine(otLogLevel aLogLevel, otLogRegion aLogRegion, const uint8_t *aBytes, const size_t aLength) static void DumpLine(otLogLevel aLogLevel, otLogRegion aLogRegion, const uint8_t *aBytes, const size_t aLength)
{ {
ot::String<kStringLineLength> string("|"); ot::String<kStringLineLength> string;
ot::StringWriter writer(string);
writer.Append("|");
for (uint8_t i = 0; i < kDumpBytesPerLine; i++) for (uint8_t i = 0; i < kDumpBytesPerLine; i++)
{ {
if (i < aLength) if (i < aLength)
{ {
IgnoreError(string.Append(" %02X", aBytes[i])); writer.Append(" %02X", aBytes[i]);
} }
else else
{ {
IgnoreError(string.Append(" ..")); writer.Append(" ..");
} }
if (!((i + 1) % 8)) if (!((i + 1) % 8))
{ {
IgnoreError(string.Append(" |")); writer.Append(" |");
} }
} }
IgnoreError(string.Append(" ")); writer.Append(" ");
for (uint8_t i = 0; i < kDumpBytesPerLine; i++) for (uint8_t i = 0; i < kDumpBytesPerLine; i++)
{ {
@@ -267,7 +273,7 @@ static void DumpLine(otLogLevel aLogLevel, otLogRegion aLogRegion, const uint8_t
} }
} }
IgnoreError(string.Append("%c", c)); writer.Append("%c", c);
} }
otLogDump(aLogLevel, aLogRegion, "%s", string.AsCString()); otLogDump(aLogLevel, aLogRegion, "%s", string.AsCString());
@@ -282,17 +288,18 @@ void otDump(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aId, const
size_t idLen = strlen(aId); size_t idLen = strlen(aId);
ot::String<kStringLineLength> string; ot::String<kStringLineLength> string;
ot::StringWriter writer(string);
for (size_t i = 0; i < (kWidth - idLen) / 2 - 5; i++) for (size_t i = 0; i < (kWidth - idLen) / 2 - 5; i++)
{ {
IgnoreError(string.Append("=")); writer.Append("=");
} }
IgnoreError(string.Append("[%s len=%03u]", aId, static_cast<unsigned>(aLength))); writer.Append("[%s len=%03u]", aId, static_cast<unsigned>(aLength));
for (size_t i = 0; i < (kWidth - idLen) / 2 - 4; i++) for (size_t i = 0; i < (kWidth - idLen) / 2 - 4; i++)
{ {
IgnoreError(string.Append("=")); writer.Append("=");
} }
otLogDump(aLogLevel, aLogRegion, "%s", string.AsCString()); otLogDump(aLogLevel, aLogRegion, "%s", string.AsCString());
@@ -303,11 +310,11 @@ void otDump(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aId, const
OT_MIN((aLength - i), static_cast<size_t>(kDumpBytesPerLine))); OT_MIN((aLength - i), static_cast<size_t>(kDumpBytesPerLine)));
} }
string.Clear(); writer.Clear();
for (size_t i = 0; i < kWidth; i++) for (size_t i = 0; i < kWidth; i++)
{ {
IgnoreError(string.Append("-")); writer.Append("-");
} }
otLogDump(aLogLevel, aLogRegion, "%s", string.AsCString()); otLogDump(aLogLevel, aLogRegion, "%s", string.AsCString());
+4 -3
View File
@@ -212,6 +212,7 @@ void Notifier::LogEvents(Events aEvents) const
bool addSpace = false; bool addSpace = false;
bool didLog = false; bool didLog = false;
String<kFlagsStringBufferSize> string; String<kFlagsStringBufferSize> string;
StringWriter writer(string);
for (uint8_t bit = 0; bit < sizeof(Events::Flags) * CHAR_BIT; bit++) for (uint8_t bit = 0; bit < sizeof(Events::Flags) * CHAR_BIT; bit++)
{ {
@@ -219,16 +220,16 @@ void Notifier::LogEvents(Events aEvents) const
if (flags & (1 << bit)) if (flags & (1 << bit))
{ {
if (string.GetLength() >= kFlagsStringLineLimit) if (writer.GetLength() >= kFlagsStringLineLimit)
{ {
otLogInfoCore("Notifier: StateChanged (0x%08x) %s%s ...", aEvents.GetAsFlags(), didLog ? "... " : "[", otLogInfoCore("Notifier: StateChanged (0x%08x) %s%s ...", aEvents.GetAsFlags(), didLog ? "... " : "[",
string.AsCString()); string.AsCString());
string.Clear(); writer.Clear();
didLog = true; didLog = true;
addSpace = false; addSpace = false;
} }
IgnoreError(string.Append("%s%s", addSpace ? " " : "", EventToString(static_cast<Event>(1 << bit)))); writer.Append("%s%s", addSpace ? " " : "", EventToString(static_cast<Event>(1 << bit)));
addSpace = true; addSpace = true;
flags ^= (1 << bit); flags ^= (1 << bit);
+45 -18
View File
@@ -32,6 +32,7 @@
*/ */
#include "string.hpp" #include "string.hpp"
#include "debug.hpp"
#include <string.h> #include <string.h>
@@ -72,30 +73,56 @@ bool StringEndsWith(const char *aString, char aChar)
return len > 0 && aString[len - 1] == aChar; return len > 0 && aString[len - 1] == aChar;
} }
Error StringBase::Write(char *aBuffer, uint16_t aSize, uint16_t &aLength, const char *aFormat, va_list aArgs) StringWriter::StringWriter(char *aBuffer, uint16_t aSize)
: mBuffer(aBuffer)
, mLength(0)
, mSize(aSize)
{ {
Error error = kErrorNone; mBuffer[0] = '\0';
int len; }
len = vsnprintf(aBuffer + aLength, aSize - aLength, aFormat, aArgs); StringWriter &StringWriter::Clear(void)
{
mBuffer[0] = '\0';
mLength = 0;
return *this;
}
if (len < 0) StringWriter &StringWriter::Append(const char *aFormat, ...)
{
va_list args;
va_start(args, aFormat);
AppendVarArgs(aFormat, args);
va_end(args);
return *this;
}
StringWriter &StringWriter::AppendVarArgs(const char *aFormat, va_list aArgs)
{
int len;
len = vsnprintf(mBuffer + mLength, (mSize > mLength ? (mSize - mLength) : 0), aFormat, aArgs);
OT_ASSERT(len >= 0);
mLength += static_cast<uint16_t>(len);
if (IsTruncated())
{ {
aLength = 0; mBuffer[mSize - 1] = '\0';
aBuffer[0] = 0;
error = kErrorInvalidArgs;
}
else if (len >= aSize - aLength)
{
aLength = aSize - 1;
error = kErrorNoBufs;
}
else
{
aLength += static_cast<uint16_t>(len);
} }
return error; return *this;
}
StringWriter &StringWriter::AppendHexBytes(const uint8_t *aBytes, uint16_t aLength)
{
while (aLength--)
{
Append("%02x", *aBytes++);
}
return *this;
} }
bool IsValidUtf8String(const char *aString) bool IsValidUtf8String(const char *aString)
+61 -122
View File
@@ -90,79 +90,75 @@ const char *StringFind(const char *aString, char aChar);
*/ */
bool StringEndsWith(const char *aString, char aChar); bool StringEndsWith(const char *aString, char aChar);
/** class StringWriter;
* This class defines the base class for `String`.
*
*/
class StringBase
{
protected:
/**
* This method appends `printf()` style formatted data to a given character string buffer.
*
* @param[in] aBuffer A pointer to buffer containing the string.
* @param[in] aSize The size of the buffer (in bytes).
* @param[inout] aLength A reference to variable containing current length of string. On exit length is updated.
* @param[in] aFormat A pointer to the format string.
* @param[in] aArgs Arguments for the format specification.
*
* @retval kErrorNone Updated the string successfully.
* @retval kErrorNoBufs String could not fit in the storage.
* @retval kErrorInvalidArgs Arguments do not match the format string.
*/
static Error Write(char *aBuffer, uint16_t aSize, uint16_t &aLength, const char *aFormat, va_list aArgs);
};
/** /**
* This class defines a fixed-size string. * This class defines a fixed-size string.
* *
*/ */
template <uint16_t SIZE> class String : private StringBase template <uint16_t kSize> class String
{
friend class StringWriter;
static_assert(kSize > 0, "String buffer cannot be empty.");
public:
/**
* This method returns the string as a null-terminated C string.
*
* @returns The null-terminated C string.
*
*/
const char *AsCString(void) const { return mBuffer; }
private:
char mBuffer[kSize];
};
/**
* This class implements writing to a string buffer.
*
*/
class StringWriter
{ {
public: public:
enum
{
kSize = SIZE, ///< Size (number of characters) in the buffer storage for the string.
};
/** /**
* This constructor initializes the `String` object as empty. * This constructor initializes the object as cleared on the provided buffer.
* *
*/ */
String(void) StringWriter(char *aBuffer, uint16_t aSize);
: mLength(0)
/**
* This constructor initializes the object as cleared on a fixed-size string.
*
*/
template <uint16_t kSize>
explicit StringWriter(String<kSize> &aStringBuffer)
: StringWriter(aStringBuffer.mBuffer, kSize)
{ {
mBuffer[0] = 0;
} }
/** /**
* This constructor initializes the `String` object using `printf()` style formatted data. * This method clears the string writer.
* *
* @param[in] aFormat A pointer to the format string. * @returns The string writer.
* @param[in] ... Arguments for the format specification.
* *
*/ */
explicit String(const char *aFormat, ...) StringWriter &Clear(void);
: mLength(0)
{
va_list args;
va_start(args, aFormat);
IgnoreError(Write(mBuffer, kSize, mLength, aFormat, args));
va_end(args);
}
/** /**
* This method clears the string. * This method returns whether the output is truncated.
*
* @note If the output is truncated, the buffer is still null-terminated.
*
* @retval true The output is truncated.
* @retval false The output is not truncated.
* *
*/ */
void Clear(void) bool IsTruncated(void) const { return mLength >= mSize; }
{
mBuffer[0] = 0;
mLength = 0;
}
/** /**
* This method gets the length of the string. * This method gets the length of the wanted string.
* *
* Similar to `strlen()` the length does not include the null character at the end of the string. * Similar to `strlen()` the length does not include the null character at the end of the string.
* *
@@ -172,107 +168,50 @@ public:
uint16_t GetLength(void) const { return mLength; } uint16_t GetLength(void) const { return mLength; }
/** /**
* This method returns the size (number of chars) in the buffer storage for the string. * This method returns the size (number of chars) in the buffer.
* *
* @returns The size of the buffer storage for the string. * @returns The size of the buffer.
* *
*/ */
uint16_t GetSize(void) const { return kSize; } uint16_t GetSize(void) const { return mSize; }
/** /**
* This method returns the string as a null-terminated C string. * This method appends `printf()` style formatted data to the buffer.
*
* @returns The null-terminated C string.
*
*/
const char *AsCString(void) const { return mBuffer; }
/**
* This method sets the string using `printf()` style formatted data.
* *
* @param[in] aFormat A pointer to the format string. * @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification. * @param[in] ... Arguments for the format specification.
* *
* @retval kErrorNone Updated the string successfully. * @returns The string writer.
* @retval kErrorNoBufs String could not fit in the storage.
* @retval kErrorInvalidArgs Arguments do not match the format string.
* *
*/ */
Error Set(const char *aFormat, ...) StringWriter &Append(const char *aFormat, ...);
{
va_list args;
Error error;
va_start(args, aFormat);
mLength = 0;
error = Write(mBuffer, kSize, mLength, aFormat, args);
va_end(args);
return error;
}
/** /**
* This method appends `printf()` style formatted data to the `String` object. * This method appends `printf()` style formatted data to the buffer.
*
* @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification.
*
* @retval kErrorNone Updated the string successfully.
* @retval kErrorNoBufs String could not fit in the storage.
* @retval kErrorInvalidArgs Arguments do not match the format string.
*
*/
Error Append(const char *aFormat, ...)
{
va_list args;
Error error;
va_start(args, aFormat);
error = Write(mBuffer, kSize, mLength, aFormat, args);
va_end(args);
return error;
}
/**
* This method appends `printf()` style formatted data to the `String` object.
* *
* @param[in] aFormat A pointer to the format string. * @param[in] aFormat A pointer to the format string.
* @param[in] aArgs Arguments for the format specification (as `va_list`). * @param[in] aArgs Arguments for the format specification (as `va_list`).
* *
* @retval kErrorNone Updated the string successfully. * @returns The string writer.
* @retval kErrorNoBufs String could not fit in the storage.
* @retval kErrorInvalidArgs Arguments do not match the format string.
* *
*/ */
Error AppendVarArgs(const char *aFormat, va_list aArgs) { return Write(mBuffer, kSize, mLength, aFormat, aArgs); } StringWriter &AppendVarArgs(const char *aFormat, va_list aArgs);
/** /**
* This method appends an array of bytes in hex representation (using "%02x" style) to the `String` object. * This method appends an array of bytes in hex representation (using "%02x" style) to the buffer.
* *
* @param[in] aBytes A pointer to buffer containing the bytes to append. * @param[in] aBytes A pointer to buffer containing the bytes to append.
* @param[in] aLength The length of @p aBytes buffer (in bytes). * @param[in] aLength The length of @p aBytes buffer (in bytes).
* *
* @retval kErrorNone Updated the string successfully. * @returns The string writer.
* @retval kErrorNoBufs String could not fit in the storage.
* *
*/ */
Error AppendHexBytes(const uint8_t *aBytes, uint16_t aLength) StringWriter &AppendHexBytes(const uint8_t *aBytes, uint16_t aLength);
{
Error error = kErrorNone;
while (aLength--)
{
SuccessOrExit(error = Append("%02x", *aBytes++));
}
exit:
return error;
}
private: private:
uint16_t mLength; char * mBuffer;
char mBuffer[kSize]; uint16_t mLength;
const uint16_t mSize;
}; };
/** /**
+9 -8
View File
@@ -95,12 +95,13 @@ exit:
ChannelMask::InfoString ChannelMask::ToString(void) const ChannelMask::InfoString ChannelMask::ToString(void) const
{ {
InfoString string; InfoString string;
uint8_t channel = kChannelIteratorFirst; StringWriter writer(string);
bool addComma = false; uint8_t channel = kChannelIteratorFirst;
Error error; bool addComma = false;
Error error;
IgnoreError(string.Append("{")); writer.Append("{");
error = GetNextChannel(channel); error = GetNextChannel(channel);
@@ -119,16 +120,16 @@ ChannelMask::InfoString ChannelMask::ToString(void) const
rangeEnd = channel; rangeEnd = channel;
} }
IgnoreError(string.Append("%s%d", addComma ? ", " : " ", rangeStart)); writer.Append("%s%d", addComma ? ", " : " ", rangeStart);
addComma = true; addComma = true;
if (rangeStart < rangeEnd) if (rangeStart < rangeEnd)
{ {
IgnoreError(string.Append("%s%d", rangeEnd == rangeStart + 1 ? ", " : "-", rangeEnd)); writer.Append("%s%d", rangeEnd == rangeStart + 1 ? ", " : "-", rangeEnd);
} }
} }
IgnoreError(string.Append(" }")); writer.Append(" }");
return string; return string;
} }
+20 -18
View File
@@ -1381,26 +1381,27 @@ exit:
Frame::InfoString Frame::ToInfoString(void) const Frame::InfoString Frame::ToInfoString(void) const
{ {
InfoString string; InfoString string;
uint8_t commandId, type; StringWriter writer(string);
Address src, dst; uint8_t commandId, type;
Address src, dst;
IgnoreError(string.Append("len:%d, seqnum:%d, type:", mLength, GetSequence())); writer.Append("len:%d, seqnum:%d, type:", mLength, GetSequence());
type = GetType(); type = GetType();
switch (type) switch (type)
{ {
case kFcfFrameBeacon: case kFcfFrameBeacon:
IgnoreError(string.Append("Beacon")); writer.Append("Beacon");
break; break;
case kFcfFrameData: case kFcfFrameData:
IgnoreError(string.Append("Data")); writer.Append("Data");
break; break;
case kFcfFrameAck: case kFcfFrameAck:
IgnoreError(string.Append("Ack")); writer.Append("Ack");
break; break;
case kFcfFrameMacCmd: case kFcfFrameMacCmd:
@@ -1412,34 +1413,33 @@ Frame::InfoString Frame::ToInfoString(void) const
switch (commandId) switch (commandId)
{ {
case kMacCmdDataRequest: case kMacCmdDataRequest:
IgnoreError(string.Append("Cmd(DataReq)")); writer.Append("Cmd(DataReq)");
break; break;
case kMacCmdBeaconRequest: case kMacCmdBeaconRequest:
IgnoreError(string.Append("Cmd(BeaconReq)")); writer.Append("Cmd(BeaconReq)");
break; break;
default: default:
IgnoreError(string.Append("Cmd(%d)", commandId)); writer.Append("Cmd(%d)", commandId);
break; break;
} }
break; break;
default: default:
IgnoreError(string.Append("%d", type)); writer.Append("%d", type);
break; break;
} }
IgnoreError(GetSrcAddr(src)); IgnoreError(GetSrcAddr(src));
IgnoreError(GetDstAddr(dst)); IgnoreError(GetDstAddr(dst));
IgnoreError(string.Append(", src:%s, dst:%s, sec:%s, ackreq:%s", src.ToString().AsCString(), writer.Append(", src:%s, dst:%s, sec:%s, ackreq:%s", src.ToString().AsCString(), dst.ToString().AsCString(),
dst.ToString().AsCString(), GetSecurityEnabled() ? "yes" : "no", GetSecurityEnabled() ? "yes" : "no", GetAckRequest() ? "yes" : "no");
GetAckRequest() ? "yes" : "no"));
#if OPENTHREAD_CONFIG_MULTI_RADIO #if OPENTHREAD_CONFIG_MULTI_RADIO
IgnoreError(string.Append(", radio:%s", RadioTypeToString(GetRadioType()))); writer.Append(", radio:%s", RadioTypeToString(GetRadioType()));
#endif #endif
return string; return string;
@@ -1448,12 +1448,14 @@ Frame::InfoString Frame::ToInfoString(void) const
BeaconPayload::InfoString BeaconPayload::ToInfoString(void) const BeaconPayload::InfoString BeaconPayload::ToInfoString(void) const
{ {
NetworkName name; NetworkName name;
InfoString string;
IgnoreError(name.Set(GetNetworkName())); IgnoreError(name.Set(GetNetworkName()));
return InfoString("name:%s, xpanid:%s, id:%d, ver:%d, joinable:%s, native:%s", name.GetAsCString(), StringWriter(string).Append("name:%s, xpanid:%s, id:%d, ver:%d, joinable:%s, native:%s", name.GetAsCString(),
mExtendedPanId.ToString().AsCString(), GetProtocolId(), GetProtocolVersion(), mExtendedPanId.ToString().AsCString(), GetProtocolId(), GetProtocolVersion(),
IsJoiningPermitted() ? "yes" : "no", IsNative() ? "yes" : "no"); IsJoiningPermitted() ? "yes" : "no", IsNative() ? "yes" : "no");
return string;
} }
#endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1) #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_NOTE) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
+25 -9
View File
@@ -67,7 +67,7 @@ ExtAddress::InfoString ExtAddress::ToString(void) const
{ {
InfoString string; InfoString string;
IgnoreError(string.AppendHexBytes(m8, sizeof(ExtAddress))); StringWriter(string).AppendHexBytes(m8, sizeof(ExtAddress));
return string; return string;
} }
@@ -92,15 +92,29 @@ void ExtAddress::CopyAddress(uint8_t *aDst, const uint8_t *aSrc, CopyByteOrder a
Address::InfoString Address::ToString(void) const Address::InfoString Address::ToString(void) const
{ {
return (mType == kTypeExtended) ? GetExtended().ToString() InfoString string;
: (mType == kTypeNone ? InfoString("None") : InfoString("0x%04x", GetShort()));
if (mType == kTypeExtended)
{
string = GetExtended().ToString();
}
else if (mType == kTypeNone)
{
StringWriter(string).Append("None");
}
else
{
StringWriter(string).Append("0x%04x", GetShort());
}
return string;
} }
ExtendedPanId::InfoString ExtendedPanId::ToString(void) const ExtendedPanId::InfoString ExtendedPanId::ToString(void) const
{ {
InfoString string; InfoString string;
IgnoreError(string.AppendHexBytes(m8, sizeof(ExtendedPanId))); StringWriter(string).AppendHexBytes(m8, sizeof(ExtendedPanId));
return string; return string;
} }
@@ -203,13 +217,15 @@ void RadioTypes::AddAll(void)
RadioTypes::InfoString RadioTypes::ToString(void) const RadioTypes::InfoString RadioTypes::ToString(void) const
{ {
InfoString string("{"); InfoString string;
bool addComma = false; StringWriter writer(string);
bool addComma = false;
writer.Append("{");
#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
if (Contains(kRadioTypeIeee802154)) if (Contains(kRadioTypeIeee802154))
{ {
IgnoreError(string.Append("%s%s", addComma ? ", " : " ", RadioTypeToString(kRadioTypeIeee802154))); writer.Append("%s%s", addComma ? ", " : " ", RadioTypeToString(kRadioTypeIeee802154));
addComma = true; addComma = true;
} }
#endif #endif
@@ -217,14 +233,14 @@ RadioTypes::InfoString RadioTypes::ToString(void) const
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
if (Contains(kRadioTypeTrel)) if (Contains(kRadioTypeTrel))
{ {
IgnoreError(string.Append("%s%s", addComma ? ", " : " ", RadioTypeToString(kRadioTypeTrel))); writer.Append("%s%s", addComma ? ", " : " ", RadioTypeToString(kRadioTypeTrel));
addComma = true; addComma = true;
} }
#endif #endif
OT_UNUSED_VARIABLE(addComma); OT_UNUSED_VARIABLE(addComma);
IgnoreError(string.Append(" }")); writer.Append(" }");
return string; return string;
} }
+6 -5
View File
@@ -164,22 +164,23 @@ bool JoinerDiscerner::operator==(const JoinerDiscerner &aOther) const
JoinerDiscerner::InfoString JoinerDiscerner::ToString(void) const JoinerDiscerner::InfoString JoinerDiscerner::ToString(void) const
{ {
InfoString str; InfoString str;
StringWriter writer(str);
if (mLength <= sizeof(uint16_t) * CHAR_BIT) if (mLength <= sizeof(uint16_t) * CHAR_BIT)
{ {
IgnoreError(str.Set("0x%04x", static_cast<uint16_t>(mValue))); writer.Append("0x%04x", static_cast<uint16_t>(mValue));
} }
else if (mLength <= sizeof(uint32_t) * CHAR_BIT) else if (mLength <= sizeof(uint32_t) * CHAR_BIT)
{ {
IgnoreError(str.Set("0x%08x", static_cast<uint32_t>(mValue))); writer.Append("0x%08x", static_cast<uint32_t>(mValue));
} }
else else
{ {
IgnoreError(str.Set("0x%x-%08x", static_cast<uint32_t>(mValue >> 32), static_cast<uint32_t>(mValue))); writer.Append("0x%x-%08x", static_cast<uint32_t>(mValue >> 32), static_cast<uint32_t>(mValue));
} }
IgnoreError(str.Append("/len:%d", mLength)); writer.Append("/len:%d", mLength);
return str; return str;
} }
+4 -1
View File
@@ -88,7 +88,10 @@ exit:
Address::InfoString Address::ToString(void) const Address::InfoString Address::ToString(void) const
{ {
return InfoString("%d.%d.%d.%d", mBytes[0], mBytes[1], mBytes[2], mBytes[3]); InfoString string;
StringWriter(string).Append("%d.%d.%d.%d", mBytes[0], mBytes[1], mBytes[2], mBytes[3]);
return string;
} }
} // namespace Ip4 } // namespace Ip4
+13 -9
View File
@@ -126,20 +126,21 @@ bool Prefix::IsValidNat64(void) const
Prefix::InfoString Prefix::ToString(void) const Prefix::InfoString Prefix::ToString(void) const
{ {
InfoString string; InfoString string;
uint8_t sizeInUint16 = (GetBytesSize() + sizeof(uint16_t) - 1) / sizeof(uint16_t); StringWriter writer(string);
uint8_t sizeInUint16 = (GetBytesSize() + sizeof(uint16_t) - 1) / sizeof(uint16_t);
for (uint16_t i = 0; i < sizeInUint16; i++) for (uint16_t i = 0; i < sizeInUint16; i++)
{ {
IgnoreError(string.Append("%s%x", (i > 0) ? ":" : "", HostSwap16(mPrefix.mFields.m16[i]))); writer.Append("%s%x", (i > 0) ? ":" : "", HostSwap16(mPrefix.mFields.m16[i]));
} }
if (GetBytesSize() < Address::kSize - 1) if (GetBytesSize() < Address::kSize - 1)
{ {
IgnoreError(string.Append("::")); writer.Append("::");
} }
IgnoreError(string.Append("/%d", mLength)); writer.Append("/%d", mLength);
return string; return string;
} }
@@ -248,7 +249,7 @@ InterfaceIdentifier::InfoString InterfaceIdentifier::ToString(void) const
{ {
InfoString string; InfoString string;
IgnoreError(string.AppendHexBytes(mFields.m8, kSize)); StringWriter(string).AppendHexBytes(mFields.m8, kSize);
return string; return string;
} }
@@ -629,9 +630,12 @@ exit:
Address::InfoString Address::ToString(void) const Address::InfoString Address::ToString(void) const
{ {
return InfoString("%x:%x:%x:%x:%x:%x:%x:%x", HostSwap16(mFields.m16[0]), HostSwap16(mFields.m16[1]), InfoString string;
HostSwap16(mFields.m16[2]), HostSwap16(mFields.m16[3]), HostSwap16(mFields.m16[4]),
HostSwap16(mFields.m16[5]), HostSwap16(mFields.m16[6]), HostSwap16(mFields.m16[7])); StringWriter(string).Append("%x:%x:%x:%x:%x:%x:%x:%x", HostSwap16(mFields.m16[0]), HostSwap16(mFields.m16[1]),
HostSwap16(mFields.m16[2]), HostSwap16(mFields.m16[3]), HostSwap16(mFields.m16[4]),
HostSwap16(mFields.m16[5]), HostSwap16(mFields.m16[6]), HostSwap16(mFields.m16[7]));
return string;
} }
const Address &Address::GetLinkLocalAllNodesMulticast(void) const Address &Address::GetLinkLocalAllNodesMulticast(void)
+4 -1
View File
@@ -38,7 +38,10 @@ namespace Ip6 {
SockAddr::InfoString SockAddr::ToString(void) const SockAddr::InfoString SockAddr::ToString(void) const
{ {
return InfoString("[%s]:%u", GetAddress().ToString().AsCString(), GetPort()); InfoString string;
StringWriter(string).Append("[%s]:%u", GetAddress().ToString().AsCString(), GetPort());
return string;
} }
} // namespace Ip6 } // namespace Ip6
+9 -9
View File
@@ -77,35 +77,35 @@ uint16_t Header::GetSize(Type aType)
Header::InfoString Header::ToString(void) const Header::InfoString Header::ToString(void) const
{ {
Type type = GetType(); Type type = GetType();
InfoString string; InfoString string;
StringWriter writer(string);
switch (type) switch (type)
{ {
case kTypeBroadcast: case kTypeBroadcast:
IgnoreError(string.Set("broadcast ch:%d", GetChannel())); writer.Append("broadcast ch:%d", GetChannel());
break; break;
case kTypeUnicast: case kTypeUnicast:
IgnoreError(string.Set("unicast ch:%d", GetChannel())); writer.Append("unicast ch:%d", GetChannel());
break; break;
case kTypeAck: case kTypeAck:
IgnoreError(string.Set("ack")); writer.Append("ack");
break; break;
} }
IgnoreError( writer.Append(" panid:%04x num:%lu src:%s", GetPanId(), GetPacketNumber(), GetSource().ToString().AsCString());
string.Append(" panid:%04x num:%lu src:%s", GetPanId(), GetPacketNumber(), GetSource().ToString().AsCString()));
if ((type == kTypeUnicast) || (type == kTypeAck)) if ((type == kTypeUnicast) || (type == kTypeAck))
{ {
IgnoreError(string.Append(" dst:%s", GetDestination().ToString().AsCString())); writer.Append(" dst:%s", GetDestination().ToString().AsCString());
} }
if ((type == kTypeUnicast) || (type == kTypeBroadcast)) if ((type == kTypeUnicast) || (type == kTypeBroadcast))
{ {
IgnoreError(string.Append(GetAckMode() == kNoAck ? " no-ack" : " ack-req")); writer.Append(GetAckMode() == kNoAck ? " no-ack" : " ack-req");
} }
return string; return string;
+7 -3
View File
@@ -109,7 +109,8 @@ RssAverager::InfoString RssAverager::ToString(void) const
InfoString string; InfoString string;
VerifyOrExit(mCount != 0); VerifyOrExit(mCount != 0);
IgnoreError(string.Set("%d.%s", -(mAverage >> kPrecisionBitShift), kDigitsString[mAverage & kPrecisionBitMask])); StringWriter(string).Append("%d.%s", -(mAverage >> kPrecisionBitShift),
kDigitsString[mAverage & kPrecisionBitMask]);
exit: exit:
return string; return string;
@@ -166,8 +167,11 @@ uint8_t LinkQualityInfo::GetLinkMargin(void) const
LinkQualityInfo::InfoString LinkQualityInfo::ToInfoString(void) const LinkQualityInfo::InfoString LinkQualityInfo::ToInfoString(void) const
{ {
return InfoString("aveRss:%s, lastRss:%d, linkQuality:%d", mRssAverager.ToString().AsCString(), GetLastRss(), InfoString string;
GetLinkQuality());
StringWriter(string).Append("aveRss:%s, lastRss:%d, linkQuality:%d", mRssAverager.ToString().AsCString(),
GetLastRss(), GetLinkQuality());
return string;
} }
uint8_t LinkQualityInfo::ConvertRssToLinkMargin(int8_t aNoiseFloor, int8_t aRss) uint8_t LinkQualityInfo::ConvertRssToLinkMargin(int8_t aNoiseFloor, int8_t aRss)
+1 -1
View File
@@ -4117,7 +4117,7 @@ void Mle::Log(MessageAction aAction, MessageType aType, const Ip6::Address &aAdd
if (aRloc != Mac::kShortAddrInvalid) if (aRloc != Mac::kShortAddrInvalid)
{ {
IgnoreError(rlocString.Set(",0x%04x", aRloc)); StringWriter(rlocString).Append(",0x%04x", aRloc);
} }
otLogInfoMle("%s %s%s (%s%s)", MessageActionToString(aAction), MessageTypeToString(aType), otLogInfoMle("%s %s%s (%s%s)", MessageActionToString(aAction), MessageTypeToString(aType),
+5 -2
View File
@@ -55,8 +55,11 @@ void DeviceMode::Set(const ModeConfig &aModeConfig)
DeviceMode::InfoString DeviceMode::ToString(void) const DeviceMode::InfoString DeviceMode::ToString(void) const
{ {
return InfoString("rx-on:%s ftd:%s full-net:%s", IsRxOnWhenIdle() ? "yes" : "no", InfoString string;
IsFullThreadDevice() ? "yes" : "no", IsFullNetworkData() ? "yes" : "no");
StringWriter(string).Append("rx-on:%s ftd:%s full-net:%s", IsRxOnWhenIdle() ? "yes" : "no",
IsFullThreadDevice() ? "yes" : "no", IsFullNetworkData() ? "yes" : "no");
return string;
} }
void MeshLocalPrefix::SetFromExtendedPanId(const Mac::ExtendedPanId &aExtendedPanId) void MeshLocalPrefix::SetFromExtendedPanId(const Mac::ExtendedPanId &aExtendedPanId)
+3 -2
View File
@@ -369,8 +369,9 @@ void RadioSelector::Log(otLogLevel aLogLevel,
{ {
if (aNeighbor.GetSupportedRadioTypes().Contains(radio)) if (aNeighbor.GetSupportedRadioTypes().Contains(radio))
{ {
IgnoreError(preferenceString.Append("%s%s:%d", isFirstEntry ? "" : " ", RadioTypeToString(radio), StringWriter(preferenceString)
aNeighbor.GetRadioPreference(radio))); .Append("%s%s:%d", isFirstEntry ? "" : " ", RadioTypeToString(radio),
aNeighbor.GetRadioPreference(radio));
isFirstEntry = false; isFirstEntry = false;
} }
} }
+1 -1
View File
@@ -195,7 +195,7 @@ void ChannelMonitor::LogResults(void)
for (uint16_t channel : mChannelOccupancy) for (uint16_t channel : mChannelOccupancy)
{ {
IgnoreError(logString.Append("%02x ", channel >> 8)); StringWriter(logString).Append("%02x ", channel >> 8);
} }
otLogInfoUtil("ChannelMonitor: %u [%s]", mSampleCount, logString.AsCString()); otLogInfoUtil("ChannelMonitor: %u [%s]", mSampleCount, logString.AsCString());
+46 -52
View File
@@ -43,76 +43,70 @@ enum
template <uint16_t kSize> void PrintString(const char *aName, const String<kSize> aString) template <uint16_t kSize> void PrintString(const char *aName, const String<kSize> aString)
{ {
printf("\t%s = [%d] \"%s\"\n", aName, aString.GetLength(), aString.AsCString()); printf("\t%s = [%zu] \"%s\"\n", aName, strlen(aString.AsCString()), aString.AsCString());
} }
void TestString(void) void TestStringWriter(void)
{ {
otError error; String<kStringSize> str;
String<kStringSize> str1; constexpr char kLongString[] = "abcdefghijklmnopqratuvwxyzabcdefghijklmnopqratuvwxyz";
String<kStringSize> str2("abc");
String<kStringSize> str3("%d", 12);
printf("\nTest 1: String constructor\n"); printf("\nTest 1: StringWriter constructor\n");
VerifyOrQuit(str1.GetSize() == kStringSize, "GetSize() failed"); VerifyOrQuit(StringWriter(str).GetSize() == kStringSize, "GetSize() failed");
VerifyOrQuit(StringWriter(str).GetLength() == 0, "GetLength() failed for empty string");
VerifyOrQuit(str1.GetLength() == 0, "GetLength() failed for empty string"); VerifyOrQuit(strcmp(str.AsCString(), "") == 0, "String content is incorrect");
VerifyOrQuit(str2.GetLength() == 3, "GetLength() failed");
VerifyOrQuit(str3.GetLength() == 2, "GetLength() failed");
VerifyOrQuit(strcmp(str1.AsCString(), "") == 0, "String content is incorrect"); PrintString("str", str);
VerifyOrQuit(strcmp(str2.AsCString(), "abc") == 0, "String content is incorrect");
VerifyOrQuit(strcmp(str3.AsCString(), "12") == 0, "String content is incorrect");
PrintString("str1", str1);
PrintString("str2", str2);
PrintString("str3", str3);
printf(" -- PASS\n"); printf(" -- PASS\n");
printf("\nTest 2: String::Set() and String::Clear() method\n"); printf("\nTest 2: String::Append() method\n");
error = str1.Set("Hello"); {
SuccessOrQuit(error, "String::Set() failed unexpectedly"); StringWriter writer(str);
VerifyOrQuit(str1.GetLength() == 5, "GetLength() failed for empty string");
VerifyOrQuit(strcmp(str1.AsCString(), "Hello") == 0, "String content is incorrect");
PrintString("str1", str1);
str1.Clear(); writer.Append("Hi");
VerifyOrQuit(str1.GetLength() == 0, "GetLength() failed for empty string"); VerifyOrQuit(writer.GetLength() == 2, "GetLength() failed");
VerifyOrQuit(strcmp(str1.AsCString(), "") == 0, "String content is incorrect"); VerifyOrQuit(strcmp(str.AsCString(), "Hi") == 0, "String content is incorrect");
PrintString("str", str);
IgnoreError(str1.Set("%d", 12)); writer.Append("%s%d", "!", 12);
VerifyOrQuit(str1.GetLength() == 2, "GetLength() failed"); VerifyOrQuit(writer.GetLength() == 5, "GetLength() failed");
VerifyOrQuit(strcmp(str1.AsCString(), "12") == 0, "String content is incorrect"); VerifyOrQuit(strcmp(str.AsCString(), "Hi!12") == 0, "String content is incorrect");
PrintString("str1", str1); PrintString("str", str);
error = str1.Set("abcdefghijklmnopqratuvwxyzabcdefghijklmnopqratuvwxyz"); writer.Append(kLongString);
VerifyOrQuit(error == OT_ERROR_NO_BUFS, "String::Set() did not handle overflow buffer correctly"); VerifyOrQuit(writer.IsTruncated() && writer.GetLength() == 5 + sizeof(kLongString) - 1,
PrintString("str1", str1); "String::Append() did not handle overflow buffer correctly");
PrintString("str", str);
}
printf("\nTest 3: String::Append() method\n"); printf("\nTest 3: String::Clear() method\n");
str2.Clear(); {
VerifyOrQuit(str2.GetLength() == 0, "GetLength() failed for empty string"); StringWriter writer(str);
VerifyOrQuit(strcmp(str2.AsCString(), "") == 0, "String content is incorrect");
error = str2.Append("Hi"); writer.Append("Hello");
SuccessOrQuit(error, "String::Append() failed unexpectedly"); VerifyOrQuit(writer.GetLength() == 5, "GetLength() failed for empty string");
VerifyOrQuit(str2.GetLength() == 2, "GetLength() failed"); VerifyOrQuit(strcmp(str.AsCString(), "Hello") == 0, "String content is incorrect");
VerifyOrQuit(strcmp(str2.AsCString(), "Hi") == 0, "String content is incorrect"); PrintString("str", str);
PrintString("str2", str2);
error = str2.Append("%s%d", "!", 12); writer.Clear();
SuccessOrQuit(error, "String::Append() failed unexpectedly"); VerifyOrQuit(writer.GetLength() == 0, "GetLength() failed for empty string");
VerifyOrQuit(str2.GetLength() == 5, "GetLength() failed"); VerifyOrQuit(strcmp(str.AsCString(), "") == 0, "String content is incorrect");
VerifyOrQuit(strcmp(str2.AsCString(), "Hi!12") == 0, "String content is incorrect");
PrintString("str2", str2);
error = str2.Append("abcdefghijklmnopqratuvwxyzabcdefghijklmnopqratuvwxyz"); writer.Append("%d", 12);
VerifyOrQuit(error == OT_ERROR_NO_BUFS, "String::Append() did not handle overflow buffer correctly"); VerifyOrQuit(writer.GetLength() == 2, "GetLength() failed");
PrintString("str2", str2); VerifyOrQuit(strcmp(str.AsCString(), "12") == 0, "String content is incorrect");
PrintString("str", str);
writer.Clear().Append(kLongString);
VerifyOrQuit(writer.IsTruncated() && writer.GetLength() == sizeof(kLongString) - 1,
"String::Clear() + String::Append() did not handle overflow buffer correctly");
PrintString("str", str);
}
printf(" -- PASS\n"); printf(" -- PASS\n");
} }
@@ -179,7 +173,7 @@ void TestStringFind(void)
int main(void) int main(void)
{ {
ot::TestString(); ot::TestStringWriter();
ot::TestStringLength(); ot::TestStringLength();
ot::TestUtf8(); ot::TestUtf8();
ot::TestStringFind(); ot::TestStringFind();