summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorMarkus Mittendrein <maxmitti@maxmitti.tk>2022-01-09 17:43:10 +0100
committerMarkus Mittendrein <maxmitti@maxmitti.tk>2022-01-09 17:43:10 +0100
commitf1ff922eafc6972dd6437d6e9908146fa92577fa (patch)
tree1a947b24944bc94f3fc88c13e713ff77ba366bec /include
parent3a79b82bac837e54da6f9e564a3272aa473388c4 (diff)
downloadcxxformat-f1ff922eafc6972dd6437d6e9908146fa92577fa.tar.gz
cxxformat-f1ff922eafc6972dd6437d6e9908146fa92577fa.zip
Improve exception message for out of range numbers in format strings
Diffstat (limited to 'include')
-rw-r--r--include/cxxformat/core.hpp32
-rw-r--r--include/cxxformat/runtime.hpp2
2 files changed, 22 insertions, 12 deletions
diff --git a/include/cxxformat/core.hpp b/include/cxxformat/core.hpp
index 6eec0ef..2a78b26 100644
--- a/include/cxxformat/core.hpp
+++ b/include/cxxformat/core.hpp
@@ -224,6 +224,16 @@ namespace format {
return {val, p};
}
+ template<std::unsigned_integral T = unsigned int>
+ constexpr std::pair<std::optional<T>, std::size_t> parseNumberWithMessage(std::string_view s, std::size_t pos, std::string_view numberName)
+ {
+ try {
+ return parseNumber<T>(s, pos);
+ } catch(const std::out_of_range&) {
+ throw std::out_of_range{std::string{numberName} + " is too big; maximum is " + std::to_string(std::numeric_limits<T>::max())};
+ }
+ }
+
namespace exceptions {
struct incomplete_specifier : std::invalid_argument {
using std::invalid_argument::invalid_argument;
@@ -263,7 +273,7 @@ namespace format {
};
bool hasExplicitArgIndex = false;
- const auto argIndex = parseNumber<ArgIndex>(fmt, pos);
+ const auto argIndex = parseNumberWithMessage<ArgIndex>(fmt, pos, "Argument index or field width");
if (argIndex.first)
{
checkEos(argIndex.second);
@@ -315,8 +325,8 @@ namespace format {
checkEos();
ArgIndex maxArg = 0;
- const auto argIndexOrNextArg = [&pos, &nextArg, &maxArg, checkEos, fmt](decltype(*format_specifier::minWidth)& argIndex) {
- const auto index = parseNumber<ArgIndex>(fmt, pos);
+ const auto argIndexOrNextArg = [&pos, &nextArg, &maxArg, checkEos, fmt](decltype(*format_specifier::minWidth)& argIndex, std::string_view numberName) {
+ const auto index = parseNumberWithMessage<ArgIndex>(fmt, pos, numberName);
checkEos(index.second);
if (index.first && fmt[index.second] == '$')
{
@@ -336,22 +346,22 @@ namespace format {
maxArg = std::max(maxArg, argIndex);
};
- const auto handleWidthPrecision = [&pos, argIndexOrNextArg, fmt, checkEos](decltype(format_specifier::minWidth)& indexOrValue, bool allowEmpty = false){
+ const auto handleWidthPrecision = [&pos, argIndexOrNextArg, fmt, checkEos](decltype(format_specifier::minWidth)& indexOrValue, std::string_view numberName, bool allowEmpty = false){
bool asArg = false;
if (fmt[pos] == '*')
{
asArg = true;
++pos;
checkEos();
- argIndexOrNextArg(indexOrValue.emplace());
+ argIndexOrNextArg(indexOrValue.emplace(), numberName);
}
else
{
- const auto width = parseNumber<ArgIndex>(fmt, pos);
- if (width.first)
+ const auto value = parseNumberWithMessage<ArgIndex>(fmt, pos, numberName);
+ if (value.first)
{
- indexOrValue = *width.first;
- pos = width.second;
+ indexOrValue = *value.first;
+ pos = value.second;
}
else if (allowEmpty)
{
@@ -360,14 +370,14 @@ namespace format {
}
return asArg;
};
- spec.flags.widthAsArg = handleWidthPrecision(spec.minWidth);
+ spec.flags.widthAsArg = handleWidthPrecision(spec.minWidth, "Field width");
if (fmt[pos] == '.')
{
++pos;
checkEos();
- spec.flags.precisionAsArg = handleWidthPrecision(spec.precision, true);
+ spec.flags.precisionAsArg = handleWidthPrecision(spec.precision, "Precision", true);
}
{
diff --git a/include/cxxformat/runtime.hpp b/include/cxxformat/runtime.hpp
index 85c6ecf..7659468 100644
--- a/include/cxxformat/runtime.hpp
+++ b/include/cxxformat/runtime.hpp
@@ -184,7 +184,7 @@ namespace format {
throw exceptions::incomplete_specifier{"Incomplete format specifier “%s” at end of format string"_format(fmt.substr(nextSpec))};
} catch(const std::exception& e) {
constexpr std::size_t showPartSize = 10;
- throw std::invalid_argument{"%s when parsing format specifier “%s%s” at column %u"_format(e.what(), fmt.substr(nextSpec, showPartSize), nextSpec + showPartSize > fmt.size() ? "" : "…", nextSpec)};
+ throw std::invalid_argument{"%s; when parsing format specifier “%s%s” at column %u"_format(e.what(), fmt.substr(nextSpec, showPartSize), nextSpec + showPartSize > fmt.size() ? "" : "…", nextSpec)};
}
}
}