NextLine


Description:
NextLine can be used to iterate through an entire file, reading in a line at a time. It uses a buffer to keep file reads to a minimum. The buffer can automatically grow if it needs to, so NextLine can handle lines of any size.

Call InitNextLine before calling NextLine, and once NextLine returns false, it's hit the end of file, and free'd any memory it's allocated.
 
Code:
// --- Header

void InitNextLine(HANDLE hFile, LPTSTR szLine, DWORD cbLine);
bool GetNextLine();

// --- Code
LPTSTR  g_szLine;
DWORD   g_cbLine;
HANDLE  g_hFile;

DWORD   g_nLenData;
DWORD   g_nMaxLen;
char*   g_szData;
char*   g_szData2;
char*   g_szCurPos;

void InitNextLine(HANDLE hFile, LPTSTR szLine, DWORD cbLine)
{
    g_hFile = hFile;
    g_cbLine = cbLine;
    g_szLine = szLine;

    g_nMaxLen = 2048;
 if (g_szData)
 {
  free(g_szData);
 }
 if (g_szData2)
 {
  free(g_szData2);
 }

    g_szData = (char *) malloc(2048);
    g_szData2 = (char *) malloc(2048);
    g_szCurPos = g_szData;

    DWORD dwRead;
    ReadFile(hFile, g_szData, 1024, &dwRead, NULL);
    g_nLenData = dwRead;
}

bool GetNextLine()
{

    do
    {
        char * szPos = g_szCurPos;
        int nLeft = g_nLenData;

  // Look for the newline character within our current buffer
        while (nLeft > 0)
        {
            if (*szPos == '\n')
            {
                // Found a newline, process the line

                *szPos = 0;
                if (*(szPos - 1) == '\r')
                {
     // Get rid of any CR since we get rid of the LF
                    *(szPos - 1) = 0;
                }

    // Write the output in our string
    #ifdef UNICODE
     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, g_szCurPos, (g_nLenData - nLeft + 1), 
      g_szLine, g_cbLine);
    #else
     _tcsncpy(g_szLine, g_szCurPos, (g_nLenData - nLeft + 1));
    #endif

                nLeft --;
                szPos ++;
                g_szCurPos = szPos;
                g_nLenData = nLeft;
                return true;
            }
            szPos ++;
            nLeft --;
        }
        
        // If we get here, there's no more LF's in the string

        if (g_nLenData + 1024 > g_nMaxLen)
        {
   // Whoops, we still have enough data in the buffer that we can't
   //  add BUFFER_SIZE to it, so increase it
            DWORD nNewSize = g_nMaxLen;
            while (g_nLenData + 1024 > nNewSize)
            {
                nNewSize += 1024;
            }

   // Need to keep track of the current position in the buffer
            int nOffset = g_szCurPos - g_szData;
            free(g_szData2);
            g_szData2 = (char*) malloc(nNewSize);
            memcpy(g_szData2,g_szData, g_nMaxLen);
            free(g_szData);
            g_szData = g_szData2;
            g_szData2 = (char*) malloc(nNewSize);

            g_szCurPos = g_szData + nOffset;
        }

  //Copy the remaining data to our backup buffer
        memcpy(g_szData2, g_szCurPos, g_nLenData);

  // Read in some more data
        DWORD dwRead = 0;
        DWORD nRet = ReadFile(g_hFile, g_szData2 + g_nLenData, 1024, &dwRead, NULL);
        if (!nRet || !dwRead)
        {
   // Either there's no more data, or a broken file
   free(g_szData);
   free(g_szData2);

   g_szData = NULL;
   g_szData2 = NULL;

            return false;
        }
        g_nLenData += dwRead;

  // Everything of interest is in the backup buffer, so switch buffers
        char * szTemp = g_szData;
        g_szData = g_szData2;
        g_szData2 = szTemp;
        g_szCurPos = g_szData;

  // And just loop around and work with the new data
    }
    while (true);

    return false;

}