/* * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Initial Developer of this code is David Baum. * Portions created by David Baum are Copyright (C) 1999 David Baum. * All Rights Reserved. * * Portions created by John Hansen are Copyright (C) 2005 John Hansen. * All Rights Reserved. * */ #include #include #include "Buffer.h" using std::fopen; using std::memcpy; using std::strlen; #ifdef DEBUG using std::strcpy; #endif #define CR 0x0d #define LF 0x0a #define kDefaultBufferSize 10 Buffer::Buffer() : fName(0), fData(0), fLength(0) { } Buffer::~Buffer() { delete [] fName; delete [] fData; } bool Buffer::Create(const char *name, const char *pathname) { FILE *fp = fopen(pathname, "rb"); if (!fp) return false; Create(name, fp); fclose(fp); return true; } void Buffer::Create(const char *name, FILE *fp) { // figure out length if (fseek(fp,0,SEEK_END)==0) { // if stream supports seeking, then we can determine total size, // allcoate enough storage, and read the entire thing at once fLength = ftell(fp); fseek(fp, 0, SEEK_SET); // allow room for terminating NL int allocate = fLength + 1; fData = new char[allocate]; fread(fData, 1, fLength, fp); } else { // This code is for io streams (such as redirected stdin under MPW) // which don't support seeking. The data from the stream is read into // a dynamically growing array. This is a lot less efficient than // the previous case which knew the total lenght beforehand. int max = kDefaultBufferSize; fData = new char[max]; fLength = 0; int c; while((c=getc(fp)) != EOF) { fData[fLength++] = (char)c; if (fLength == max) { // grow buffer - this needs to be done even on the last // char in the file since a terminating NL will be added // later on max *= 2; char *newBuf = new char[max]; memcpy(newBuf, fData, fLength); delete [] fData; fData = newBuf; } } } FinishCreate(name); } void Buffer::Create(const char *name, const char *data, int length) { // allcoate memory (allow for trailing NL) fData = new char[length + 1]; fLength = length; memcpy(fData, data, length); FinishCreate(name); } void Buffer::FinishCreate(const char *name) { fName = new char[strlen(name) + 1]; strcpy(fName, name); ConvertLineEndings(); // do this after ConvertLineEndings() since mac files might // end with CR and \n is an LF, so CRLF would get reduced if // \n was added before conversion fData[fLength++] = '\n'; } const char *Buffer::GetLine(int line) const { if (line < 1) return 0; const char *ptr = fData; const char *end = fData + fLength; --line; while(line) { if (ptr == end) return 0; if (*ptr++ == '\n') --line; } return ptr; } /* * int Buffer::FindLine(int &offset) const * * return the line number given an offset. Also adjust the offset * to the start of the line. */ int Buffer::FindLine(int &offset) const { const char *ptr = fData; const char *lineStart = fData; int line = 1; // clip the offset to fLength-1 since fData[fLength-1] is implicitly // the last line of the buffer and no line can start after it const char *end = ptr + ((offset < (fLength-1)) ? offset : fLength-1); while(ptr < end) { if (*ptr++ == '\n') { ++line; lineStart = ptr; // ptr is already adjusted past the NL } } offset = lineStart - fData; return line; } /* * int Buffer::FindStartOfLine(int offset) const * * return the offset of the first character in the line containing the * specified offset. */ int Buffer::FindStartOfLine(int offset) const { const char *ptr = fData + offset; while(ptr > fData) { --ptr; if (*ptr == '\n') return (ptr - fData + 1); } return 0; } /* * int Buffer::FindEndOfLine(int offset) const * * return the offset of the newline ending the line containing the * specified offset. */ int Buffer::FindEndOfLine(int offset) const { const char *ptr = fData + offset; const char *end = fData + fLength; while(ptr < end) { if (*ptr == '\n') return ptr - fData; ++ptr; } return fLength - 1; } void Buffer::ConvertLineEndings() { const char *src, *end; char *dst; src = fData; end = src + fLength; dst = fData; while(src < end) { char c = *src++; switch(c) { case CR: *dst++ = '\n'; // skip second part of CR-LF pair if (src < end && *src==LF) src++; break; case LF: *dst++ = '\n'; break; default: *dst++ = c; break; } } fLength = dst - fData; }