Part: Eliminate use of sscanf

Replace with safer modern C++ `std::from_chars` (plus some additional
validation for expected inputs). Includes unit tests for new function.
This commit is contained in:
Chris Hennes
2026-02-15 21:01:53 -06:00
committed by Kacper Donat
parent b4325de672
commit 07e94dfaae
5 changed files with 51 additions and 5 deletions
+18
View File
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
#include "ElementNamingUtils.h"
#include <charconv>
#include <boost/algorithm/string/predicate.hpp>
@@ -123,3 +124,20 @@ const std::string Data::indexSuffix(int index, const char* label)
name += std::to_string(index);
return name;
}
int Data::indexOfElement(std::string_view s, std::string_view prefix)
{
int idx = 0;
if (prefix.empty()) {
return idx;
}
if (s.starts_with(prefix)) {
auto num = s.substr(prefix.size());
auto [ptr, ec] = std::from_chars(num.data(), num.data() + num.size(), idx);
if (ec != std::errc{} || ptr != num.data() + num.size()) {
return 0;
}
}
return idx;
}
+4
View File
@@ -3,6 +3,7 @@
#pragma once
#include <string>
#include <string_view>
#include <utility>
#include "FCGlobal.h"
@@ -119,5 +120,8 @@ AppExport const char *hasMappedElementName(const char *subname);
AppExport const std::string indexSuffix(int index, const char *label=ELEMENT_MAP_INDEX);
/// Given a string and a prefix, return the integer index that follows that prefix, or 0 if not found
AppExport int indexOfElement(std::string_view s, std::string_view prefix);
} // namespace Data
// clang-format on
+2 -3
View File
@@ -1987,9 +1987,8 @@ void FilletBase::onUpdateElementReference(const App::Property* prop)
FC_WARN("fillet edge count mismatch in object " << getFullName());
break;
}
int idx = 0;
sscanf(subs[i].c_str(), "Edge%d", &idx);
if (idx) {
int idx = Data::indexOfElement(subs[i], "Edge");
if (idx != 0) {
values[i].edgeid = idx;
}
else {
+2 -2
View File
@@ -48,6 +48,7 @@
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObject.h>
#include <App/ElementNamingUtils.h>
#include <Base/UnitsApi.h>
#include <Base/Tools.h>
#include <Gui/Application.h>
@@ -674,8 +675,7 @@ void DlgFilletEdges::setupFillet(const std::vector<App::DocumentObject*>& objs)
for (size_t i = 0; i < e.size(); ++i) {
auto& sub = subs[i];
if (sub.newName.empty()) {
int idx = 0;
sscanf(sub.oldName.c_str(), "Edge%d", &idx);
int idx = Data::indexOfElement(sub.oldName, "Edge");
if (idx == 0) {
FC_WARN("missing element reference: " << sub.oldName);
}
+25
View File
@@ -59,4 +59,29 @@ TEST_F(ElementNamingUtilsTest, findElementName)
EXPECT_STREQ(name3, "Edge3");
EXPECT_STREQ(name4, "Edge4");
}
TEST_F(ElementNamingUtilsTest, indexOfElement)
{
// Valid cases
EXPECT_EQ(Data::indexOfElement("Edge1", "Edge"), 1);
EXPECT_EQ(Data::indexOfElement("Edge12", "Edge"), 12);
EXPECT_EQ(Data::indexOfElement("Edge999", "Edge"), 999);
// Prefix mismatch
EXPECT_EQ(Data::indexOfElement("Node5", "Edge"), 0);
// Missing numeric suffix
EXPECT_EQ(Data::indexOfElement("Edge", "Edge"), 0);
// Non-numeric suffix
EXPECT_EQ(Data::indexOfElement("EdgeX", "Edge"), 0);
EXPECT_EQ(Data::indexOfElement("Edge12X", "Edge"), 0);
// Zero or invalid index
EXPECT_EQ(Data::indexOfElement("Edge0", "Edge"), 0);
// Degenerate inputs
EXPECT_EQ(Data::indexOfElement("", "Edge"), 0);
EXPECT_EQ(Data::indexOfElement("123", ""), 0);
}
// NOLINTEND(readability-magic-numbers)