Skip to content

Instantly share code, notes, and snippets.

@mrkline
Created January 20, 2015 21:47
Show Gist options
  • Save mrkline/99630570e839a4af0e3b to your computer and use it in GitHub Desktop.
Save mrkline/99630570e839a4af0e3b to your computer and use it in GitHub Desktop.
// MSVC apparently doesn't have C's getline
// This is a poor man's implementation of it using fgets.
// See the man page at
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html
size_t getline(char** buf, size_t* bufLen, FILE* f)
{
if (buf == nullptr || bufLen == nullptr)
{
errno = EINVAL;
return -1;
}
if (fgets(*buf, *bufLen, f) != *buf)
return -1;
while (true)
{
const size_t amountRead = strlen(*buf);
// If the length of the string is less than the whole buffer
// (minus the last space for \0) or the last character is a newline,
// we win. Done.
if (amountRead != *bufLen - 1 || (*buf)[amountRead - 1] == '\n')
return amountRead;
// We didn't have enought room, expand with realloc.
// First make sure we can.
// If we can't take any more, give up.
if (*bufLen == SSIZE_MAX)
{
errno = EOVERFLOW;
return -1;
}
// If the MSB of bufLen is 1, doubling will overflow.
const bool willOverflow = (*bufLen >> (sizeof(size_t) * 8 - 1)) == 1;
const size_t newSize = willOverflow ? SSIZE_MAX : *bufLen * 2;
char* newBuf = static_cast<char*>(realloc(*buf, newSize));
if (newBuf == nullptr)
{
errno = ENOMEM;
return -1;
}
// We succeeded in expanding.
*buf = newBuf;
*bufLen = newSize;
// Keep reading where we left off
char* const resumePoint = *buf + amountRead;
if (fgets(resumePoint, *bufLen - amountRead, f) != resumePoint)
return -1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment