The unix command wc
has this functionality:
$ wc - - -
aaa bbb ccc
0 3 11 -
aaa bbb ccc
0 3 11 -
aaa bbb ccc
0
With the patient help of Davis, I learned the difference between typed input finished with Ctrl+D and a here document which I was not aware of. (My tribute to Davis Herring.)
Once, I got it the rest in C++ was quite simple like shown in my MCVE.
line-count.cc
:
#include <fstream>
#include <iostream>
#include <string>
unsigned process(const std::string &fileName, std::istream &in)
{
unsigned nLines = 0;
if (in.bad()) {
std::cerr << "ERROR: Cannot open '" << fileName << "'!\n";
return 0;
}
for (std::string buffer; std::getline(in, buffer); ++nLines);
std::cout << "File: '" << fileName << "', " << nLines << " counted.\n";
return nLines;
}
int main(int argc, char **argv)
{
unsigned nLines = 0;
for (int i = 1; i < argc; ++i) {
const std::string arg = argv[i];
if (arg == "-") {
nLines += process(arg, std::cin);
std::cin.clear();
} else {
std::ifstream fIn(arg.c_str());
nLines += process(arg, fIn);
}
}
std::cout << "Total: " << nLines << " counted.\n";
return 0;
}
Compiled and tested in cygwin64:
$ g++ -std=c++11 -o line-count line-count.cc
$ ./line-count line-count.cc - line-count.cc -
File: 'line-count.cc', 32 counted.
1
2
3
File: '-', 3 counted.
File: 'line-count.cc', 32 counted.
1
2
3
File: '-', 3 counted.
Total: 70 counted.
$
So, it's indeed the trick with std::cin.clear() which resets the EOF flag in input stream and makes it possible to read again from the /dev/stdin
.
In the case of OP, the std::cin.ignore() after std::cin.clear()
is IMHO wrong. It discards the first character of the re-enabled standard input which makes the following processing wrong (by not counting the first character).
Davis (again) prodived a short but obvious explanation which I give in my words:
With CtrlD, the standard input receives an EOF in the next attempt to read; and memorizes it in its internal flags. Nevertheless, the flag can be reset. If there isn't any further input the next read attempt would fail but otherwise, the input can just be continued.
May be, it's worth to emphasize the internal EOF flag in std::ios
. Without std::cin.clear(), the read attempt would fail even when more input is available. As long as the internal std::stream
flags doesn't result in good state, no read attempt will be performed on lower level even though it might succeed.