243 lines
4.9 KiB
C++
243 lines
4.9 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// File: ccsv.cpp
|
|
//
|
|
// Module: CMPBK32.DLL
|
|
//
|
|
// Synopsis: Implementation of the class CCSVFile.
|
|
//
|
|
// Copyright (c) 1998 Microsoft Corporation
|
|
//
|
|
// Author: quintinb created header 08/17/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
// ############################################################################
|
|
// INCLUDES
|
|
#include "cmmaster.h"
|
|
|
|
// ############################################################################
|
|
// DEFINES
|
|
#define chComma ','
|
|
#define chNewline '\n'
|
|
#define chReturn '\r'
|
|
#define chSpace ' '
|
|
|
|
// ############################################################################
|
|
//
|
|
// CCSVFile - simple file i/o for CSV files
|
|
//
|
|
CCSVFile::CCSVFile()
|
|
{
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
m_chLastRead = 0;
|
|
m_pchLast = m_pchBuf = NULL;
|
|
m_fReadFail = FALSE;
|
|
m_fUseLastRead = FALSE;
|
|
}
|
|
|
|
// ############################################################################
|
|
CCSVFile::~CCSVFile()
|
|
{
|
|
CMASSERTMSG(m_hFile==INVALID_HANDLE_VALUE,"CCSV file is still open");
|
|
}
|
|
|
|
// ############################################################################
|
|
BOOLEAN CCSVFile::Open(LPCSTR pszFileName)
|
|
{
|
|
CMASSERTMSG(m_hFile==INVALID_HANDLE_VALUE, "a file is already open.");
|
|
|
|
m_hFile = CreateFile((LPCTSTR) pszFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
|
if (INVALID_HANDLE_VALUE == m_hFile)
|
|
{
|
|
return FALSE;
|
|
}
|
|
m_pchLast = m_pchBuf = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
// ############################################################################
|
|
BOOL CCSVFile::ClearNewLines(void)
|
|
{
|
|
//
|
|
// This routine is designed to eat characters until a non-newline char or
|
|
// the end-of-file is encountered. If a non-newline char is encountered,
|
|
// the fUseLast flag is set to ensure that the next call to ChNext will
|
|
// return the correct current character.
|
|
//
|
|
|
|
char ch = chNewline;
|
|
WORD wRet;
|
|
BYTE bErr;
|
|
|
|
//
|
|
// eat leading newlines
|
|
//
|
|
|
|
while (chNewline == ch)
|
|
{
|
|
//
|
|
// eat the leading space first
|
|
//
|
|
do
|
|
{
|
|
wRet = ChNext();
|
|
} while ((wRet == chSpace) || (wRet == TEXT('\t')));
|
|
|
|
bErr = HIBYTE(wRet);
|
|
ch = LOBYTE(wRet);
|
|
|
|
// if EOF return false
|
|
|
|
if (0xff == bErr)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// we hit a character other than newline, use current char as next.
|
|
//
|
|
|
|
m_fUseLastRead = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// ############################################################################
|
|
BOOLEAN CCSVFile::ReadToken(char *psz, DWORD cbMax)
|
|
{
|
|
char *pszOrig = psz;
|
|
DWORD dwLen = 0;
|
|
char ch;
|
|
BYTE bErr = 0xff;
|
|
WORD wRet;
|
|
|
|
wRet = ChNext();
|
|
bErr = HIBYTE(wRet);
|
|
ch = LOBYTE(wRet);
|
|
|
|
if (0xff == bErr)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// read chars until we hit a comma, newline, or run out of file
|
|
|
|
while (dwLen < cbMax - 1 && chComma != ch && chNewline != ch && 0xff != bErr)
|
|
{
|
|
*psz++ = ch;
|
|
|
|
wRet = ChNext(); //Read in the next character
|
|
bErr = HIBYTE(wRet);
|
|
ch = LOBYTE(wRet);
|
|
|
|
dwLen++;
|
|
}
|
|
|
|
*psz++ = '\0';
|
|
|
|
// eat leading spaces
|
|
|
|
while (*pszOrig == chSpace)
|
|
{
|
|
lstrcpy(pszOrig,pszOrig+1);
|
|
}
|
|
|
|
psz = pszOrig + lstrlen(pszOrig);
|
|
|
|
// eat trailing spaces
|
|
|
|
while ((psz != pszOrig) && (*(psz-1) == chSpace))
|
|
{
|
|
psz--;
|
|
*psz = 0;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// ############################################################################
|
|
void CCSVFile::Close(void)
|
|
{
|
|
if (m_hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(m_hFile);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (m_hFile==INVALID_HANDLE_VALUE)
|
|
{
|
|
CMTRACE("CCSVFile::Close was called, but m_hFile was already INVALID_HANDLE_VALUE\n");
|
|
}
|
|
|
|
#endif
|
|
|
|
m_hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
// ############################################################################
|
|
BOOL CCSVFile::ReadError(void)
|
|
{
|
|
return (m_fReadFail);
|
|
}
|
|
|
|
// ############################################################################
|
|
BOOL CCSVFile::FReadInBuffer(void)
|
|
{
|
|
//Read another buffer
|
|
if (!ReadFile(m_hFile, m_rgchBuf, CCSVFILE_BUFFER_SIZE, &m_cchAvail, NULL) || !m_cchAvail)
|
|
{
|
|
m_fReadFail = TRUE;
|
|
return FALSE; //nothing more to read
|
|
}
|
|
|
|
m_pchBuf = m_rgchBuf;
|
|
m_pchLast = m_pchBuf + m_cchAvail;
|
|
|
|
return TRUE; //success
|
|
}
|
|
|
|
// ############################################################################
|
|
inline WORD CCSVFile::ChNext(void)
|
|
{
|
|
//
|
|
// If the fUseLastRead flag is set, clear the
|
|
// flag and use the existing m_chLastRead
|
|
//
|
|
|
|
if (m_fUseLastRead)
|
|
{
|
|
m_fUseLastRead = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Get the next char in the buffer. Load new buffer if necessary.
|
|
//
|
|
|
|
LNextChar:
|
|
|
|
if (m_pchBuf >= m_pchLast && !FReadInBuffer()) //implies that we finished reading the buffer. Read in some more.
|
|
{
|
|
return MAKEWORD(0, 0xff); //nothing more to read
|
|
}
|
|
|
|
m_chLastRead = *m_pchBuf++;
|
|
|
|
//
|
|
// If its a carriage return, read another char
|
|
//
|
|
|
|
if (chReturn == m_chLastRead)
|
|
{
|
|
goto LNextChar; //faster to NOT make extra function call
|
|
}
|
|
}
|
|
|
|
return MAKEWORD(m_chLastRead, 0);
|
|
}
|
|
|
|
|