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:
committed by
Kacper Donat
parent
b4325de672
commit
07e94dfaae
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user