0

I would like my program to read from stdin until EOF, print all input, and repeat. I tried clearing the EOF state of stdin as follows:

#include <string>
#include <iostream>
#include <iterator>

using namespace std;

int main() {

  cin >> noskipws;

  while (1) {

    printf("Begin");
    istream_iterator<char> iterator(cin);
    istream_iterator<char> end;
    string input(iterator, end);
    cout << input << endl;
    cin.clear();

  }

}

After the first input is received and printed, however, the program just infinitely prints "Begin" without waiting for further input.

Chiraag Mundhe
  • 374
  • 7
  • 15
  • 1
    How can you continue reading past EOF? Once there's no more data, *there's no more data.* – Jonathon Reinhart Nov 03 '13 at 05:04
  • @JonathonReinhart EOF doesn't necessarily mean that there will never be any more data, only that the end-of-file was reached. A terminal can keep providing input after the user enters the EOF escape, and a file can have more data written to it. – hobbs Nov 03 '13 at 05:10
  • 1
    @hobbs I understand that. I actually considered what you'd mentioned, but couldn't think of any standard UNIX-y program that continues trying to read after it gets EOF from stdin. If I press Ctrl+D, I expect it to finish. – Jonathon Reinhart Nov 03 '13 at 05:11
  • Ultimately I'd like to be able to run this program, enter some input that spans multiple lines, signal EOF with Ctrl-D, and have a transformation of my input printed to stdout. The program should then wait for more input followed by an EOF followed by printing to stdout, etc. – Chiraag Mundhe Nov 03 '13 at 05:13
  • 2
    @JonathonReinhart `tail -f` does it as a matter of course (although not usually on stdin). `perl -` reads a program from stdin until EOF, and then gives stdin to the program to read more data from. They're the only ones I can think of offhand. Anyway, it's certainly possible. – hobbs Nov 03 '13 at 05:18
  • @hobbs Thanks for the excellent examples. And Chiraag, thanks for the explanation. Perhaps that information be best included in the original question. – Jonathon Reinhart Nov 03 '13 at 05:19

2 Answers2

1

The approach you're taking there won't work - when 'cin' gives you end-of-file in the context you're using, then cin is closed.

For your stated purpose of "reading text until eof, then doing it again", sorry for missing the nuance of this previously, but if you clone the stdin file descriptor and then use the clone, you can continue reading from these additional file descriptors.

Cloning iostreams isn't easy. See How to construct a c++ fstream from a POSIX file descriptor?

It's a little c-like, but this code will drain one copy of stdin until that stdin closes, then it'll make a new copy and drain that, and on.

#include <iostream>
#include <string>

void getInput(std::string& input)
{
    char buffer[4096];
    int newIn = dup(STDIN_FILENO);
    int result = EAGAIN;
    input = "";
    do {
        buffer[0] = 0;
        result = read(newIn, buffer, sizeof(buffer));
        if (result > 0)
            input += buffer;
    } while (result >= sizeof(buffer));
    close(newIn);

    return input;
}

int main(int argc, const char* argv[])
{
    std::string input;
    for (;;) {
        getInput(input);
        if (input.empty())
            break;
        std::cout << "8x --- start --- x8\n" << input.c_str() << "\n8x --- end --- x8\n\n";
    }
}
Community
  • 1
  • 1
kfsone
  • 23,617
  • 2
  • 42
  • 74
0

That is because you have printf("begin"); inside your loop so you are going to get it printed again each time round the loop.

The loop will not wait for input so each time it reads data from stdin - if there is nothing there it immediately gets EOF and so continues looping until some data is present.

Let me know if this doesn't make sense - or if I got it totally wrong.

eg:

#include <string>
#include <iostream>
#include <iterator>

using namespace std;

int main() {

  cin >> noskipws;

  printf("Begin");

  while (1) {

    istream_iterator<char> iterator(cin);
    istream_iterator<char> end;
    string input(iterator, end);
    cout << input << endl;
    cin.clear();

  }

}
James Sefton
  • 133
  • 9
  • The first time this program is executed, the body of the loop waits for input. I'd like it to wait in each iteration. Moving the print statement outside of the loop does not really help. There is still the write to cout which prints an endless number of blank lines to console and clearly indicates that the loop is not waiting. – Chiraag Mundhe Nov 03 '13 at 05:07
  • if you are wanting to grab a line each time (like asking the user a question and they type an answer, then hit enter) then maybe using something like getline() might help you a bit. http://www.cplusplus.com/reference/string/string/getline/ – James Sefton Nov 03 '13 at 05:11
  • I'm expecting the input to span an arbitrary number of lines. – Chiraag Mundhe Nov 03 '13 at 05:17
  • This makes sense, but you got it totally wrong. Your solution still creates an endless loop. – David G Nov 03 '13 at 12:42