]> git.saurik.com Git - wxWidgets.git/blame - src/common/file.cpp
Better text control non-selection solution
[wxWidgets.git] / src / common / file.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
f172cb82 2// Name: src/common/file.cpp
c801d85f
KB
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>
65571936 10// Licence: wxWindows licence
c801d85f
KB
11/////////////////////////////////////////////////////////////////////////////
12
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
16
c801d85f
KB
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
c801d85f
KB
19
20#ifdef __BORLANDC__
ce4169a4 21 #pragma hdrstop
c801d85f
KB
22#endif
23
ce4169a4
RR
24#if wxUSE_FILE
25
c801d85f 26// standard
1c193821 27#if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
30a5be97 28
f172cb82
VZ
29#define WIN32_LEAN_AND_MEAN
30#define NOSERVICE
31#define NOIME
32#define NOATOM
33#define NOGDI
34#define NOGDICAPMASKS
35#define NOMETAFILE
36#define NOMINMAX
37#define NOMSG
38#define NOOPENFILE
39#define NORASTEROPS
40#define NOSCROLL
41#define NOSOUND
42#define NOSYSMETRICS
43#define NOTEXTMETRIC
44#define NOWH
45#define NOCOMM
46#define NOKANJI
47#define NOCRYPT
48#define NOMCX
a3ef5bf5 49
1c193821 50#elif defined(__WXMSW__) && defined(__WXWINCE__)
d109c584 51 #include "wx/msw/missing.h"
5a3912f2
SN
52#elif (defined(__OS2__))
53 #include <io.h>
c801d85f 54#elif (defined(__UNIX__) || defined(__GNUWIN32__))
3f4a0c5b 55 #include <unistd.h>
fd938b11 56 #include <time.h>
732b8386 57 #include <sys/stat.h>
3f4a0c5b 58 #ifdef __GNUWIN32__
9ed0d735 59 #include "wx/msw/wrapwin.h"
3f4a0c5b 60 #endif
d3b4d710
VS
61#elif defined(__DOS__)
62 #if defined(__WATCOMC__)
63 #include <io.h>
64 #elif defined(__DJGPP__)
65 #include <io.h>
66 #include <unistd.h>
67 #include <stdio.h>
68 #else
69 #error "Please specify the header with file functions declarations."
70 #endif
34138703 71#elif (defined(__WXSTUBS__))
3f4a0c5b
VZ
72 // Have to ifdef this for different environments
73 #include <io.h>
17dff81c 74#elif (defined(__WXMAC__))
5b781a67 75#if __MSL__ < 0x6000
3f4a0c5b 76 int access( const char *path, int mode ) { return 0 ; }
5b781a67
SC
77#else
78 int _access( const char *path, int mode ) { return 0 ; }
79#endif
3f4a0c5b 80 char* mktemp( char * path ) { return path ;}
5b781a67 81 #include <stat.h>
6294ac2e 82 #include <unistd.h>
9b4da627
VZ
83#elif defined(__WXPALMOS__)
84 #include "wx/palmos/missing.h"
c801d85f 85#else
3f4a0c5b 86 #error "Please specify the header with file functions declarations."
c801d85f
KB
87#endif //Win/UNIX
88
89#include <stdio.h> // SEEK_xxx constants
1c193821 90
65fe93d8
VZ
91#ifndef __WXWINCE__
92 #include <errno.h>
93#endif
94
4ea2c29f
VZ
95// Windows compilers don't have these constants
96#ifndef W_OK
97 enum
98 {
99 F_OK = 0, // test for existence
100 X_OK = 1, // execute permission
101 W_OK = 2, // write
102 R_OK = 4 // read
103 };
104#endif // W_OK
34138703 105
77ffb593 106// wxWidgets
ade35f11
VZ
107#ifndef WX_PRECOMP
108 #include "wx/string.h"
109 #include "wx/intl.h"
ade35f11 110 #include "wx/log.h"
0bf751e7 111 #include "wx/crt.h"
ade35f11
VZ
112#endif // !WX_PRECOMP
113
114#include "wx/filename.h"
44d568b6 115#include "wx/file.h"
4ea2c29f 116#include "wx/filefn.h"
f6bcfd97 117
7cbe148e
SN
118// there is no distinction between text and binary files under Unix, so define
119// O_BINARY as 0 if the system headers don't do it already
120#if defined(__UNIX__) && !defined(O_BINARY)
121 #define O_BINARY (0)
122#endif //__UNIX__
123
28f5082b
VS
124#ifdef __WXMSW__
125 #include "wx/msw/mslu.h"
126#endif
127
1c193821
JS
128#ifdef __WXWINCE__
129 #include "wx/msw/private.h"
130#endif
131
7cbe148e
SN
132#ifndef MAX_PATH
133 #define MAX_PATH 512
134#endif
30984dea 135
c801d85f
KB
136// ============================================================================
137// implementation of wxFile
138// ============================================================================
139
140// ----------------------------------------------------------------------------
141// static functions
142// ----------------------------------------------------------------------------
4ea2c29f 143
fcea31d5 144bool wxFile::Exists(const wxString& name)
246037e2 145{
4ea2c29f 146 return wxFileExists(name);
d1427b70
VZ
147}
148
fcea31d5 149bool wxFile::Access(const wxString& name, OpenMode mode)
d1427b70 150{
4ea2c29f
VZ
151 int how;
152
153 switch ( mode )
154 {
155 default:
156 wxFAIL_MSG(wxT("bad wxFile::Access mode parameter."));
157 // fall through
d1427b70 158
49d5d881
VZ
159 case read:
160 how = R_OK;
161 break;
d1427b70 162
49d5d881
VZ
163 case write:
164 how = W_OK;
165 break;
d1427b70 166
4ea2c29f
VZ
167 case read_write:
168 how = R_OK | W_OK;
169 break;
49d5d881 170 }
d1427b70 171
4ea2c29f 172 return wxAccess(name, how) == 0;
c801d85f
KB
173}
174
175// ----------------------------------------------------------------------------
176// opening/closing
177// ----------------------------------------------------------------------------
178
179// ctors
11aac4ba 180wxFile::wxFile(const wxString& fileName, OpenMode mode)
c801d85f 181{
49d5d881 182 m_fd = fd_invalid;
65fe93d8 183 m_lasterror = 0;
c801d85f 184
11aac4ba 185 Open(fileName, mode);
c801d85f
KB
186}
187
65fe93d8
VZ
188bool wxFile::CheckForError(wxFileOffset rc) const
189{
190 if ( rc != -1 )
191 return false;
192
193 const_cast<wxFile *>(this)->m_lasterror =
194#ifndef __WXWINCE__
195 errno
196#else
197 ::GetLastError()
198#endif
199 ;
200
201 return true;
202}
203
c801d85f 204// create the file, fail if it already exists and bOverwrite
fcea31d5 205bool wxFile::Create(const wxString& fileName, bool bOverwrite, int accessMode)
c801d85f 206{
49d5d881
VZ
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
fcea31d5 209 int fd = wxOpen( fileName,
92980e90 210 O_BINARY | O_WRONLY | O_CREAT |
f172cb82
VZ
211 (bOverwrite ? O_TRUNC : O_EXCL),
212 accessMode );
65fe93d8 213 if ( CheckForError(fd) )
92980e90 214 {
fcea31d5 215 wxLogSysError(_("can't create file '%s'"), fileName);
a62848fd 216 return false;
49d5d881 217 }
769627d7
DS
218
219 Attach(fd);
220 return true;
c801d85f
KB
221}
222
223// open the file
fcea31d5 224bool wxFile::Open(const wxString& fileName, OpenMode mode, int accessMode)
c801d85f 225{
49d5d881 226 int flags = O_BINARY;
c801d85f 227
92980e90
RR
228 switch ( mode )
229 {
49d5d881
VZ
230 case read:
231 flags |= O_RDONLY;
232 break;
c801d85f 233
f6bcfd97 234 case write_append:
fcea31d5 235 if ( wxFile::Exists(fileName) )
f6bcfd97
BP
236 {
237 flags |= O_WRONLY | O_APPEND;
238 break;
239 }
240 //else: fall through as write_append is the same as write if the
241 // file doesn't exist
242
49d5d881
VZ
243 case write:
244 flags |= O_WRONLY | O_CREAT | O_TRUNC;
245 break;
61b02744 246
68164137
RL
247 case write_excl:
248 flags |= O_WRONLY | O_CREAT | O_EXCL;
249 break;
250
49d5d881
VZ
251 case read_write:
252 flags |= O_RDWR;
253 break;
254 }
c801d85f 255
cc8cc54f
VZ
256#ifdef __WINDOWS__
257 // only read/write bits for "all" are supported by this function under
258 // Windows, and VC++ 8 returns EINVAL if any other bits are used in
259 // accessMode, so clear them as they have at best no effect anyhow
260 accessMode &= wxS_IRUSR | wxS_IWUSR;
261#endif // __WINDOWS__
262
f172cb82 263 int fd = wxOpen( fileName, flags, accessMode);
6294ac2e 264
65fe93d8 265 if ( CheckForError(fd) )
92980e90 266 {
fcea31d5 267 wxLogSysError(_("can't open file '%s'"), fileName);
a62848fd 268 return false;
49d5d881 269 }
769627d7
DS
270
271 Attach(fd);
272 return true;
c801d85f
KB
273}
274
275// close
61b02744 276bool wxFile::Close()
c801d85f 277{
49d5d881 278 if ( IsOpened() ) {
65fe93d8 279 if ( CheckForError(wxClose(m_fd)) )
1c193821 280 {
49d5d881
VZ
281 wxLogSysError(_("can't close file descriptor %d"), m_fd);
282 m_fd = fd_invalid;
a62848fd 283 return false;
49d5d881
VZ
284 }
285 else
286 m_fd = fd_invalid;
61b02744 287 }
61b02744 288
a62848fd 289 return true;
c801d85f
KB
290}
291
292// ----------------------------------------------------------------------------
293// read/write
294// ----------------------------------------------------------------------------
295
296// read
f8a586e0 297ssize_t wxFile::Read(void *pBuf, size_t nCount)
c801d85f 298{
49d5d881 299 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f 300
30984dea 301 ssize_t iRc = wxRead(m_fd, pBuf, nCount);
6294ac2e 302
65fe93d8 303 if ( CheckForError(iRc) )
02aef13c 304 {
49d5d881 305 wxLogSysError(_("can't read from file descriptor %d"), m_fd);
f8a586e0 306 return wxInvalidOffset;
49d5d881 307 }
02aef13c
VZ
308
309 return iRc;
c801d85f
KB
310}
311
312// write
30984dea 313size_t wxFile::Write(const void *pBuf, size_t nCount)
c801d85f 314{
49d5d881 315 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f 316
30984dea 317 ssize_t iRc = wxWrite(m_fd, pBuf, nCount);
6294ac2e 318
65fe93d8 319 if ( CheckForError(iRc) )
02aef13c 320 {
49d5d881 321 wxLogSysError(_("can't write to file descriptor %d"), m_fd);
02aef13c 322 iRc = 0;
49d5d881 323 }
02aef13c 324
30984dea 325 return iRc;
c801d85f
KB
326}
327
b1c67394
VZ
328bool wxFile::Write(const wxString& s, const wxMBConv& conv)
329{
330 const wxWX2MBbuf buf = s.mb_str(conv);
331 if ( !buf )
332 return false;
333
ae0e22dd 334#if wxUSE_UNICODE
227989f3 335 const size_t size = buf.length();
ae0e22dd
VZ
336#else
337 const size_t size = s.length();
338#endif
339
b1c67394
VZ
340 return Write(buf, size) == size;
341}
342
c801d85f
KB
343// flush
344bool wxFile::Flush()
345{
c8ccc915 346#ifdef HAVE_FSYNC
608a34bf
VZ
347 // fsync() only works on disk files and returns errors for pipes, don't
348 // call it then
349 if ( IsOpened() && GetKind() == wxFILE_KIND_DISK )
350 {
65fe93d8 351 if ( CheckForError(wxFsync(m_fd)) )
09914df7
VZ
352 {
353 wxLogSysError(_("can't flush file descriptor %d"), m_fd);
a62848fd 354 return false;
09914df7 355 }
49d5d881 356 }
c8ccc915 357#endif // HAVE_FSYNC
c801d85f 358
a62848fd 359 return true;
c801d85f
KB
360}
361
362// ----------------------------------------------------------------------------
363// seek
364// ----------------------------------------------------------------------------
365
366// seek
30984dea 367wxFileOffset wxFile::Seek(wxFileOffset ofs, wxSeekMode mode)
c801d85f 368{
9a83f860 369 wxASSERT_MSG( IsOpened(), wxT("can't seek on closed file") );
686a3ee0
VZ
370 wxCHECK_MSG( ofs != wxInvalidOffset || mode != wxFromStart,
371 wxInvalidOffset,
9a83f860 372 wxT("invalid absolute file offset") );
49d5d881 373
a1b82138 374 int origin;
49d5d881 375 switch ( mode ) {
a1b82138 376 default:
9a83f860 377 wxFAIL_MSG(wxT("unknown seek origin"));
a1b82138 378
49d5d881 379 case wxFromStart:
a1b82138 380 origin = SEEK_SET;
49d5d881
VZ
381 break;
382
383 case wxFromCurrent:
a1b82138 384 origin = SEEK_CUR;
49d5d881
VZ
385 break;
386
387 case wxFromEnd:
a1b82138 388 origin = SEEK_END;
49d5d881 389 break;
49d5d881
VZ
390 }
391
30984dea 392 wxFileOffset iRc = wxSeek(m_fd, ofs, origin);
65fe93d8 393 if ( CheckForError(iRc) )
02aef13c 394 {
49d5d881 395 wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
49d5d881 396 }
02aef13c
VZ
397
398 return iRc;
c801d85f
KB
399}
400
02aef13c 401// get current file offset
30984dea 402wxFileOffset wxFile::Tell() const
c801d85f 403{
49d5d881
VZ
404 wxASSERT( IsOpened() );
405
30984dea 406 wxFileOffset iRc = wxTell(m_fd);
65fe93d8 407 if ( CheckForError(iRc) )
02aef13c 408 {
49d5d881 409 wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
49d5d881 410 }
02aef13c
VZ
411
412 return iRc;
c801d85f
KB
413}
414
415// get current file length
30984dea 416wxFileOffset wxFile::Length() const
c801d85f 417{
49d5d881 418 wxASSERT( IsOpened() );
c801d85f 419
41f6f17d
VZ
420 // we use a special method for Linux systems where files in sysfs (i.e.
421 // those under /sys typically) return length of 4096 bytes even when
422 // they're much smaller -- this is a problem as it results in errors later
423 // when we try reading 4KB from them
424#ifdef __LINUX__
425 struct stat st;
426 if ( fstat(m_fd, &st) == 0 )
427 {
428 // returning 0 for the special files indicates to the caller that they
429 // are not seekable
430 return st.st_blocks ? st.st_size : 0;
431 }
432 //else: failed to stat, try the normal method
433#endif // __LINUX__
434
30984dea 435 wxFileOffset iRc = Tell();
02aef13c 436 if ( iRc != wxInvalidOffset ) {
f48a1159 437 wxFileOffset iLen = const_cast<wxFile *>(this)->SeekEnd();
02aef13c 438 if ( iLen != wxInvalidOffset ) {
49d5d881 439 // restore old position
02aef13c 440 if ( ((wxFile *)this)->Seek(iRc) == wxInvalidOffset ) {
49d5d881 441 // error
02aef13c 442 iLen = wxInvalidOffset;
49d5d881 443 }
c801d85f 444 }
c801d85f 445
49d5d881
VZ
446 iRc = iLen;
447 }
49d5d881 448
02aef13c
VZ
449 if ( iRc == wxInvalidOffset )
450 {
65fe93d8 451 // last error was already set by Tell()
49d5d881 452 wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
c801d85f 453 }
02aef13c
VZ
454
455 return iRc;
c801d85f
KB
456}
457
458// is end of file reached?
459bool wxFile::Eof() const
460{
49d5d881 461 wxASSERT( IsOpened() );
c801d85f 462
30984dea 463 wxFileOffset iRc;
61b02744 464
f172cb82 465#if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ )
61b02744 466 // @@ this doesn't work, of course, on unseekable file descriptors
30984dea 467 wxFileOffset ofsCur = Tell(),
49d5d881 468 ofsMax = Length();
1678ad78 469 if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
02aef13c 470 iRc = wxInvalidOffset;
61b02744 471 else
49d5d881
VZ
472 iRc = ofsCur == ofsMax;
473#else // Windows and "native" compiler
6294ac2e 474 iRc = wxEof(m_fd);
49d5d881 475#endif // Windows/Unix
c801d85f 476
43b2d5e7 477 if ( iRc == 0 )
b9daf00a 478 return false;
43b2d5e7
VZ
479
480 if ( iRc == wxInvalidOffset )
481 {
b9daf00a 482 wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd);
43b2d5e7
VZ
483 }
484 else if ( iRc != 1 )
485 {
9a83f860 486 wxFAIL_MSG(wxT("invalid eof() return value."));
43b2d5e7 487 }
c801d85f 488
a62848fd 489 return true;
c801d85f
KB
490}
491
492// ============================================================================
493// implementation of wxTempFile
494// ============================================================================
495
496// ----------------------------------------------------------------------------
497// construction
498// ----------------------------------------------------------------------------
44b62d54 499
c801d85f
KB
500wxTempFile::wxTempFile(const wxString& strName)
501{
49d5d881 502 Open(strName);
c801d85f
KB
503}
504
505bool wxTempFile::Open(const wxString& strName)
506{
44b62d54
VZ
507 // we must have an absolute filename because otherwise CreateTempFileName()
508 // would create the temp file in $TMP (i.e. the system standard location
509 // for the temp files) which might be on another volume/drive/mount and
510 // wxRename()ing it later to m_strName from Commit() would then fail
511 //
512 // with the absolute filename, the temp file is created in the same
513 // directory as this one which ensures that wxRename() may work later
514 wxFileName fn(strName);
515 if ( !fn.IsAbsolute() )
516 {
517 fn.Normalize(wxPATH_NORM_ABSOLUTE);
518 }
519
520 m_strName = fn.GetFullPath();
246037e2 521
44b62d54 522 m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file);
ade35f11
VZ
523
524 if ( m_strTemp.empty() )
525 {
526 // CreateTempFileName() failed
a62848fd 527 return false;
ade35f11 528 }
49d5d881 529
49d5d881 530#ifdef __UNIX__
ade35f11
VZ
531 // the temp file should have the same permissions as the original one
532 mode_t mode;
a62848fd 533
f6bcfd97 534 wxStructStat st;
ca11abde 535 if ( stat( (const char*) m_strName.fn_str(), &st) == 0 )
49d5d881 536 {
ade35f11 537 mode = st.st_mode;
49d5d881
VZ
538 }
539 else
540 {
ade35f11 541 // file probably didn't exist, just give it the default mode _using_
68164137 542 // user's umask (new files creation should respect umask)
ade35f11
VZ
543 mode_t mask = umask(0777);
544 mode = 0666 & ~mask;
545 umask(mask);
49d5d881 546 }
49d5d881 547
ca11abde 548 if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 )
fe99e285 549 {
5a3912f2 550#ifndef __OS2__
ade35f11 551 wxLogSysError(_("Failed to set temporary file permissions"));
5a3912f2 552#endif
fe99e285 553 }
49d5d881 554#endif // Unix
246037e2 555
a62848fd 556 return true;
c801d85f
KB
557}
558
559// ----------------------------------------------------------------------------
560// destruction
561// ----------------------------------------------------------------------------
562
563wxTempFile::~wxTempFile()
564{
49d5d881
VZ
565 if ( IsOpened() )
566 Discard();
c801d85f
KB
567}
568
569bool wxTempFile::Commit()
570{
49d5d881 571 m_file.Close();
c801d85f 572
f6bcfd97 573 if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) {
49d5d881 574 wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
a62848fd 575 return false;
49d5d881 576 }
c801d85f 577
f35746ce 578 if ( !wxRenameFile(m_strTemp, m_strName) ) {
49d5d881 579 wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
a62848fd 580 return false;
49d5d881 581 }
c801d85f 582
a62848fd 583 return true;
c801d85f
KB
584}
585
586void wxTempFile::Discard()
587{
49d5d881 588 m_file.Close();
f6bcfd97 589 if ( wxRemove(m_strTemp) != 0 )
af588446 590 {
49d5d881 591 wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
af588446 592 }
c801d85f 593}
ce4169a4 594
ade35f11 595#endif // wxUSE_FILE
cc985fac 596