]> git.saurik.com Git - wxWidgets.git/blame - src/common/file.cpp
Removed streams from VC++ makefile for now; corrected typo in log.h
[wxWidgets.git] / src / common / file.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: file.cpp
3// Purpose: wxFile - encapsulates low-level "file descriptor"
4// wxTempFile
5// Author: Vadim Zeitlin
6// Modified by:
7// Created: 29/01/98
8// RCS-ID: $Id$
9// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10// Licence: wxWindows license
11/////////////////////////////////////////////////////////////////////////////
12
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
16
17#ifdef __GNUG__
18#pragma implementation "file.h"
19#endif
20
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23#include "wx/defs.h"
24
25#ifdef __BORLANDC__
26#pragma hdrstop
27#endif
28
29// standard
2049ba38 30#if defined(__WXMSW__) && !defined(__GNUWIN32__)
c801d85f
KB
31 #include <io.h>
32#elif (defined(__UNIX__) || defined(__GNUWIN32__))
33 #include <unistd.h>
34#else
35 #error "Please specify the header with file functions declarations."
36#endif //Win/UNIX
37
38#include <stdio.h> // SEEK_xxx constants
39#include <fcntl.h> // O_RDONLY &c
40#include <sys/types.h> // needed for stat
41#include <sys/stat.h> // stat
42
43// Microsoft compiler loves underscores, feed them to it
44#ifdef _MSC_VER
45 // functions
46 #define open _open
47 #define close _close
48 #define read _read
49 #define write _write
50 #define lseek _lseek
51 #define fsync _commit
52 #define access _access
53 #define eof _eof
54
55 // types
56 #define stat _stat
57
58 // constants
59 #define O_RDONLY _O_RDONLY
60 #define O_WRONLY _O_WRONLY
61 #define O_RDWR _O_RDWR
62 #define O_EXCL _O_EXCL
63 #define O_CREAT _O_CREAT
64 #define O_BINARY _O_BINARY
65
66 #define S_IFDIR _S_IFDIR
67 #define S_IFREG _S_IFREG
68
69 #define S_IREAD _S_IREAD
70 #define S_IWRITE _S_IWRITE
71#else
72 #define tell(fd) lseek(fd, 0, SEEK_CUR)
73#endif //_MSC_VER
74
75// there is no distinction between text and binary files under Unix
76#ifdef __UNIX__
77 #define O_BINARY (0)
78#endif //__UNIX__
79
80// wxWindows
81#include <wx/string.h>
82#include <wx/intl.h>
83#include <wx/file.h>
84#include <wx/log.h>
85
86
87// ============================================================================
88// implementation of wxFile
89// ============================================================================
90
91// ----------------------------------------------------------------------------
92// static functions
93// ----------------------------------------------------------------------------
94bool wxFile::Exists(const char *sz)
95{
96 struct stat st;
97 return !access(sz, 0) && !stat(sz, &st) && (st.st_mode & S_IFREG);
98}
99
100// ----------------------------------------------------------------------------
101// opening/closing
102// ----------------------------------------------------------------------------
103
104// ctors
105wxFile::wxFile(const char *szFileName, OpenMode mode)
106{
107 m_fd = fd_invalid;
108
109 Open(szFileName, mode);
110}
111
112// dtor
113wxFile::~wxFile()
114{
115 Close();
116}
117
118// create the file, fail if it already exists and bOverwrite
119bool wxFile::Create(const char *szFileName, bool bOverwrite)
120{
121 // if bOverwrite we create a new file or truncate the existing one,
122 // otherwise we only create the new file and fail if it already exists
61b02744 123 int fd = open(szFileName, O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL));
c801d85f
KB
124
125 if ( fd == -1 ) {
126 wxLogSysError("can't create file '%s'", szFileName);
127 return FALSE;
128 }
129 else {
130 Attach(fd);
131 return TRUE;
132 }
133}
134
135// open the file
136bool wxFile::Open(const char *szFileName, OpenMode mode)
137{
138 int flags = O_BINARY;
139
140 switch ( mode ) {
141 case read:
142 flags |= O_RDONLY;
143 break;
144
145 case write:
61b02744
VZ
146 flags |= O_WRONLY | O_CREAT | O_TRUNC;
147 break;
148
149 case write_append:
150 flags |= O_WRONLY | O_APPEND;
c801d85f
KB
151 break;
152
153 case read_write:
154 flags |= O_RDWR;
155 break;
156 }
157
158 int fd = open(szFileName, flags, S_IREAD | S_IWRITE);
159
160 if ( fd == -1 ) {
161 wxLogSysError("can't open file '%s'", szFileName);
162 return FALSE;
163 }
164 else {
165 Attach(fd);
166 return TRUE;
167 }
168}
169
170// close
61b02744 171bool wxFile::Close()
c801d85f
KB
172{
173 if ( IsOpened() ) {
61b02744 174 if ( close(m_fd) == -1 ) {
c801d85f 175 wxLogSysError("can't close file descriptor %d", m_fd);
61b02744
VZ
176 m_fd = fd_invalid;
177 return FALSE;
178 }
179 else
180 m_fd = fd_invalid;
c801d85f 181 }
61b02744
VZ
182
183 return TRUE;
c801d85f
KB
184}
185
186// ----------------------------------------------------------------------------
187// read/write
188// ----------------------------------------------------------------------------
189
190// read
191off_t wxFile::Read(void *pBuf, off_t nCount)
192{
1311c7a9 193 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f
KB
194
195 int iRc = ::read(m_fd, pBuf, nCount);
196 if ( iRc == -1 ) {
197 wxLogSysError("can't read from file descriptor %d", m_fd);
198 return ofsInvalid;
199 }
200 else
201 return (uint)iRc;
202}
203
204// write
205bool wxFile::Write(const void *pBuf, uint nCount)
206{
1311c7a9 207 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f
KB
208
209 int iRc = ::write(m_fd, pBuf, nCount);
210 if ( iRc == -1 ) {
211 wxLogSysError("can't write to file descriptor %d", m_fd);
212 return FALSE;
213 }
214 else
215 return TRUE;
216}
217
218// flush
219bool wxFile::Flush()
220{
221 if ( IsOpened() ) {
61b02744 222 // @@@ fsync() is not ANSI (BSDish)
c801d85f
KB
223// if ( fsync(m_fd) == -1 ) { // TODO
224 if (TRUE) {
225 wxLogSysError("can't flush file descriptor %d", m_fd);
226 return FALSE;
227 }
228 }
229
230 return TRUE;
231}
232
233// ----------------------------------------------------------------------------
234// seek
235// ----------------------------------------------------------------------------
236
237// seek
238off_t wxFile::Seek(off_t ofs, SeekMode mode)
239{
240 wxASSERT( IsOpened() );
241
242 int flag = -1;
243 switch ( mode ) {
244 case FromStart:
245 flag = SEEK_SET;
246 break;
247
248 case FromCurrent:
249 flag = SEEK_CUR;
250 break;
251
252 case FromEnd:
253 flag = SEEK_END;
254 break;
255
256 default:
257 wxFAIL_MSG("unknown seek origin");
258 }
259
260 int iRc = lseek(m_fd, ofs, flag);
261 if ( iRc == -1 ) {
262 wxLogSysError("can't seek on file descriptor %d", m_fd);
263 return ofsInvalid;
264 }
265 else
266 return (off_t)iRc;
267}
268
269// get current off_t
270off_t wxFile::Tell() const
271{
272 wxASSERT( IsOpened() );
273
274 int iRc = tell(m_fd);
275 if ( iRc == -1 ) {
276 wxLogSysError("can't get seek position on file descriptor %d", m_fd);
277 return ofsInvalid;
278 }
279 else
280 return (off_t)iRc;
281}
282
283// get current file length
284off_t wxFile::Length() const
285{
286 wxASSERT( IsOpened() );
287
288 #ifdef _MSC_VER
289 int iRc = _filelength(m_fd);
290 #else
291 int iRc = tell(m_fd);
292 if ( iRc != -1 ) {
61b02744 293 // @ have to use const_cast :-(
c801d85f
KB
294 int iLen = ((wxFile *)this)->SeekEnd();
295 if ( iLen != -1 ) {
296 // restore old position
297 if ( ((wxFile *)this)->Seek(iRc) == -1 ) {
298 // error
299 iLen = -1;
300 }
301 }
302
303 iRc = iLen;
304 }
305
306 #endif //_MSC_VER
307
308 if ( iRc == -1 ) {
309 wxLogSysError("can't find length of file on file descriptor %d", m_fd);
310 return ofsInvalid;
311 }
312 else
313 return (off_t)iRc;
314}
315
316// is end of file reached?
317bool wxFile::Eof() const
318{
319 wxASSERT( IsOpened() );
320
61b02744
VZ
321 int iRc;
322
323 #if defined(__UNIX__) || defined(__GNUWIN32__)
324 // @@ this doesn't work, of course, on unseekable file descriptors
325 off_t ofsCur = Tell(),
326 ofsMax = Length();
327 if ( ofsCur == ofsInvalid || ofsMax == ofsInvalid )
328 iRc = -1;
329 else
330 iRc = ofsCur == ofsMax;
331 #else // Windows and "native" compiler
332 iRc = eof(m_fd);
333 #endif // Windows/Unix
c801d85f
KB
334
335 switch ( iRc ) {
336 case 1:
337 break;
338
339 case 0:
340 return FALSE;
341
342 case -1:
343 wxLogSysError("can't determine if the end of file is reached on "
344 "descriptor %d", m_fd);
345 break;
346
347 default:
348 wxFAIL_MSG("invalid eof() return value.");
349 }
350
351 return TRUE;
352}
353
354// ============================================================================
355// implementation of wxTempFile
356// ============================================================================
357
358// ----------------------------------------------------------------------------
359// construction
360// ----------------------------------------------------------------------------
361wxTempFile::wxTempFile(const wxString& strName)
362{
363 Open(strName);
364}
365
366bool wxTempFile::Open(const wxString& strName)
367{
368 m_strName = strName;
b59650be
VZ
369
370 // we want to create the file in the same directory as strName because
371 // otherwise rename() in Commit() might not work (if the files are on
372 // different partitions for example). Unfortunately, the only standard
373 // (POSIX) temp file creation function tmpnam() can't do it.
374 #ifdef __UNIX__
375 static const char *szMktempSuffix = "XXXXXX";
376 m_strTemp << strName << szMktempSuffix;
377 mktemp((char *)m_strTemp.c_str()); // @@@ even if the length doesn't change
378 //m_strTemp.UngetWriteBuf();
379 #else // Windows
380 m_strTemp = tmpnam(NULL);
381 #endif // Windows/Unix
382
c801d85f
KB
383 return m_file.Open(m_strTemp, wxFile::write);
384}
385
386// ----------------------------------------------------------------------------
387// destruction
388// ----------------------------------------------------------------------------
389
390wxTempFile::~wxTempFile()
391{
392 if ( IsOpened() )
393 Discard();
394}
395
396bool wxTempFile::Commit()
397{
398 m_file.Close();
399
400 if ( wxFile::Exists(m_strName) && remove(m_strName) != 0 ) {
401 wxLogSysError("can't remove file '%s'", m_strName.c_str());
402 return FALSE;
403 }
404
405 if ( rename(m_strTemp, m_strName) != 0 ) {
406 wxLogSysError("can't commit changes to file '%s'", m_strName.c_str());
407 return FALSE;
408 }
409
410 return TRUE;
411}
412
413void wxTempFile::Discard()
414{
415 m_file.Close();
416 if ( remove(m_strTemp) != 0 )
417 wxLogSysError("can't remove temporary file '%s'", m_strTemp.c_str());
418}