1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/textbuf.cpp
3 // Purpose:     implementation of wxTextBuffer class
4 // Created:     14.11.01
5 // Author:      Morten Hanssen, Vadim Zeitlin
6 // Copyright:   (c) 1998-2001 wxWidgets team
7 // Licence:     wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 // ============================================================================
11 // headers
12 // ============================================================================
13 
14 #include  "wx/wxprec.h"
15 
16 #ifndef WX_PRECOMP
17     #include  "wx/string.h"
18     #include  "wx/intl.h"
19     #include  "wx/log.h"
20 #endif
21 
22 #include "wx/textbuf.h"
23 
24 // ============================================================================
25 // wxTextBuffer class implementation
26 // ============================================================================
27 
28 // ----------------------------------------------------------------------------
29 // static methods (always compiled in)
30 // ----------------------------------------------------------------------------
31 
32 // default type is the native one
33 
34 const wxTextFileType wxTextBuffer::typeDefault =
35 #if defined(__WINDOWS__)
36   wxTextFileType_Dos;
37 #elif defined(__UNIX__)
38   wxTextFileType_Unix;
39 #else
40   wxTextFileType_None;
41   #error  "wxTextBuffer: unsupported platform."
42 #endif
43 
GetEOL(wxTextFileType type)44 const wxChar *wxTextBuffer::GetEOL(wxTextFileType type)
45 {
46     switch ( type ) {
47         default:
48             wxFAIL_MSG(wxT("bad buffer type in wxTextBuffer::GetEOL."));
49             wxFALLTHROUGH; // fall through nevertheless - we must return something...
50 
51         case wxTextFileType_None: return wxEmptyString;
52         case wxTextFileType_Unix: return wxT("\n");
53         case wxTextFileType_Dos:  return wxT("\r\n");
54         case wxTextFileType_Mac:  return wxT("\r");
55     }
56 }
57 
Translate(const wxString & text,wxTextFileType type)58 wxString wxTextBuffer::Translate(const wxString& text, wxTextFileType type)
59 {
60     // don't do anything if there is nothing to do
61     if ( type == wxTextFileType_None )
62         return text;
63 
64     // nor if it is empty
65     if ( text.empty() )
66         return text;
67 
68     wxString eol = GetEOL(type), result;
69 
70     // optimization: we know that the length of the new string will be about
71     // the same as the length of the old one, so prealloc memory to avoid
72     // unnecessary relocations
73     result.Alloc(text.Len());
74 
75     wxChar chLast = 0;
76     for ( wxString::const_iterator i = text.begin(); i != text.end(); ++i )
77     {
78         wxChar ch = *i;
79         switch ( ch ) {
80             case wxT('\n'):
81                 // Dos/Unix line termination
82                 result += eol;
83                 chLast = 0;
84                 break;
85 
86             case wxT('\r'):
87                 if ( chLast == wxT('\r') ) {
88                     // Mac empty line
89                     result += eol;
90                 }
91                 else {
92                     // just remember it: we don't know whether it is just "\r"
93                     // or "\r\n" yet
94                     chLast = wxT('\r');
95                 }
96                 break;
97 
98             default:
99                 if ( chLast == wxT('\r') ) {
100                     // Mac line termination
101                     result += eol;
102 
103                     // reset chLast to avoid inserting another eol before the
104                     // next character
105                     chLast = 0;
106                 }
107 
108                 // add to the current line
109                 result += ch;
110         }
111     }
112 
113     if ( chLast ) {
114         // trailing '\r'
115         result += eol;
116     }
117 
118     return result;
119 }
120 
121 #if wxUSE_TEXTBUFFER
122 
123 wxString wxTextBuffer::ms_eof;
124 
125 // ----------------------------------------------------------------------------
126 // ctors & dtor
127 // ----------------------------------------------------------------------------
128 
wxTextBuffer(const wxString & strBufferName)129 wxTextBuffer::wxTextBuffer(const wxString& strBufferName)
130             : m_strBufferName(strBufferName)
131 {
132     m_nCurLine = 0;
133     m_isOpened = false;
134 }
135 
~wxTextBuffer()136 wxTextBuffer::~wxTextBuffer()
137 {
138     // required here for Darwin
139 }
140 
141 // ----------------------------------------------------------------------------
142 // buffer operations
143 // ----------------------------------------------------------------------------
144 
Exists() const145 bool wxTextBuffer::Exists() const
146 {
147     return OnExists();
148 }
149 
Create(const wxString & strBufferName)150 bool wxTextBuffer::Create(const wxString& strBufferName)
151 {
152     m_strBufferName = strBufferName;
153 
154     return Create();
155 }
156 
Create()157 bool wxTextBuffer::Create()
158 {
159     // buffer name must be either given in ctor or in Create(const wxString&)
160     wxASSERT( !m_strBufferName.empty() );
161 
162     // if the buffer already exists do nothing
163     if ( Exists() ) return false;
164 
165     if ( !OnOpen(m_strBufferName, WriteAccess) )
166         return false;
167 
168     OnClose();
169     return true;
170 }
171 
Open(const wxString & strBufferName,const wxMBConv & conv)172 bool wxTextBuffer::Open(const wxString& strBufferName, const wxMBConv& conv)
173 {
174     m_strBufferName = strBufferName;
175 
176     return Open(conv);
177 }
178 
Open(const wxMBConv & conv)179 bool wxTextBuffer::Open(const wxMBConv& conv)
180 {
181     // buffer name must be either given in ctor or in Open(const wxString&)
182     wxASSERT( !m_strBufferName.empty() );
183 
184     // open buffer in read-only mode
185     if ( !OnOpen(m_strBufferName, ReadAccess) )
186         return false;
187 
188     // read buffer into memory
189     m_isOpened = OnRead(conv);
190 
191     OnClose();
192 
193     return m_isOpened;
194 }
195 
196 // analyse some lines of the buffer trying to guess it's type.
197 // if it fails, it assumes the native type for our platform.
GuessType() const198 wxTextFileType wxTextBuffer::GuessType() const
199 {
200     wxASSERT( IsOpened() );
201 
202     // scan the buffer lines
203     size_t nUnix = 0,     // number of '\n's alone
204            nDos  = 0,     // number of '\r\n'
205            nMac  = 0;     // number of '\r's
206 
207     // we take MAX_LINES_SCAN in the beginning, middle and the end of buffer
208     #define MAX_LINES_SCAN    (10)
209     size_t nCount = m_aLines.GetCount() / 3,
210         nScan =  nCount > 3*MAX_LINES_SCAN ? MAX_LINES_SCAN : nCount / 3;
211 
212     #define   AnalyseLine(n)              \
213         switch ( m_aTypes[n] ) {            \
214             case wxTextFileType_Unix: nUnix++; break;   \
215             case wxTextFileType_Dos:  nDos++;  break;   \
216             case wxTextFileType_Mac:  nMac++;  break;   \
217             default: wxFAIL_MSG(wxT("unknown line terminator")); \
218         }
219 
220     size_t n;
221     for ( n = 0; n < nScan; n++ )     // the beginning
222         AnalyseLine(n);
223     for ( n = (nCount - nScan)/2; n < (nCount + nScan)/2; n++ )
224         AnalyseLine(n);
225     for ( n = nCount - nScan; n < nCount; n++ )
226         AnalyseLine(n);
227 
228     #undef   AnalyseLine
229 
230     // interpret the results (FIXME far from being even 50% fool proof)
231     if ( nScan > 0 && nDos + nUnix + nMac == 0 ) {
232         // no newlines at all
233         wxLogWarning(_("'%s' is probably a binary buffer."), m_strBufferName.c_str());
234     }
235     else {
236         #define   GREATER_OF(t1, t2) n##t1 == n##t2 ? typeDefault               \
237                                                 : n##t1 > n##t2             \
238                                                     ? wxTextFileType_##t1   \
239                                                     : wxTextFileType_##t2
240 
241         if ( nDos > nUnix )
242             return GREATER_OF(Dos, Mac);
243         else if ( nDos < nUnix )
244             return GREATER_OF(Unix, Mac);
245         else {
246             // nDos == nUnix
247             return nMac > nDos ? wxTextFileType_Mac : typeDefault;
248         }
249 
250         #undef    GREATER_OF
251     }
252 
253     return typeDefault;
254 }
255 
256 
Close()257 bool wxTextBuffer::Close()
258 {
259     Clear();
260     m_isOpened = false;
261 
262     return true;
263 }
264 
Write(wxTextFileType typeNew,const wxMBConv & conv)265 bool wxTextBuffer::Write(wxTextFileType typeNew, const wxMBConv& conv)
266 {
267     return OnWrite(typeNew, conv);
268 }
269 
270 #endif // wxUSE_TEXTBUFFER
271