blob: 24a083d1863d8cea9f419fb76af6b714ca90f16f [file]
// Copyright 2026 The Pigweed Authors
//
// 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
//
// https://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 "pw_tokenizer_private/printf_support.h"
#include <algorithm>
#include <cstdio>
#include <string>
#include <string_view>
#include "pw_tokenizer/detokenize.h"
namespace pw::tokenizer::test {
namespace {
const bool kSupportsC99Printf = [] {
char buf[16] = {};
std::snprintf(buf, sizeof(buf), "%zu", sizeof(char));
return buf[0] == '1' && buf[1] == '\0';
}();
const bool kSupportsFloatPrintf = [] {
char buf[16] = {};
std::snprintf(buf, sizeof(buf), "%.1f", 3.5f);
return buf[0] == '3' && buf[1] == '.' && buf[2] == '5' && buf[3] == '\0';
}();
bool FormatIsSupported(std::string_view format_view) {
if constexpr (sizeof(void*) == 8) {
return true; // Assume 64-bit machines support all format strings
}
pw::tokenizer::FormatString format_string(std::string(format_view).c_str());
for (const auto& segment : format_string.segments()) {
if (segment.type() == pw::tokenizer::StringSegment::kLiteral ||
segment.type() == pw::tokenizer::StringSegment::kPercent) {
continue;
}
if (!kSupportsC99Printf) {
std::string_view text = segment.text();
for (const char* modifier : {"hh", "ll", "j", "z", "t"}) {
if (text.find(modifier) != std::string_view::npos) {
return false;
}
}
}
if (!kSupportsFloatPrintf &&
segment.type() == pw::tokenizer::StringSegment::kFloatingPoint) {
return false;
}
}
return true;
}
} // namespace
bool FormatIsSupported(const pw::tokenizer::Detokenizer& detok,
std::string_view data) {
uint32_t token = 0;
for (size_t i = 0; i < std::min(data.size(), sizeof(token)); ++i) {
token |= static_cast<uint32_t>(static_cast<unsigned char>(data[i]))
<< (i * 8);
}
const auto entries =
detok.DatabaseLookup(token, pw::tokenizer::kDefaultDomain);
if (entries.empty()) {
return true;
}
return FormatIsSupported(entries[0].first.text());
}
} // namespace pw::tokenizer::test