2

I'm trying to convert a program (it's a bridge between vscode and a debug) This program is written in C#.

It was based on the o vscode-mono-debug

(https://github.com/Microsoft/vscode-mono-debug/blob/master/src/Protocol.cs)

Well, In C # I can read the standard input as a stream:

 byte[] buffer = new byte[BUFFER_SIZE];
Stream inputStream = Console.OpenStandardInput();
    _rawData = new ByteBuffer();

        while (!_stopRequested) {
            var read = await inputStream.ReadAsync(buffer, 0, buffer.Length);

            if (read == 0) {
                // end of stream
                break;
            }

            if (read > 0) {
                _rawData.Append(buffer, read);
                ProcessData();
            }
        }

I try this :

#define _WIN32_WINNT 0x05017
#define BUFFER_SIZE 4096
#include<iostream>
#include<thread>
#include <sstream>

using namespace std;
class ProtocolServer
{

    private:
        bool _stopRequested;
        ostringstream _rawData;
    public:
        void Start()
        {

            char buffer[BUFFER_SIZE];

            while (!cin.eof())
            {

                cin.getline(buffer,BUFFER_SIZE);

                if (cin.fail())
                {
                    //error
                    break;
                }
                else
                {
                    _rawData << buffer;
                }

            }
        }

};

int main()
{
    ProtocolServer *server = new ProtocolServer();
    server->Start();
    return 0;

}

Input:

Content-Length: 261\r\n\r\n{\"command\":\"initialize\",\"arguments\":{\"clientID\":\"vscode\",\"adapterID\":\"advpl\",\"pathFormat\":\"path\",\"linesStartAt1\":true,\"columnsStartAt1\":true,\"supportsVariableType\":true,\"supportsVariablePaging\":true,\"supportsRunInTerminalRequest\":true},\"type\":\"request\",\"seq\":1}

This reads the first 2 lines correctly. Since the protocol does not put \n at the end, it gets stuck in cin.getline in the 3 interaction.

Switching to read() causes it to stay stopped at cin.read (), and does not read anything at all.

I found some similar questions: StackOverFlow Question

And examples: Posix_chat_client

But I do not need it to be necessarily asynchronous, but it works on windows and linux.

I'm sorry for my English

Thanks!

Community
  • 1
  • 1
KillerAll
  • 315
  • 1
  • 8
  • 1
    _I tried doing with boost asio and istream.read , but I did not have much success with both._ And.. Why didn't you have any success? maybe there was something wrong your attempt? Please provide [mcve] on what you tried, and an explanation of _why_ the functionality you get doesn't match your expectations. – Algirdas Preidžius Apr 14 '17 at 20:39
  • 1
    I'm no C# guru, but if I'm not mistaken `await` blocks until the async action is complete. You should be able to use `std::cin.read(buffer, sizeof(buffer));`, assuming buffer is a statically allocated array. – user4581301 Apr 14 '17 at 21:11
  • @user4581301, I try use cin.read, but stuck in this line. – KillerAll Apr 15 '17 at 01:57
  • Now that I see what you want, `cin` is either too stupid or too smart, depending on how you look at it, to do what you want. It will always go looking for that next byte, next delimiter or whatever you send it for. My appologies for sending you down a bad path. I think you're going to have to go OS specific (CreateFile, ReadConsoleInput, and WaitSingleObject with a short timeout) or use Boost asio, neither of which I've ever used for this, but professor Google may have a few useful hints. – user4581301 Apr 15 '17 at 06:05
  • For example this: http://stackoverflow.com/a/19964096/4581301 Looks like I'm about half wrong – user4581301 Apr 15 '17 at 06:07
  • @user4581301 Not really, it's just that its interface is surprisingly unintuitive for non-conventional tasks. [Yes, that's bad.] See my answer though – sehe Apr 17 '17 at 14:59

1 Answers1

4

What you want is known as unformatted input operations.

Here's a 1:1 translation using just std::iostream. The only "trick" is using and honouring gcount():

std::vector<char> buffer(BUFFER_SIZE);
auto& inputStream = std::cin;
_rawData = std::string {}; // or _rawData.clear(), e.g.

while (!_stopRequested) {
    inputStream.read(buffer.data(), buffer.size());
    auto read = inputStream.gcount();

    if (read == 0) {
        // end of stream
        break;
    }

    if (read > 0) {
        _rawData.append(buffer.begin(), buffer.begin() + read);
        ProcessData();
    }
}

I'd personally suggest dropping that read == 0 check in favour of the more accurate:

if (inputStream.eof()) { break; }   // end of stream
if (!inputStream.good()) { break; } // failure

Note that !good() also catches eof(), so you can

if (!inputStream.good()) { break; } // failure or end of stream

Live Demo

Live On Coliru

#include <iostream>
#include <vector>
#include <atomic>

struct Foo {

    void bar() {
        std::vector<char> buffer(BUFFER_SIZE);
        auto& inputStream = std::cin;
        _rawData = std::string {};

        while (!_stopRequested) {
            inputStream.read(buffer.data(), buffer.size());
            auto read = inputStream.gcount();

            if (read > 0) {
                _rawData.append(buffer.begin(), buffer.begin() + read);
                ProcessData();
            }

            if (!inputStream.good()) { break; } // failure or end of stream
        }
    }
  protected:
    void ProcessData() {
        //std::cout << "got " << _rawData.size() << " bytes: \n-----\n" << _rawData << "\n-----\n";
        std::cout << "got " << _rawData.size() << " bytes\n";
        _rawData.clear();
    }

    static constexpr size_t BUFFER_SIZE = 128;
    std::atomic_bool _stopRequested { false };
    std::string _rawData;
};

int main() {
    Foo foo;
    foo.bar();
}

Prints (e.g. when reading its own source file):

got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 92 bytes
sehe
  • 374,641
  • 47
  • 450
  • 633
  • I'd considered this when I was putting an answer together. It's what I do to read a file of unknown size to dump it into a socket or some other output where I don't care about the size. I got hung up on not closing `cin`, which on third thought doesn't look like a requirement. – user4581301 Apr 17 '17 at 15:13
  • @user4581301 Yeah I see no `dispose` or `using(inputStream)`. Anyways, this being stdin probably means it would only close the stream instance. Anyways, `inputStream.close()` is not that hard to spell either :) – sehe Apr 17 '17 at 15:16
  • Classic example of I should have asked OP instead of assuming. Pity that you can't count on `istream::readsome`'s behaviour cross platform because you'd think that would be exactly what to use. – user4581301 Apr 17 '17 at 15:27
  • @user4581301 Precisely :) – sehe Apr 17 '17 at 15:27
  • 1
    @sehe That's exactly what I needed. I tested it on Windows and it worked perfectly, I will test in linux soon. Thank you so much. – KillerAll Apr 17 '17 at 20:24