#include "TextFile.h" TextFile::TextFile(const char* fileName) : maxLineLen(2048) { lineBuf = new char[maxLineLen+1]; parseBuf = new char[maxLineLen+1]; status = (lineBuf!=0 && parseBuf!=0); inFile = 0; open(fileName); } TextFile::~TextFile() { close(); if (lineBuf != 0) delete[] lineBuf; if (parseBuf != 0) delete[] parseBuf; } bool TextFile::open(const char* fileName) { close(); // always re-open lineBuf[maxLineLen] = 0; lineLen = 0; lineNum = 0; inBuffer = (moreInBuffer = 0); nextLine = 0; if (fileName == 0) return false; // Create input file stream. // Make it binary because of compatibility to text files from any // known operating system. #if defined(HAVE_IOS_BIN) inFile = new ifstream(fileName,ios::in|ios::bin); #else inFile = new ifstream(fileName,ios::in|ios::binary); #endif #if defined(HAVE_SEEKG_OFFSET) leftToLoad = (inFileLen = (inFile->seekg(0,ios::end)).offset()); #else inFile->seekg(0,ios::end); leftToLoad = (inFileLen = (unsigned long)inFile->tellg()); #endif inFile->seekg(0,ios::beg); #if defined(DONT_HAVE_IS_OPEN) isGood = (inFile && inFile!=0 && !inFile->bad()); #else isGood = (inFile->is_open() && inFile!=0 && !inFile->bad()); #endif return isGood; } void TextFile::close() { if (inFile != 0) { inFile->close(); delete inFile; inFile = 0; isGood = false; } } const char* TextFile::getLineBuf() const { return lineBuf; } const unsigned long TextFile::getLineNum() const { return lineNum; } int TextFile::getLineLen() const { return lineLen; } bool TextFile::endOfFile() const { return ((leftToLoad==0)&&(moreInBuffer==0)); } bool TextFile::readNextLine() { // Next line (or just part of ...) also buffered. if ((nextLine != 0) && (moreInBuffer != 0)) { // Now move the next line to the beginning of the buffer. for (int i = 0; i < (maxLineLen-(int)(nextLine-lineBuf)); i++ ) { lineBuf[i] = nextLine[i]; } inBuffer = moreInBuffer; loadFromDisk(lineBuf+moreInBuffer,maxLineLen-moreInBuffer); zeroDelimiters(); lineNum++; haveParseCopy = false; return true; } // Nothing left in buffer. Fill the buffer by loading from disk. else { inBuffer = (moreInBuffer = 0); if (!loadFromDisk(lineBuf,maxLineLen)) { // No next line. Reset everything. lineLen = 0; lineBuf[0] = 0; nextLine = 0; lineNum = 0; haveParseCopy = false; return false; } else { zeroDelimiters(); lineNum++; haveParseCopy = false; return true; } } } bool TextFile::loadFromDisk(char* buf, const unsigned int maxLen) { if (status && isGood) // input file stream object status? { if (maxLen <= leftToLoad) { inFile->read(buf,maxLen); inBuffer += maxLen; leftToLoad -= maxLen; } else if (leftToLoad > 0) { inFile->read(buf,leftToLoad); inBuffer += leftToLoad; leftToLoad = 0; } else // leftToLoad == 0 { return false; } return true; } else // ifstream object not created; cannot load from disk { return false; } } // Search input line buffer for next newline sequence. Replace newline // sequence by a string-terminating zero. Skip it and save start of next // line if available. bool TextFile::zeroDelimiters() { // Unix: LF = 0x0A // MS-Windows, MS-DOS: CR,LF = 0x0D,0x0A // MacOS: CR = 0x0D bool foundEOL = false; // assume we do not find a delimiter char c; char* pCurPos = lineBuf; char* pDelimiter; for (int n = 0; n < inBuffer; n++) { c = *pCurPos; pDelimiter = pCurPos; pCurPos++; // skip read character if (c == 0x0A) { *pDelimiter = 0; // zero overstrike lineLen = pDelimiter - lineBuf; nextLine = pCurPos; // In case we read more than one line. Calc the remainder. moreInBuffer = (int) ((lineBuf+inBuffer)-pCurPos); foundEOL = true; break; // LF found } else if (c == 0x0D) { *pDelimiter = 0; // zero overstrike lineLen = pDelimiter - lineBuf; nextLine = pCurPos; if (*pCurPos == 0x0A) { *pCurPos = 0; // zero overstrike pCurPos++; // CR,LF found, skip LF nextLine = pCurPos; } // In case we read more than one line. Calc the remainder. moreInBuffer = (int) ((lineBuf+inBuffer)-pCurPos); foundEOL = true; break; // CR or CR,LF found } } // Here we decide to accept some unterminated characters at the end of a // file as a valid line (the last one). if ( !foundEOL && (inBuffer != 0)) { lineBuf[inBuffer] = 0; // terminate lineLen = inBuffer; moreInBuffer = 0; nextLine = 0; } return foundEOL; } bool TextFile::isComment() { if ( !haveParseCopy ) { createParseCopy(); } return ((parseBuf[0]==';')||(parseBuf[0]=='#')); } bool TextFile::isBlank() { if ( !haveParseCopy ) { createParseCopy(); } return (parseBuf[0]==0); } bool TextFile::isKey(const char *keyword, bool advance) { if ( !haveParseCopy ) { createParseCopy(); } bool matches = (strnicmp(curParseBuf,keyword,strlen(keyword))==0); if (matches && advance) { curParseBuf += strlen(keyword); if (curParseBuf > (parseBuf+maxLineLen)) { curParseBuf = parseBuf+maxLineLen; } } return matches; } bool TextFile::createParseCopy() { int di = 0; for ( int i = 0; i < lineLen; i++ ) { char c = lineBuf[i]; parseBuf[di] = c; if ( !isspace(c) ) { di++; } } parseBuf[di] = 0; curParseBuf = parseBuf; return (haveParseCopy=true); } const char* TextFile::getParseBuf() { if ( !haveParseCopy ) { createParseCopy(); } return parseBuf; } const char* TextFile::getCurParseBuf() { if ( !haveParseCopy ) { createParseCopy(); } return curParseBuf; }