Search code examples
c++csocketstelnetncurses

Turn stream into function argument to use Telnet and Ncurses


Hello fellow programmers.

I'm developing a C/C++ program with sockets that are supposed to connect to the server via Telnet.

To send text and ANSI codes to the Telnet remote terminal I'm using this funcion:

void writeline(int socketfd, string line)
{
  string tosend = line + "\n";
  write(socketfd, tosend.c_str(), tosend.length());
}

Is there a way to create a stream object like cout, cerr, clog or even a FILE (from C) that sends everything it gets to a function?

For example:

clientout << "Hello World";

would call something like this:

writeline(clientout.str()); //or alike

I did something like this last year when I programmed a microprocessor (with AVR) and redirected stdout into a function that sent everything to the USART connection. I was hoping I could do something like that now.

This is how I did it then:

static int usart_putchar(char c, FILE *stream)
{
    while ( !(UCSR0A & (1<<UDRE0)) );
    UDR0 = c;
    return 0;
}

static FILE usart_stream = FDEV_SETUP_STREAM(usart_putchar, NULL, _FDEV_SETUP_WRITE);

int main()
{
   //(...)
   stdout = &usart_stream;
   //(...)
}

I'm interested in this because, besides being an easier way to print into the remote terminal, I need a stream for even thinking about using ncurses with my program. To use it, I need this function which needs a stream for input and another for output.

I apologize for the long question. Thank you in advance.


Solution

  • Yes, it's possible to do this, but it's quite a bit of work.

    Basically, you have to implement a subclass of std::streambuf that implements std::streambuf's virtual methods to read and write from the socket directly, or call the wrapper functions you showed in your question. It's not really a lot of work, it's only a handful of virtual methods, but you have to understand their obscure semantics, and implement them correctly, 100%. No margin for error.

    Once you have your std::streambuf subclass, you can then instantiate a std::istream, std::ostream, and/or std::iostream (which have a constructor that takes a pointer to a std::streambuf).

    Now, you have your stream that reads and/or writes to the socket.