/////////////////////////////////////////////////////////////////////////////// // Name: textfile.cpp // Purpose: implementation of wxTextFile class // Author: Vadim Zeitlin // Modified by: // Created: 03.04.98 // RCS-ID: $Id$ // Copyright: (c) 1998 Vadim Zeitlin // Licence: wxWindows license /////////////////////////////////////////////////////////////////////////////// // ============================================================================ // headers // ============================================================================ #ifdef __GNUG__ #pragma implementation "textfile.h" #endif #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif //__BORLANDC__ #include #include #include #include #include // ============================================================================ // wxTextFile class implementation // ============================================================================ // ---------------------------------------------------------------------------- // static variables // ---------------------------------------------------------------------------- // default type is the native one const wxTextFile::Type wxTextFile::typeDefault = wxTextFile:: #if defined(__WXMSW__) Type_Dos; #elif defined(__UNIX__) Type_Unix; #elif defined(__MAC__) Type_Mac; // if you feel brave, remove the next line #error "wxTextFile: code for Mac files is untested." #else Type_None; #error "wxTextFile: unsupported platform." #endif // ---------------------------------------------------------------------------- // ctors & dtor // ---------------------------------------------------------------------------- wxTextFile::wxTextFile(const wxString& strFile) : m_strFile(strFile) { } wxTextFile::~wxTextFile() { // m_file dtor called automatically } // ---------------------------------------------------------------------------- // file operations // ---------------------------------------------------------------------------- bool wxTextFile::Open(const wxString& strFile) { m_strFile = strFile; return Open(); } bool wxTextFile::Open() { // file name must be either given in ctor or in Open(const wxString&) wxASSERT( !m_strFile.IsEmpty() ); // open file in read-only mode if ( !m_file.Open(m_strFile) ) return FALSE; // read file into memory bool bRet = Read(); m_file.Close(); return bRet; } // analyse some lines of the file trying to guess it's type. // if it fails, it assumes the native type for our platform. wxTextFile::Type wxTextFile::GuessType() const { // file should be opened and we must be in it's beginning wxASSERT( m_file.IsOpened() && m_file.Tell() == 0 ); // scan the file lines uint nUnix = 0, // number of '\n's alone nDos = 0, // number of '\r\n' nMac = 0; // number of '\r's // we take MAX_LINES_SCAN in the beginning, middle and the end of file #define MAX_LINES_SCAN (10) uint nCount = m_aLines.Count() / 3, nScan = nCount > 3*MAX_LINES_SCAN ? MAX_LINES_SCAN : nCount / 3; #define AnalyseLine(n) \ switch ( m_aTypes[n] ) { \ case Type_Unix: nUnix++; break; \ case Type_Dos: nDos++; break; \ case Type_Mac: nMac++; break; \ default: wxFAIL_MSG("unknown line terminator"); \ } uint n; for ( n = 0; n < nScan; n++ ) // the beginning AnalyseLine(n); for ( n = (nCount - nScan)/2; n < (nCount + nScan)/2; n++ ) AnalyseLine(n); for ( n = nCount - nScan; n < nCount; n++ ) AnalyseLine(n); #undef AnalyseLine // interpret the results (@@ far from being even 50% fool proof) if ( nDos + nUnix + nMac == 0 ) { // no newlines at all wxLogWarning("'%s' is probably a binary file.", m_strFile.c_str()); } else { #define GREATER_OF(t1, t2) n##t1 == n##t2 ? typeDefault \ : n##t1 > n##t2 ? Type_##t1 \ : Type_##t2 if ( nDos > nUnix ) return GREATER_OF(Dos, Mac); else if ( nDos < nUnix ) return GREATER_OF(Unix, Mac); else { // nDos == nUnix return nMac > nDos ? Type_Mac : typeDefault; } #undef GREATER_OF } return typeDefault; } bool wxTextFile::Read() { // file should be opened and we must be in it's beginning wxASSERT( m_file.IsOpened() && m_file.Tell() == 0 ); wxString str; char ch, chLast = '\0'; char buf[1024]; int n, nRead; while ( !m_file.Eof() ) { nRead = m_file.Read(buf, WXSIZEOF(buf)); if ( nRead == ofsInvalid ) { // read error (error message already given in wxFile::Read) m_file.Close(); return FALSE; } #ifdef __MAC__ #pragma message("wxTextFile::Read() hasn't been tested with Mac files.") #endif for ( n = 0; n < nRead; n++ ) { ch = buf[n]; switch ( ch ) { case '\n': // Dos/Unix line termination m_aLines.Add(str); m_aTypes.Add(chLast == '\r' ? Type_Dos : Type_Unix); str.Empty(); chLast = '\n'; break; case '\r': if ( chLast == '\r' ) { // Mac empty line m_aLines.Add(""); m_aTypes.Add(Type_Mac); } else chLast = '\r'; break; default: if ( chLast == '\r' ) { // Mac line termination m_aLines.Add(str); m_aTypes.Add(Type_Mac); str = ch; } else { // add to the current line str += ch; } } } } // anything in the last line? if ( !str.IsEmpty() ) { m_aTypes.Add(Type_None); // no line terminator m_aLines.Add(str); } return TRUE; } bool wxTextFile::Write(Type typeNew) { wxTempFile fileTmp(m_strFile); if ( !fileTmp.IsOpened() ) { wxLogError("can't write file '%s' to disk.", m_strFile.c_str()); return FALSE; } uint nCount = m_aLines.Count(); for ( uint n = 0; n < nCount; n++ ) { fileTmp.Write(m_aLines[n] + GetEOL(typeNew == Type_None ? m_aTypes[n] : typeNew)); } // replace the old file with this one return fileTmp.Commit(); }