]> git.saurik.com Git - wxWidgets.git/blame - src/common/file.cpp
no message
[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>
246037e2 10// Licence: wxWindows license
c801d85f
KB
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
246037e2 30#if defined(__WXMSW__) && !defined(__GNUWIN32__)
c801d85f 31 #include <io.h>
30a5be97
VZ
32
33 #define WIN32_LEAN_AND_MEAN
34 #define NOSERVICE
35 #define NOIME
36 #define NOATOM
37 #define NOGDI
38 #define NOGDICAPMASKS
39 #define NOMETAFILE
40 #define NOMINMAX
41 #define NOMSG
42 #define NOOPENFILE
43 #define NORASTEROPS
44 #define NOSCROLL
45 #define NOSOUND
46 #define NOSYSMETRICS
47 #define NOTEXTMETRIC
48 #define NOWH
49 #define NOCOMM
50 #define NOKANJI
51 #define NOCRYPT
52 #define NOMCX
53 #include <windows.h> // for GetTempFileName
c801d85f
KB
54#elif (defined(__UNIX__) || defined(__GNUWIN32__))
55 #include <unistd.h>
34138703
JS
56#elif (defined(__WXSTUBS__))
57 // Have to ifdef this for different environments
58 #include <io.h>
17dff81c
SC
59#elif (defined(__WXMAC__))
60 int access( const char *path, int mode ) { return 0 ; }
61 char* mktemp( char * path ) { return path ;}
62 #include <unistd.h>
63 #include <unix.h>
64 #define W_OK 2
65 #define R_OK 4
c801d85f 66#else
246037e2 67 #error "Please specify the header with file functions declarations."
c801d85f
KB
68#endif //Win/UNIX
69
70#include <stdio.h> // SEEK_xxx constants
71#include <fcntl.h> // O_RDONLY &c
469e1e5c 72#ifndef __MWERKS__
c801d85f
KB
73#include <sys/types.h> // needed for stat
74#include <sys/stat.h> // stat
469e1e5c 75#endif
c801d85f
KB
76
77// Microsoft compiler loves underscores, feed them to it
78#ifdef _MSC_VER
469e1e5c
SC
79
80 #ifndef __MWERKS__
81
c801d85f
KB
82 // functions
83 #define open _open
84 #define close _close
85 #define read _read
86 #define write _write
87 #define lseek _lseek
88 #define fsync _commit
89 #define access _access
90 #define eof _eof
91
92 // types
93 #define stat _stat
94
95 // constants
469e1e5c 96
c801d85f
KB
97 #define O_RDONLY _O_RDONLY
98 #define O_WRONLY _O_WRONLY
99 #define O_RDWR _O_RDWR
100 #define O_EXCL _O_EXCL
101 #define O_CREAT _O_CREAT
102 #define O_BINARY _O_BINARY
103
104 #define S_IFDIR _S_IFDIR
105 #define S_IFREG _S_IFREG
469e1e5c
SC
106
107 #endif
d1427b70
VZ
108
109 #define W_OK 2
110 #define R_OK 4
c801d85f
KB
111#else
112 #define tell(fd) lseek(fd, 0, SEEK_CUR)
113#endif //_MSC_VER
114
34138703
JS
115#ifdef __BORLANDC__
116 #define W_OK 2
117 #define R_OK 4
118#endif
119
c801d85f 120// there is no distinction between text and binary files under Unix
246037e2
VZ
121#ifdef __UNIX__
122 #define O_BINARY (0)
123#endif //__UNIX__
c801d85f
KB
124
125// wxWindows
126#include <wx/string.h>
127#include <wx/intl.h>
128#include <wx/file.h>
129#include <wx/log.h>
130
81d66cf3
JS
131#ifndef MAX_PATH
132#define MAX_PATH 512
133#endif
c801d85f
KB
134
135// ============================================================================
136// implementation of wxFile
137// ============================================================================
138
139// ----------------------------------------------------------------------------
140// static functions
141// ----------------------------------------------------------------------------
d1427b70 142bool wxFile::Exists(const char *name)
246037e2
VZ
143{
144 struct stat st;
d1427b70
VZ
145 return !access(name, 0) && !stat(name, &st) && (st.st_mode & S_IFREG);
146}
147
148bool wxFile::Access(const char *name, OpenMode mode)
149{
8fdca65c 150 int how = 0;
d1427b70
VZ
151
152 switch ( mode ) {
153 case read:
154 how = R_OK;
155 break;
156
157 case write:
158 how = W_OK;
159 break;
160
161 default:
162 wxFAIL_MSG("bad wxFile::Access mode parameter.");
163 }
164
165 return access(name, how) == 0;
c801d85f
KB
166}
167
168// ----------------------------------------------------------------------------
169// opening/closing
170// ----------------------------------------------------------------------------
171
172// ctors
173wxFile::wxFile(const char *szFileName, OpenMode mode)
174{
175 m_fd = fd_invalid;
79c3e0e1 176 m_error = FALSE;
c801d85f
KB
177
178 Open(szFileName, mode);
179}
180
181// dtor
182wxFile::~wxFile()
183{
184 Close();
185}
186
187// create the file, fail if it already exists and bOverwrite
246037e2 188bool wxFile::Create(const char *szFileName, bool bOverwrite, int access)
c801d85f
KB
189{
190 // if bOverwrite we create a new file or truncate the existing one,
191 // otherwise we only create the new file and fail if it already exists
5fc5e442
VZ
192 int fd = open(szFileName, O_WRONLY | O_CREAT |
193 (bOverwrite ? O_TRUNC : O_EXCL), access);
c801d85f
KB
194
195 if ( fd == -1 ) {
1a5a8367 196 wxLogSysError(_("can't create file '%s'"), szFileName);
c801d85f
KB
197 return FALSE;
198 }
199 else {
200 Attach(fd);
201 return TRUE;
202 }
203}
204
205// open the file
246037e2 206bool wxFile::Open(const char *szFileName, OpenMode mode, int access)
c801d85f
KB
207{
208 int flags = O_BINARY;
209
210 switch ( mode ) {
246037e2
VZ
211 case read:
212 flags |= O_RDONLY;
c801d85f
KB
213 break;
214
246037e2
VZ
215 case write:
216 flags |= O_WRONLY | O_CREAT | O_TRUNC;
61b02744
VZ
217 break;
218
219 case write_append:
220 flags |= O_WRONLY | O_APPEND;
c801d85f
KB
221 break;
222
246037e2 223 case read_write:
c801d85f
KB
224 flags |= O_RDWR;
225 break;
226 }
227
246037e2 228 int fd = open(szFileName, flags, access);
c801d85f
KB
229
230 if ( fd == -1 ) {
1a5a8367 231 wxLogSysError(_("can't open file '%s'"), szFileName);
c801d85f
KB
232 return FALSE;
233 }
234 else {
235 Attach(fd);
236 return TRUE;
237 }
238}
239
240// close
61b02744 241bool wxFile::Close()
c801d85f
KB
242{
243 if ( IsOpened() ) {
61b02744 244 if ( close(m_fd) == -1 ) {
1a5a8367 245 wxLogSysError(_("can't close file descriptor %d"), m_fd);
61b02744
VZ
246 m_fd = fd_invalid;
247 return FALSE;
248 }
249 else
250 m_fd = fd_invalid;
c801d85f 251 }
61b02744
VZ
252
253 return TRUE;
c801d85f
KB
254}
255
256// ----------------------------------------------------------------------------
257// read/write
258// ----------------------------------------------------------------------------
259
260// read
261off_t wxFile::Read(void *pBuf, off_t nCount)
262{
1311c7a9 263 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f 264
469e1e5c
SC
265#ifdef __MWERKS__
266 int iRc = ::read(m_fd, (char*) pBuf, nCount);
267#else
c801d85f 268 int iRc = ::read(m_fd, pBuf, nCount);
469e1e5c 269#endif
c801d85f 270 if ( iRc == -1 ) {
1a5a8367 271 wxLogSysError(_("can't read from file descriptor %d"), m_fd);
1678ad78 272 return wxInvalidOffset;
c801d85f
KB
273 }
274 else
c86f1403 275 return (size_t)iRc;
c801d85f
KB
276}
277
278// write
c86f1403 279size_t wxFile::Write(const void *pBuf, size_t nCount)
c801d85f 280{
1311c7a9 281 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f 282
469e1e5c
SC
283#ifdef __MWERKS__
284 int iRc = ::write(m_fd, (const char*) pBuf, nCount);
285#else
c801d85f 286 int iRc = ::write(m_fd, pBuf, nCount);
469e1e5c 287#endif
c801d85f 288 if ( iRc == -1 ) {
1a5a8367 289 wxLogSysError(_("can't write to file descriptor %d"), m_fd);
79c3e0e1
GL
290 m_error = TRUE;
291 return 0;
c801d85f
KB
292 }
293 else
1678ad78 294 return iRc;
c801d85f
KB
295}
296
297// flush
298bool wxFile::Flush()
299{
300 if ( IsOpened() ) {
1678ad78 301 // @@@ fsync() is not ANSI (BSDish)
c801d85f 302// if ( fsync(m_fd) == -1 ) { // TODO
341287bf 303 if (wxTrue) {
1a5a8367 304 wxLogSysError(_("can't flush file descriptor %d"), m_fd);
c801d85f
KB
305 return FALSE;
306 }
307 }
308
309 return TRUE;
310}
311
312// ----------------------------------------------------------------------------
313// seek
314// ----------------------------------------------------------------------------
315
316// seek
79c3e0e1 317off_t wxFile::Seek(off_t ofs, wxSeekMode mode)
c801d85f
KB
318{
319 wxASSERT( IsOpened() );
320
321 int flag = -1;
322 switch ( mode ) {
79c3e0e1 323 case wxFromStart:
c801d85f
KB
324 flag = SEEK_SET;
325 break;
326
79c3e0e1 327 case wxFromCurrent:
c801d85f
KB
328 flag = SEEK_CUR;
329 break;
330
79c3e0e1 331 case wxFromEnd:
c801d85f
KB
332 flag = SEEK_END;
333 break;
334
335 default:
1a5a8367 336 wxFAIL_MSG(_("unknown seek origin"));
c801d85f
KB
337 }
338
339 int iRc = lseek(m_fd, ofs, flag);
340 if ( iRc == -1 ) {
1a5a8367 341 wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
1678ad78 342 return wxInvalidOffset;
c801d85f
KB
343 }
344 else
345 return (off_t)iRc;
346}
347
348// get current off_t
349off_t wxFile::Tell() const
350{
351 wxASSERT( IsOpened() );
352
353 int iRc = tell(m_fd);
354 if ( iRc == -1 ) {
1a5a8367 355 wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
1678ad78 356 return wxInvalidOffset;
c801d85f
KB
357 }
358 else
359 return (off_t)iRc;
360}
361
362// get current file length
363off_t wxFile::Length() const
364{
365 wxASSERT( IsOpened() );
366
469e1e5c 367 #if defined( _MSC_VER ) && !defined( __MWERKS__ )
c801d85f
KB
368 int iRc = _filelength(m_fd);
369 #else
370 int iRc = tell(m_fd);
371 if ( iRc != -1 ) {
246037e2 372 // @ have to use const_cast :-(
c801d85f
KB
373 int iLen = ((wxFile *)this)->SeekEnd();
374 if ( iLen != -1 ) {
375 // restore old position
376 if ( ((wxFile *)this)->Seek(iRc) == -1 ) {
377 // error
378 iLen = -1;
379 }
380 }
381
382 iRc = iLen;
383 }
384
385 #endif //_MSC_VER
386
387 if ( iRc == -1 ) {
1a5a8367 388 wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
1678ad78 389 return wxInvalidOffset;
c801d85f
KB
390 }
391 else
392 return (off_t)iRc;
393}
394
395// is end of file reached?
396bool wxFile::Eof() const
397{
398 wxASSERT( IsOpened() );
399
61b02744
VZ
400 int iRc;
401
469e1e5c 402 #if defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ )
61b02744
VZ
403 // @@ this doesn't work, of course, on unseekable file descriptors
404 off_t ofsCur = Tell(),
405 ofsMax = Length();
1678ad78 406 if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
61b02744
VZ
407 iRc = -1;
408 else
409 iRc = ofsCur == ofsMax;
410 #else // Windows and "native" compiler
411 iRc = eof(m_fd);
412 #endif // Windows/Unix
c801d85f
KB
413
414 switch ( iRc ) {
415 case 1:
416 break;
417
418 case 0:
419 return FALSE;
420
421 case -1:
1a5a8367
DP
422 wxLogSysError(_("can't determine if the end of file is reached on \
423descriptor %d"), m_fd);
c801d85f
KB
424 break;
425
426 default:
1a5a8367 427 wxFAIL_MSG(_("invalid eof() return value."));
c801d85f
KB
428 }
429
430 return TRUE;
431}
432
433// ============================================================================
434// implementation of wxTempFile
435// ============================================================================
436
437// ----------------------------------------------------------------------------
438// construction
439// ----------------------------------------------------------------------------
440wxTempFile::wxTempFile(const wxString& strName)
441{
442 Open(strName);
443}
444
445bool wxTempFile::Open(const wxString& strName)
446{
447 m_strName = strName;
246037e2 448
b59650be
VZ
449 // we want to create the file in the same directory as strName because
450 // otherwise rename() in Commit() might not work (if the files are on
451 // different partitions for example). Unfortunately, the only standard
452 // (POSIX) temp file creation function tmpnam() can't do it.
17dff81c 453 #if defined(__UNIX__) || defined(__WXSTUBS__)|| defined( __WXMAC__ )
b59650be
VZ
454 static const char *szMktempSuffix = "XXXXXX";
455 m_strTemp << strName << szMktempSuffix;
30a5be97 456 mktemp((char *)m_strTemp.c_str()); // will do because length doesn't change
b59650be 457 #else // Windows
30a5be97
VZ
458 wxString strPath;
459 wxSplitPath(strName, &strPath, NULL, NULL);
460 if ( strPath.IsEmpty() )
461 strPath = '.'; // GetTempFileName will fail if we give it empty string
81d66cf3 462#ifdef __WIN32__
30a5be97 463 if ( !GetTempFileName(strPath, "wx_",0, m_strTemp.GetWriteBuf(MAX_PATH)) )
81d66cf3
JS
464#else
465 // Not sure why MSVC++ 1.5 header defines first param as BYTE - bug?
466 if ( !GetTempFileName((BYTE) (const char*) strPath, "wx_",0, m_strTemp.GetWriteBuf(MAX_PATH)) )
467#endif
30a5be97
VZ
468 wxLogLastError("GetTempFileName");
469 m_strTemp.UngetWriteBuf();
b59650be 470 #endif // Windows/Unix
246037e2 471
c801d85f
KB
472 return m_file.Open(m_strTemp, wxFile::write);
473}
474
475// ----------------------------------------------------------------------------
476// destruction
477// ----------------------------------------------------------------------------
478
479wxTempFile::~wxTempFile()
480{
481 if ( IsOpened() )
482 Discard();
483}
484
485bool wxTempFile::Commit()
486{
487 m_file.Close();
488
489 if ( wxFile::Exists(m_strName) && remove(m_strName) != 0 ) {
1a5a8367 490 wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
c801d85f
KB
491 return FALSE;
492 }
493
494 if ( rename(m_strTemp, m_strName) != 0 ) {
1a5a8367 495 wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
c801d85f
KB
496 return FALSE;
497 }
498
499 return TRUE;
500}
501
502void wxTempFile::Discard()
503{
504 m_file.Close();
505 if ( remove(m_strTemp) != 0 )
1a5a8367 506 wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
c801d85f 507}