compilation fixes for Watcom+MGL+MS-DOS
[wxWidgets.git] / src / common / file.cpp
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
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 #if wxUSE_FILE
29
30 // standard
31 #if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__WXMICROWIN__)
32 #include <io.h>
33
34 #ifndef __SALFORDC__
35 #define WIN32_LEAN_AND_MEAN
36 #define NOSERVICE
37 #define NOIME
38 #define NOATOM
39 #define NOGDI
40 #define NOGDICAPMASKS
41 #define NOMETAFILE
42 #define NOMINMAX
43 #define NOMSG
44 #define NOOPENFILE
45 #define NORASTEROPS
46 #define NOSCROLL
47 #define NOSOUND
48 #define NOSYSMETRICS
49 #define NOTEXTMETRIC
50 #define NOWH
51 #define NOCOMM
52 #define NOKANJI
53 #define NOCRYPT
54 #define NOMCX
55 #endif
56
57 #elif (defined(__UNIX__) || defined(__GNUWIN32__))
58 #include <unistd.h>
59 #ifdef __GNUWIN32__
60 #include <windows.h>
61 #endif
62 #elif defined(__DOS__) && defined(__WATCOMC__)
63 #include <io.h>
64 char* mktemp(char *path) { return _mktemp(path); }
65 #elif (defined(__WXPM__))
66 #include <io.h>
67 #define W_OK 2
68 #define R_OK 4
69 #elif (defined(__WXSTUBS__))
70 // Have to ifdef this for different environments
71 #include <io.h>
72 #elif (defined(__WXMAC__))
73 #if __MSL__ < 0x6000
74 int access( const char *path, int mode ) { return 0 ; }
75 #else
76 int _access( const char *path, int mode ) { return 0 ; }
77 #endif
78 char* mktemp( char * path ) { return path ;}
79 #include <stat.h>
80 #define W_OK 2
81 #define R_OK 4
82 #include <unistd.h>
83 #else
84 #error "Please specify the header with file functions declarations."
85 #endif //Win/UNIX
86
87 #include <stdio.h> // SEEK_xxx constants
88 #include <fcntl.h> // O_RDONLY &c
89
90 #ifndef __MWERKS__
91 #include <sys/types.h> // needed for stat
92 #include <sys/stat.h> // stat
93 #elif ( defined(__MWERKS__) && defined(__WXMSW__) )
94 #include <sys/types.h> // needed for stat
95 #include <sys/stat.h> // stat
96 #endif
97
98 #if defined(__BORLANDC__) || defined(_MSC_VER)
99 #define W_OK 2
100 #define R_OK 4
101 #endif
102
103 // there is no distinction between text and binary files under Unix, so define
104 // O_BINARY as 0 if the system headers don't do it already
105 #if defined(__UNIX__) && !defined(O_BINARY)
106 #define O_BINARY (0)
107 #endif //__UNIX__
108
109 #ifdef __SALFORDC__
110 #include <unix.h>
111 #endif
112
113 #ifndef MAX_PATH
114 #define MAX_PATH 512
115 #endif
116
117 // some broken compilers don't have 3rd argument in open() and creat()
118 #ifdef __SALFORDC__
119 #define ACCESS(access)
120 #define stat _stat
121 #else // normal compiler
122 #define ACCESS(access) , (access)
123 #endif // Salford C
124
125 // wxWindows
126 #ifndef WX_PRECOMP
127 #include "wx/string.h"
128 #include "wx/intl.h"
129 #include "wx/log.h"
130 #endif // !WX_PRECOMP
131
132 #include "wx/filename.h"
133 #include "wx/file.h"
134
135 // ============================================================================
136 // implementation of wxFile
137 // ============================================================================
138
139 // ----------------------------------------------------------------------------
140 // static functions
141 // ----------------------------------------------------------------------------
142 bool wxFile::Exists(const wxChar *name)
143 {
144 wxStructStat st;
145 #if wxUSE_UNICODE && wxMBFILES
146 wxCharBuffer fname = wxConvFile.cWC2MB(name);
147
148 return !wxAccess(fname, 0) &&
149 !wxStat(wxMBSTRINGCAST fname, &st) &&
150 (st.st_mode & S_IFREG);
151
152 #else
153 return !wxAccess(name, 0) &&
154 !wxStat(name, &st) &&
155 (st.st_mode & S_IFREG);
156 #endif
157 }
158
159 bool wxFile::Access(const wxChar *name, OpenMode mode)
160 {
161 int how = 0;
162
163 switch ( mode ) {
164 case read:
165 how = R_OK;
166 break;
167
168 case write:
169 how = W_OK;
170 break;
171
172 default:
173 wxFAIL_MSG(wxT("bad wxFile::Access mode parameter."));
174 }
175
176 return wxAccess(wxFNCONV(name), how) == 0;
177 }
178
179 // ----------------------------------------------------------------------------
180 // opening/closing
181 // ----------------------------------------------------------------------------
182
183 // ctors
184 wxFile::wxFile(const wxChar *szFileName, OpenMode mode)
185 {
186 m_fd = fd_invalid;
187 m_error = FALSE;
188
189 Open(szFileName, mode);
190 }
191
192 // create the file, fail if it already exists and bOverwrite
193 bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode)
194 {
195 // if bOverwrite we create a new file or truncate the existing one,
196 // otherwise we only create the new file and fail if it already exists
197 #if defined(__WXMAC__) && !defined(__UNIX__)
198 // Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace
199 // int fd = open(wxUnix2MacFilename( szFileName ), O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access);
200 int fd = creat( szFileName , accessMode);
201 #else
202 int fd = wxOpen(wxFNCONV(szFileName),
203 O_BINARY | O_WRONLY | O_CREAT |
204 (bOverwrite ? O_TRUNC : O_EXCL)
205 ACCESS(accessMode));
206 #endif
207 if ( fd == -1 ) {
208 wxLogSysError(_("can't create file '%s'"), szFileName);
209 return FALSE;
210 }
211 else {
212 Attach(fd);
213 return TRUE;
214 }
215 }
216
217 // open the file
218 bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode)
219 {
220 int flags = O_BINARY;
221
222 switch ( mode ) {
223 case read:
224 flags |= O_RDONLY;
225 break;
226
227 case write_append:
228 if ( wxFile::Exists(szFileName) )
229 {
230 flags |= O_WRONLY | O_APPEND;
231 break;
232 }
233 //else: fall through as write_append is the same as write if the
234 // file doesn't exist
235
236 case write:
237 flags |= O_WRONLY | O_CREAT | O_TRUNC;
238 break;
239
240 case write_excl:
241 flags |= O_WRONLY | O_CREAT | O_EXCL;
242 break;
243
244 case read_write:
245 flags |= O_RDWR;
246 break;
247 }
248
249 int fd = wxOpen(wxFNCONV(szFileName), flags ACCESS(accessMode));
250 if ( fd == -1 ) {
251 wxLogSysError(_("can't open file '%s'"), szFileName);
252 return FALSE;
253 }
254 else {
255 Attach(fd);
256 return TRUE;
257 }
258 }
259
260 // close
261 bool wxFile::Close()
262 {
263 if ( IsOpened() ) {
264 if ( close(m_fd) == -1 ) {
265 wxLogSysError(_("can't close file descriptor %d"), m_fd);
266 m_fd = fd_invalid;
267 return FALSE;
268 }
269 else
270 m_fd = fd_invalid;
271 }
272
273 return TRUE;
274 }
275
276 // ----------------------------------------------------------------------------
277 // read/write
278 // ----------------------------------------------------------------------------
279
280 // read
281 off_t wxFile::Read(void *pBuf, off_t nCount)
282 {
283 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
284
285 #ifdef __MWERKS__
286 int iRc = ::read(m_fd, (char*) pBuf, nCount);
287 #else
288 int iRc = ::read(m_fd, pBuf, nCount);
289 #endif
290 if ( iRc == -1 ) {
291 wxLogSysError(_("can't read from file descriptor %d"), m_fd);
292 return wxInvalidOffset;
293 }
294 else
295 return (size_t)iRc;
296 }
297
298 // write
299 size_t wxFile::Write(const void *pBuf, size_t nCount)
300 {
301 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
302
303 #ifdef __MWERKS__
304 #if __MSL__ >= 0x6000
305 int iRc = ::write(m_fd, (void*) pBuf, nCount);
306 #else
307 int iRc = ::write(m_fd, (const char*) pBuf, nCount);
308 #endif
309 #else
310 int iRc = ::write(m_fd, pBuf, nCount);
311 #endif
312 if ( iRc == -1 ) {
313 wxLogSysError(_("can't write to file descriptor %d"), m_fd);
314 m_error = TRUE;
315 return 0;
316 }
317 else
318 return iRc;
319 }
320
321 // flush
322 bool wxFile::Flush()
323 {
324 if ( IsOpened() ) {
325 #if defined(__VISUALC__) || wxHAVE_FSYNC
326 if ( wxFsync(m_fd) == -1 )
327 {
328 wxLogSysError(_("can't flush file descriptor %d"), m_fd);
329 return FALSE;
330 }
331 #else // no fsync
332 // just do nothing
333 #endif // fsync
334 }
335
336 return TRUE;
337 }
338
339 // ----------------------------------------------------------------------------
340 // seek
341 // ----------------------------------------------------------------------------
342
343 // seek
344 off_t wxFile::Seek(off_t ofs, wxSeekMode mode)
345 {
346 wxASSERT( IsOpened() );
347
348 int origin;
349 switch ( mode ) {
350 default:
351 wxFAIL_MSG(_("unknown seek origin"));
352
353 case wxFromStart:
354 origin = SEEK_SET;
355 break;
356
357 case wxFromCurrent:
358 origin = SEEK_CUR;
359 break;
360
361 case wxFromEnd:
362 origin = SEEK_END;
363 break;
364 }
365
366 int iRc = lseek(m_fd, ofs, origin);
367 if ( iRc == -1 ) {
368 wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
369 return wxInvalidOffset;
370 }
371 else
372 return (off_t)iRc;
373 }
374
375 // get current off_t
376 off_t wxFile::Tell() const
377 {
378 wxASSERT( IsOpened() );
379
380 int iRc = wxTell(m_fd);
381 if ( iRc == -1 ) {
382 wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
383 return wxInvalidOffset;
384 }
385 else
386 return (off_t)iRc;
387 }
388
389 // get current file length
390 off_t wxFile::Length() const
391 {
392 wxASSERT( IsOpened() );
393
394 #ifdef __VISUALC__
395 int iRc = _filelength(m_fd);
396 #else // !VC++
397 int iRc = wxTell(m_fd);
398 if ( iRc != -1 ) {
399 // @ have to use const_cast :-(
400 int iLen = ((wxFile *)this)->SeekEnd();
401 if ( iLen != -1 ) {
402 // restore old position
403 if ( ((wxFile *)this)->Seek(iRc) == -1 ) {
404 // error
405 iLen = -1;
406 }
407 }
408
409 iRc = iLen;
410 }
411 #endif // VC++
412
413 if ( iRc == -1 ) {
414 wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
415 return wxInvalidOffset;
416 }
417 else
418 return (off_t)iRc;
419 }
420
421 // is end of file reached?
422 bool wxFile::Eof() const
423 {
424 wxASSERT( IsOpened() );
425
426 int iRc;
427
428 #if defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__)
429 // @@ this doesn't work, of course, on unseekable file descriptors
430 off_t ofsCur = Tell(),
431 ofsMax = Length();
432 if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
433 iRc = -1;
434 else
435 iRc = ofsCur == ofsMax;
436 #else // Windows and "native" compiler
437 iRc = eof(m_fd);
438 #endif // Windows/Unix
439
440 switch ( iRc ) {
441 case 1:
442 break;
443
444 case 0:
445 return FALSE;
446
447 case -1:
448 wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd);
449 break;
450
451 default:
452 wxFAIL_MSG(_("invalid eof() return value."));
453 }
454
455 return TRUE;
456 }
457
458 // ============================================================================
459 // implementation of wxTempFile
460 // ============================================================================
461
462 // ----------------------------------------------------------------------------
463 // construction
464 // ----------------------------------------------------------------------------
465 wxTempFile::wxTempFile(const wxString& strName)
466 {
467 Open(strName);
468 }
469
470 bool wxTempFile::Open(const wxString& strName)
471 {
472 m_strName = strName;
473
474 m_strTemp = wxFileName::CreateTempFileName(strName);
475
476 if ( m_strTemp.empty() )
477 {
478 // CreateTempFileName() failed
479 return FALSE;
480 }
481
482 // actually open the file now (it must already exist)
483 if ( !m_file.Open(m_strTemp, wxFile::write) )
484 {
485 // opening existing file failed?
486 return FALSE;
487 }
488
489 #ifdef __UNIX__
490 // the temp file should have the same permissions as the original one
491 mode_t mode;
492
493 wxStructStat st;
494 if ( stat(strName.fn_str(), &st) == 0 )
495 {
496 mode = st.st_mode;
497 }
498 else
499 {
500 // file probably didn't exist, just give it the default mode _using_
501 // user's umask (new files creation should respect umask)
502 mode_t mask = umask(0777);
503 mode = 0666 & ~mask;
504 umask(mask);
505 }
506
507 if ( chmod(m_strTemp.mb_str(), mode) == -1 )
508 {
509 wxLogSysError(_("Failed to set temporary file permissions"));
510 }
511 #endif // Unix
512
513 return TRUE;
514 }
515
516 // ----------------------------------------------------------------------------
517 // destruction
518 // ----------------------------------------------------------------------------
519
520 wxTempFile::~wxTempFile()
521 {
522 if ( IsOpened() )
523 Discard();
524 }
525
526 bool wxTempFile::Commit()
527 {
528 m_file.Close();
529
530 if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) {
531 wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
532 return FALSE;
533 }
534
535 if ( wxRename(m_strTemp, m_strName) != 0 ) {
536 wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
537 return FALSE;
538 }
539
540 return TRUE;
541 }
542
543 void wxTempFile::Discard()
544 {
545 m_file.Close();
546 if ( wxRemove(m_strTemp) != 0 )
547 wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
548 }
549
550 #endif // wxUSE_FILE
551