aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbutl/char-scanner.cxx6
-rw-r--r--libbutl/char-scanner.ixx23
-rw-r--r--libbutl/char-scanner.mxx40
3 files changed, 61 insertions, 8 deletions
diff --git a/libbutl/char-scanner.cxx b/libbutl/char-scanner.cxx
index 2e680b6..607d887 100644
--- a/libbutl/char-scanner.cxx
+++ b/libbutl/char-scanner.cxx
@@ -35,8 +35,10 @@ using namespace std;
namespace butl
{
char_scanner::
- char_scanner (istream& is, bool crlf)
- : is_ (is),
+ char_scanner (istream& is, bool crlf, uint64_t l)
+ : line (l),
+ column (1),
+ is_ (is),
buf_ (dynamic_cast<fdbuf*> (is.rdbuf ())),
gptr_ (nullptr),
egptr_ (nullptr),
diff --git a/libbutl/char-scanner.ixx b/libbutl/char-scanner.ixx
index 0e00dfd..c32b034 100644
--- a/libbutl/char-scanner.ixx
+++ b/libbutl/char-scanner.ixx
@@ -52,12 +52,31 @@ namespace butl
inline void char_scanner::
get_ ()
{
+ int_type c;
+
if (gptr_ != egptr_)
{
buf_->gbump (1);
- ++gptr_;
+ c = *gptr_++;
}
else
- is_.get (); // About as fast as ignore() and way faster than tellg().
+ c = is_.get (); // About as fast as ignore() and way faster than tellg().
+
+ if (save_ != nullptr && c != xchar::traits_type::eof ())
+ save_->push_back (static_cast<char_type> (c));
+ }
+
+ inline void char_scanner::
+ save_start (std::string& b)
+ {
+ assert (save_ == nullptr);
+ save_ = &b;
+ }
+
+ inline void char_scanner::
+ save_stop ()
+ {
+ assert (save_ != nullptr);
+ save_ = nullptr;
}
}
diff --git a/libbutl/char-scanner.mxx b/libbutl/char-scanner.mxx
index af4dad9..9bfdeec 100644
--- a/libbutl/char-scanner.mxx
+++ b/libbutl/char-scanner.mxx
@@ -6,7 +6,7 @@
#pragma once
#endif
-// C includes.
+#include <cassert>
#ifndef __cpp_lib_modules
#include <string> // char_traits
@@ -45,7 +45,10 @@ LIBBUTL_MODEXPORT namespace butl
// a number of optimizations that assume nobody else is messing with the
// stream.
//
- char_scanner (std::istream& is, bool crlf = true);
+ // The line argument can be used to override the start line in the stream
+ // (useful when re-scanning data saved with the save_* facility).
+ //
+ char_scanner (std::istream& is, bool crlf = true, std::uint64_t line = 1);
char_scanner (const char_scanner&) = delete;
char_scanner& operator= (const char_scanner&) = delete;
@@ -107,8 +110,32 @@ LIBBUTL_MODEXPORT namespace butl
// Line and column of the next character to be extracted from the stream
// by peek() or get().
//
- std::uint64_t line = 1;
- std::uint64_t column = 1;
+ std::uint64_t line;
+ std::uint64_t column;
+
+ // Ability to save raw data as it is being scanned. Note that the
+ // character is only saved when it is got, not peeked.
+ //
+ public:
+ void
+ save_start (std::string&);
+
+ void
+ save_stop ();
+
+ struct save_guard
+ {
+ explicit
+ save_guard (char_scanner& s, std::string& b): s_ (&s) {s.save_start (b);}
+
+ void
+ stop () {if (s_ != nullptr) {s_->save_stop (); s_ = nullptr;}}
+
+ ~save_guard () {stop ();}
+
+ private:
+ char_scanner* s_;
+ };
protected:
using int_type = xchar::int_type;
@@ -123,10 +150,15 @@ LIBBUTL_MODEXPORT namespace butl
protected:
std::istream& is_;
+ // Note that if you are reading from the buffer directly, then it is
+ // also your responsibility to save the data.
+ //
fdbuf* buf_; // NULL if not ifdstream.
const char_type* gptr_;
const char_type* egptr_;
+ std::string* save_ = nullptr;
+
bool crlf_;
bool eos_ = false;