From e1b7fe218ea67519c3372a24a66bbf8f2623b7ad Mon Sep 17 00:00:00 2001 From: Elias Kosunen Date: Sun, 3 Nov 2024 20:35:35 +0200 Subject: [PATCH] Report scan_error::invalid_source_state on failed sync --- .github/workflows/docs.yml | 2 +- CHANGELOG.md | 2 + src/scn/impl.cpp | 87 +++++++++++++++++++------------------- 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index f181eb75..6f8af364 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -45,7 +45,7 @@ jobs: run: | git fetch origin master:refs/remotes/origin/master --tags --force git remote set-head origin -a - git checkout ${{ github.ref_name }} + git checkout master git pull --force - name: Prepare repository (on workflow_dispatch) diff --git a/CHANGELOG.md b/CHANGELOG.md index 205cbcb1..7975fd1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,8 @@ return result; * Deprecate `visit_scan_arg`, add `basic_scan_arg::visit` * Remove thousands separator checking when scanning localized numbers + * `scan_error::invalid_source_state` is now returned if syncing with the underlying source fails after `scan` + (like for example, `std::ungetc` fails) ## 3.0.2 diff --git a/src/scn/impl.cpp b/src/scn/impl.cpp index 6a171c09..aa0d3343 100644 --- a/src/scn/impl.cpp +++ b/src/scn/impl.cpp @@ -1822,14 +1822,49 @@ scan_expected vinput(std::string_view format, scan_args args) auto buffer = detail::make_file_scan_buffer(stdin); auto n = vscan_internal(buffer, format, args); if (n) { - buffer.sync(*n); + if (SCN_UNLIKELY(!buffer.sync(*n))) { + return detail::unexpected_scan_error( + scan_error::invalid_source_state, + "Failed to sync with underlying FILE"); + } return {}; } - buffer.sync_all(); + if (SCN_UNLIKELY(!buffer.sync_all())) { + return detail::unexpected_scan_error( + scan_error::invalid_source_state, + "Failed to sync with underlying FILE"); + } return unexpected(n.error()); } namespace detail { + +namespace { + +template +scan_expected sync_after_vscan( + Source& source, + scan_expected result) +{ + if (SCN_LIKELY(result)) { + if (SCN_UNLIKELY(!source.sync(*result))) { + return detail::unexpected_scan_error( + scan_error::invalid_source_state, + "Failed to sync with underlying source"); + } + } + else { + if (SCN_UNLIKELY(!source.sync_all())) { + return detail::unexpected_scan_error( + scan_error::invalid_source_state, + "Failed to sync with underlying source"); + } + } + return result; +} + +} // namespace + scan_expected vscan_impl(std::string_view source, std::string_view format, scan_args args) @@ -1841,13 +1876,7 @@ scan_expected vscan_impl(scan_buffer& source, scan_args args) { auto n = vscan_internal(source, format, args); - if (SCN_LIKELY(n)) { - source.sync(*n); - } - else { - source.sync_all(); - } - return n; + return sync_after_vscan(source, n); } scan_expected vscan_impl(std::wstring_view source, @@ -1861,13 +1890,7 @@ scan_expected vscan_impl(wscan_buffer& source, wscan_args args) { auto n = vscan_internal(source, format, args); - if (SCN_LIKELY(n)) { - source.sync(*n); - } - else { - source.sync_all(); - } - return n; + return sync_after_vscan(source, n); } #if !SCN_DISABLE_LOCALE @@ -1886,13 +1909,7 @@ scan_expected vscan_localized_impl(const Locale& loc, scan_args args) { auto n = vscan_internal(source, format, args, detail::locale_ref{loc}); - if (SCN_LIKELY(n)) { - source.sync(*n); - } - else { - source.sync_all(); - } - return n; + return sync_after_vscan(source, n); } template @@ -1910,13 +1927,7 @@ scan_expected vscan_localized_impl(const Locale& loc, wscan_args args) { auto n = vscan_internal(source, format, args, detail::locale_ref{loc}); - if (SCN_LIKELY(n)) { - source.sync(*n); - } - else { - source.sync_all(); - } - return n; + return sync_after_vscan(source, n); } template auto vscan_localized_impl(const std::locale&, @@ -1950,13 +1961,7 @@ scan_expected vscan_value_impl(scan_buffer& source, basic_scan_arg arg) { auto n = vscan_value_internal(source, arg); - if (SCN_LIKELY(n)) { - source.sync(*n); - } - else { - source.sync_all(); - } - return n; + return sync_after_vscan(source, n); } scan_expected vscan_value_impl( @@ -1970,13 +1975,7 @@ scan_expected vscan_value_impl( basic_scan_arg arg) { auto n = vscan_value_internal(source, arg); - if (SCN_LIKELY(n)) { - source.sync(*n); - } - else { - source.sync_all(); - } - return n; + return sync_after_vscan(source, n); } #if !SCN_DISABLE_TYPE_SCHAR