A while back, I had to write code ready to deal deal with text files coming from either Windows or Linux so I wrote my own version of getline that was ready for either. This has worked for me
template<class CT, class TT, class AT>
inline
std::basic_istream<CT, TT>& getline(
std::basic_istream<CT, TT>& instr,
std::basic_string<CT, TT, AT>& str)
{
using is_type = std::basic_istream<CT, TT>;
using sentry_type = typename is_type::sentry;
std::ios_base::iostate state = std::ios_base::goodbit;
auto changed = false;
const sentry_type sentry(instr, true);
if (sentry)
{
// State okay, extract characters
try
{
auto sb = instr.rdbuf();
str.erase();
const auto delimNL = TT::to_int_type('\n');
const auto delimCR = TT::to_int_type('\r');
auto ch = sb->sgetc();
for (; ; ch = sb->snextc())
{
if (TT::eq_int_type(TT::eof(), ch))
{
// End of file, quit
state |= std::ios::eofbit;
break;
}
else if (TT::eq_int_type(ch, delimNL))
{
// Got a newline, discard it and quit.
changed = true; // We did read something successfully
sb->sbumpc(); // Discard this character
break; // Quit
}
else if (TT::eq_int_type(ch, delimCR))
{
// Got a carriage return.
changed = true; // We did read something successfully
sb->sbumpc(); // Discard this character
// Next character might be a newline. If so, do the
// same for that
if (TT::eq_int_type(sb->sgetc(), delimNL))
sb->sbumpc();
break; // We are done
}
else if(str.max_size() <= str.size())
{
// String too large, quit
state |= std::ios_base::failbit;
break;
}
else
{
// Got a character, add it to string
str += TT::to_char_type(ch);
changed = true;
}
}
}
catch(...)
{
// Some exception. Set badbit and rethrow
instr.setstate(std::ios_base::badbit);
throw;
}
}
}