]> git.saurik.com Git - wxWidgets.git/blob - src/common/file.cpp
Added (untested) support for sub-locales.
[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 #include "wx/defs.h"
24
25 #ifdef __BORLANDC__
26 #pragma hdrstop
27 #endif
28
29 // standard
30 #if defined(__WXMSW__) && !defined(__GNUWIN32__)
31 #include <io.h>
32
33 #ifndef __SALFORDC__
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
54 #endif
55
56 #include <windows.h> // for GetTempFileName
57 #elif (defined(__UNIX__) || defined(__GNUWIN32__))
58 #include <unistd.h>
59 #ifdef __GNUWIN32__
60 #include <windows.h>
61 #endif
62 #elif (defined(__WXSTUBS__))
63 // Have to ifdef this for different environments
64 #include <io.h>
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
72 #else
73 #error "Please specify the header with file functions declarations."
74 #endif //Win/UNIX
75
76 #include <stdio.h> // SEEK_xxx constants
77 #include <fcntl.h> // O_RDONLY &c
78
79 #ifndef __MWERKS__
80 #include <sys/types.h> // needed for stat
81 #include <sys/stat.h> // stat
82 #endif
83
84 // Microsoft compiler loves underscores, feed them to it
85 #ifdef _MSC_VER
86
87 #ifndef __MWERKS__
88
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
103
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
113
114 #endif
115
116 #define W_OK 2
117 #define R_OK 4
118 #else
119 #define tell(fd) lseek(fd, 0, SEEK_CUR)
120 #endif //_MSC_VER
121
122 #ifdef __BORLANDC__
123 #define W_OK 2
124 #define R_OK 4
125 #endif
126
127 // there is no distinction between text and binary files under Unix
128 #ifdef __UNIX__
129 #define O_BINARY (0)
130 #endif //__UNIX__
131
132
133 #ifdef __SALFORDC__
134 #include <unix.h>
135 #endif
136
137 // wxWindows
138 #include <wx/string.h>
139 #include <wx/intl.h>
140 #include <wx/file.h>
141 #include <wx/log.h>
142
143 #ifndef MAX_PATH
144 #define MAX_PATH 512
145 #endif
146
147 // ============================================================================
148 // implementation of wxFile
149 // ============================================================================
150
151 // ----------------------------------------------------------------------------
152 // static functions
153 // ----------------------------------------------------------------------------
154 bool wxFile::Exists(const char *name)
155 {
156 #ifdef __SALFORDC__
157 struct _stat st;
158 #else
159 struct stat st;
160 #endif
161
162 return !access(name, 0) && !stat((char*) name, &st) && (st.st_mode & S_IFREG);
163 }
164
165 bool wxFile::Access(const char *name, OpenMode mode)
166 {
167 int how = 0;
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;
183 }
184
185 // ----------------------------------------------------------------------------
186 // opening/closing
187 // ----------------------------------------------------------------------------
188
189 // ctors
190 wxFile::wxFile(const char *szFileName, OpenMode mode)
191 {
192 m_fd = fd_invalid;
193 m_error = FALSE;
194
195 Open(szFileName, mode);
196 }
197
198 // dtor
199 wxFile::~wxFile()
200 {
201 Close();
202 }
203
204 // create the file, fail if it already exists and bOverwrite
205 bool wxFile::Create(const char *szFileName, bool bOverwrite, int accessMode)
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
209 #ifdef __SALFORDC__
210 int fd = open(szFileName, O_WRONLY | O_CREAT |
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
216
217 if ( fd == -1 ) {
218 wxLogSysError(_("can't create file '%s'"), szFileName);
219 return FALSE;
220 }
221 else {
222 Attach(fd);
223 return TRUE;
224 }
225 }
226
227 // open the file
228 bool wxFile::Open(const char *szFileName, OpenMode mode, int accessMode)
229 {
230 int flags = O_BINARY;
231
232 switch ( mode ) {
233 case read:
234 flags |= O_RDONLY;
235 break;
236
237 case write:
238 flags |= O_WRONLY | O_CREAT | O_TRUNC;
239 break;
240
241 case write_append:
242 flags |= O_WRONLY | O_APPEND;
243 break;
244
245 case read_write:
246 flags |= O_RDWR;
247 break;
248 }
249
250 #ifdef __SALFORDC__
251 int fd = open(szFileName, flags);
252 #else
253 int fd = open(szFileName, flags, accessMode);
254 #endif
255
256 if ( fd == -1 ) {
257 wxLogSysError(_("can't open file '%s'"), szFileName);
258 return FALSE;
259 }
260 else {
261 Attach(fd);
262 return TRUE;
263 }
264 }
265
266 // close
267 bool wxFile::Close()
268 {
269 if ( IsOpened() ) {
270 if ( close(m_fd) == -1 ) {
271 wxLogSysError(_("can't close file descriptor %d"), m_fd);
272 m_fd = fd_invalid;
273 return FALSE;
274 }
275 else
276 m_fd = fd_invalid;
277 }
278
279 return TRUE;
280 }
281
282 // ----------------------------------------------------------------------------
283 // read/write
284 // ----------------------------------------------------------------------------
285
286 // read
287 off_t wxFile::Read(void *pBuf, off_t nCount)
288 {
289 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
290
291 #ifdef __MWERKS__
292 int iRc = ::read(m_fd, (char*) pBuf, nCount);
293 #else
294 int iRc = ::read(m_fd, pBuf, nCount);
295 #endif
296 if ( iRc == -1 ) {
297 wxLogSysError(_("can't read from file descriptor %d"), m_fd);
298 return wxInvalidOffset;
299 }
300 else
301 return (size_t)iRc;
302 }
303
304 // write
305 size_t wxFile::Write(const void *pBuf, size_t nCount)
306 {
307 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
308
309 #ifdef __MWERKS__
310 int iRc = ::write(m_fd, (const char*) pBuf, nCount);
311 #else
312 int iRc = ::write(m_fd, pBuf, nCount);
313 #endif
314 if ( iRc == -1 ) {
315 wxLogSysError(_("can't write to file descriptor %d"), m_fd);
316 m_error = TRUE;
317 return 0;
318 }
319 else
320 return iRc;
321 }
322
323 // flush
324 bool wxFile::Flush()
325 {
326 if ( IsOpened() ) {
327 #if (defined(_MSC_VER) && !defined(__MWERKS__)) || wxHAVE_FSYNC
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
336 }
337
338 return TRUE;
339 }
340
341 // ----------------------------------------------------------------------------
342 // seek
343 // ----------------------------------------------------------------------------
344
345 // seek
346 off_t wxFile::Seek(off_t ofs, wxSeekMode mode)
347 {
348 wxASSERT( IsOpened() );
349
350 int flag = -1;
351 switch ( mode ) {
352 case wxFromStart:
353 flag = SEEK_SET;
354 break;
355
356 case wxFromCurrent:
357 flag = SEEK_CUR;
358 break;
359
360 case wxFromEnd:
361 flag = SEEK_END;
362 break;
363
364 default:
365 wxFAIL_MSG(_("unknown seek origin"));
366 }
367
368 int iRc = lseek(m_fd, ofs, flag);
369 if ( iRc == -1 ) {
370 wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
371 return wxInvalidOffset;
372 }
373 else
374 return (off_t)iRc;
375 }
376
377 // get current off_t
378 off_t wxFile::Tell() const
379 {
380 wxASSERT( IsOpened() );
381
382 int iRc = tell(m_fd);
383 if ( iRc == -1 ) {
384 wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
385 return wxInvalidOffset;
386 }
387 else
388 return (off_t)iRc;
389 }
390
391 // get current file length
392 off_t wxFile::Length() const
393 {
394 wxASSERT( IsOpened() );
395
396 #if defined( _MSC_VER ) && !defined( __MWERKS__ )
397 int iRc = _filelength(m_fd);
398 #else
399 int iRc = tell(m_fd);
400 if ( iRc != -1 ) {
401 // @ have to use const_cast :-(
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 ) {
417 wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
418 return wxInvalidOffset;
419 }
420 else
421 return (off_t)iRc;
422 }
423
424 // is end of file reached?
425 bool wxFile::Eof() const
426 {
427 wxASSERT( IsOpened() );
428
429 int iRc;
430
431 #if defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__)
432 // @@ this doesn't work, of course, on unseekable file descriptors
433 off_t ofsCur = Tell(),
434 ofsMax = Length();
435 if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
436 iRc = -1;
437 else
438 iRc = ofsCur == ofsMax;
439 #else // Windows and "native" compiler
440 iRc = eof(m_fd);
441 #endif // Windows/Unix
442
443 switch ( iRc ) {
444 case 1:
445 break;
446
447 case 0:
448 return FALSE;
449
450 case -1:
451 wxLogSysError(_("can't determine if the end of file is reached on \
452 descriptor %d"), m_fd);
453 break;
454
455 default:
456 wxFAIL_MSG(_("invalid eof() return value."));
457 }
458
459 return TRUE;
460 }
461
462 // ============================================================================
463 // implementation of wxTempFile
464 // ============================================================================
465
466 // ----------------------------------------------------------------------------
467 // construction
468 // ----------------------------------------------------------------------------
469 wxTempFile::wxTempFile(const wxString& strName)
470 {
471 Open(strName);
472 }
473
474 bool wxTempFile::Open(const wxString& strName)
475 {
476 m_strName = strName;
477
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.
482 #if defined(__UNIX__) || defined(__WXSTUBS__)|| defined( __WXMAC__ )
483 static const char *szMktempSuffix = "XXXXXX";
484 m_strTemp << strName << szMktempSuffix;
485 mktemp((char *)m_strTemp.c_str()); // will do because length doesn't change
486 #else // Windows
487 wxString strPath;
488 wxSplitPath(strName, &strPath, NULL, NULL);
489 if ( strPath.IsEmpty() )
490 strPath = '.'; // GetTempFileName will fail if we give it empty string
491 #ifdef __WIN32__
492 if ( !GetTempFileName(strPath, "wx_",0, m_strTemp.GetWriteBuf(MAX_PATH)) )
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
497 wxLogLastError("GetTempFileName");
498 m_strTemp.UngetWriteBuf();
499 #endif // Windows/Unix
500
501 return m_file.Open(m_strTemp, wxFile::write);
502 }
503
504 // ----------------------------------------------------------------------------
505 // destruction
506 // ----------------------------------------------------------------------------
507
508 wxTempFile::~wxTempFile()
509 {
510 if ( IsOpened() )
511 Discard();
512 }
513
514 bool wxTempFile::Commit()
515 {
516 m_file.Close();
517
518 if ( wxFile::Exists(m_strName) && remove(m_strName) != 0 ) {
519 wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
520 return FALSE;
521 }
522
523 if ( rename(m_strTemp, m_strName) != 0 ) {
524 wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
525 return FALSE;
526 }
527
528 return TRUE;
529 }
530
531 void wxTempFile::Discard()
532 {
533 m_file.Close();
534 if ( remove(m_strTemp) != 0 )
535 wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
536 }