Question

I have a std::basic_streambuf subclass that causes all output to be written in uppercase, like this:

class upper_streambuf : public std::streambuf
{
    public:
        upper_streambuf(std::streambuf &real)
          : m_realBuffer(real)
        {
        }

    protected:
        virtual int overflow(int c)
        {
            int uc = std::toupper(c);
            m_realBuffer.sputc(uc);
            return uc;
        }

    private:
        std::streambuf &m_realBuffer;
};

I use it like this for example (which seems to work OK):

upper_streambuf buf(*std::cout.rdbuf());
std::ostream ucout(&buf);

ucout << "Hello, world!" << std::endl; // prints "HELLO, WORLD!"

What I want to achieve is the more-or-less the inverse, I want to read from a stream and have all input converted to lowercase. I have the following:

class lower_streambuf : public std::streambuf
{
    public:
        lower_streambuf(std::streambuf &real)
          : m_realBuffer(real)
        {
        }

    protected:
        virtual int underflow()
        {
            return std::tolower(m_realBuffer.sbumpc());
        }

    private:
        std::streambuf &m_realBuffer;
};

However, when I try and use this one like this:

lower_streambuf buf(*std::cin.rdbuf());
std::istream lcin(&buf);
std::string line;

std::getline(lcin, line);

The result is a segmentation fault. Am I overriding or calling the wrong functions? Please note I am somewhat of a novice in C++. Please also note that I understand I can read the input completely and simply convert it to lowercase once it has been read, but this is more for learning/academic purposes rather than anything practical.

Was it helpful?

Solution

underflow() has post-conditions that you failed to establish: by the time you return from it, you need to have a get area in your streambuf that holds that character you're returning.

A single-character buffer is sufficient:

    protected:
        virtual int underflow()
        {
            ch = std::tolower(m_realBuffer.sbumpc());
  +         setg(&ch, &ch, &ch+1); 
            return ch;
        }
    private:
  +     char ch; // input buffer!
        std::streambuf &m_realBuffer;
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top