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