4 * Operating System classes implementation
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
30 * Revision 1.88 2007/04/20 07:18:00 csoutheren
31 * Applied 1703620 - Make PFile::Open() create file with unique name as intended
32 * Thanks to Fabrizio Ammollo
34 * Revision 1.87 2007/03/08 05:35:52 csoutheren
35 * Applied 1666290 - patch for bug thread issue
36 * Thanks to Frederic Heem
38 * Revision 1.86 2006/06/21 03:28:44 csoutheren
39 * Various cleanups thanks for Frederic Heem
41 * Revision 1.85 2005/11/30 12:47:42 csoutheren
42 * Removed tabs, reformatted some code, and changed tags for Doxygen
44 * Revision 1.84 2005/11/25 02:29:54 csoutheren
45 * Applied patch #1353487 by Hannes Friederich
48 * Revision 1.83 2004/09/23 05:00:10 csoutheren
49 * Extra proofing against possible NULL pointers
51 * Revision 1.82 2004/04/03 23:53:10 csoutheren
52 * Added various changes to improce compatibility with the Sun Forte compiler
53 * Thanks to Brian Cameron
54 * Added detection of readdir_r version
56 * Revision 1.81 2004/04/01 12:51:11 csoutheren
57 * Fixed problem with args to access, thanks to Borko Jandras
59 * Revision 1.80 2004/01/07 21:30:30 dsandras
60 * Applied patch from Miguel Rodriguez Perez <migrax@terra.es> to remove problematic PAssert failing in cases where it shouldn't.
62 * Revision 1.79 2003/09/17 01:18:04 csoutheren
63 * Removed recursive include file system and removed all references
64 * to deprecated coooperative threading support
66 * Revision 1.78 2003/05/01 06:08:36 robertj
67 * Fixed concurrency problem with some time functions, thanks chad@broadmind.com
69 * Revision 1.77 2003/01/24 10:21:06 robertj
70 * Fixed issues in RTEMS support, thanks Vladimir Nesic
72 * Revision 1.76 2002/11/22 10:14:07 robertj
73 * QNX port, thanks Xiaodan Tang
75 * Revision 1.75 2002/11/20 01:55:06 robertj
76 * Fixed to follow new semantics of GetPath(), first entry is volume which on
77 * UNix machines is always an empty string. Also collapses consecutive
78 * slashes as they are meaningless.
80 * Revision 1.74 2002/11/19 11:21:30 robertj
81 * Changed PFilePath so can be empty string, indicating illegal path.
82 * Added function to extract a path as an array of directories components.
84 * Revision 1.73 2002/10/22 07:42:52 robertj
85 * Added extra debugging for file handle and thread leak detection.
87 * Revision 1.72 2002/10/17 13:44:27 robertj
88 * Port to RTEMS, thanks Vladimir Nesic.
90 * Revision 1.71 2002/10/17 12:57:24 robertj
91 * Added ability to increase maximum file handles on a process.
93 * Revision 1.70 2002/10/10 04:43:44 robertj
94 * VxWorks port, thanks Martijn Roest
96 * Revision 1.69 2002/06/06 09:28:42 robertj
97 * Fixed problems with canonicalising directories now PINDEX is signed.
99 * Revision 1.68 2002/02/11 02:26:54 craigs
100 * Fixed problem with reading lines of length > 100 chares from text files
101 * Thanks to Ohnuma Masato
103 * Revision 1.67 2002/01/26 23:58:15 craigs
104 * Changed for GCC 3.0 compatibility, thanks to manty@manty.net
106 * Revision 1.66 2001/10/11 02:20:54 robertj
107 * Added IRIX support (no audio/video), thanks Andre Schulze.
109 * Revision 1.65 2001/09/18 05:56:03 robertj
110 * Fixed numerous problems with thread suspend/resume and signals handling.
112 * Revision 1.64 2001/09/04 04:15:44 robertj
113 * Fixed PFileInfo (stat) of file name that is dangling symlink.
115 * Revision 1.63 2001/08/11 15:38:43 rogerh
116 * Add Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
118 * Revision 1.62 2001/06/30 06:59:07 yurik
119 * Jac Goudsmit from Be submit these changes 6/28. Implemented by Yuri Kiryanov
121 * Revision 1.61 2001/05/29 03:35:16 craigs
122 * Changed to not tempnam to avoid linker warning on new Linux systems
124 * Revision 1.60 2001/03/12 02:35:20 robertj
125 * Fixed PDirectory::Exists so only returns TRUE if a directory and not file.
127 * Revision 1.59 2001/02/23 07:16:36 rogerh
128 * Darwin (MACOS X) does not have thread safe localtime_t() and gmtime_r()
129 * functions. Use the unsafe localtime() and gmtime() calls for now.
131 * Revision 1.58 2001/02/13 06:59:57 robertj
132 * Fixed problem with operator= in PDirectory class, part of larger change previously made.
134 * Revision 1.57 2001/02/13 05:15:31 robertj
135 * Fixed problem with operator= in container classes. Some containers will
136 * break unless the copy is virtual (eg PStringStream's buffer pointers) so
137 * needed to add a new AssignContents() function to all containers.
139 * Revision 1.56 2000/09/11 22:49:31 robertj
140 * Fixed bug where last char was always removed in mkdir() instead of only if '/'.
142 * Revision 1.55 2000/06/21 01:01:22 robertj
143 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
145 * Revision 1.54 2000/04/19 00:13:53 robertj
148 * Revision 1.53 2000/04/09 18:19:23 rogerh
149 * Add my changes for NetBSD support.
151 * Revision 1.52 2000/04/06 12:11:32 rogerh
152 * MacOS X support submitted by Kevin Packard
154 * Revision 1.51 2000/04/05 02:55:11 robertj
155 * Added microseconds to PTime class.
157 * Revision 1.50 2000/03/08 12:17:09 rogerh
158 * Add OpenBSD support
160 * Revision 1.49 2000/02/24 11:03:49 robertj
161 * Fixed warning on Linux systems about _REENTRANT
163 * Revision 1.48 1999/08/17 07:37:36 robertj
164 * Fixed inlines so are inlined for optimised version
166 * Revision 1.47 1999/06/28 09:28:02 robertj
167 * Portability issues, especially n BeOS (thanks Yuri!)
169 * Revision 1.46 1999/06/26 08:21:12 robertj
170 * Fixed bug in PFilePath::SetType finding dots outside of file name in path.
172 * Revision 1.45 1999/06/14 08:39:57 robertj
173 * Added PConsoleChannel class for access to stdin/stdout/stderr
175 * Revision 1.44 1999/06/09 04:08:46 robertj
176 * Added support for opening stdin/stdout/stderr as PFile objects.
178 * Revision 1.43 1999/02/22 13:26:53 robertj
181 * Revision 1.42 1998/12/12 01:06:24 robertj
182 * Fixed off by one error in month on FreeBSD platform
184 * Revision 1.41 1998/11/30 21:51:43 robertj
185 * New directory structure.
187 * Revision 1.40 1998/11/26 11:54:16 robertj
188 * Fixed error return on PFile::GetInfo
190 * Revision 1.39 1998/11/24 09:39:09 robertj
193 * Revision 1.38 1998/11/10 13:00:52 robertj
194 * Fixed strange problems with readdir_r usage.
196 * Revision 1.37 1998/11/06 04:44:46 robertj
197 * Solaris compatibility
199 * Revision 1.36 1998/11/05 12:03:13 robertj
200 * Fixed solaris compatibility and Linux warning on readdir_r function.
202 * Revision 1.35 1998/11/05 09:05:55 craigs
203 * Changed directory routines to use reenttrant functions, and added PDirectory::GetParent
205 * Revision 1.34 1998/09/24 07:39:49 robertj
206 * Removed file that only had #pragma implmentation for PTextFile and nothing else.
208 * Revision 1.33 1998/09/24 04:12:12 robertj
209 * Added open software license.
215 #pragma implementation "timer.h"
216 #pragma implementation "pdirect.h"
217 #pragma implementation "file.h"
218 #pragma implementation "textfile.h"
219 #pragma implementation "conchan.h"
220 #pragma implementation "ptime.h"
221 #pragma implementation "timeint.h"
222 #pragma implementation "filepath.h"
223 #pragma implementation "lists.h"
224 #pragma implementation "pstring.h"
225 #pragma implementation "dict.h"
226 #pragma implementation "array.h"
227 #pragma implementation "object.h"
228 #pragma implementation "contain.h"
234 #elif defined(P_SOLARIS)
235 #define _POSIX_PTHREAD_SEMANTICS
243 #include <sys/times.h>
246 #include <sys/time.h>
255 #if (__GNUC_MINOR__ < 7 && __GNUC__ < 3)
256 #include <localeinfo.h>
258 #define P_USE_LANGINFO
261 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS)
262 #define P_USE_STRFTIME
264 #include <sys/param.h>
265 #include <sys/mount.h>
267 #elif defined(P_HPUX9)
268 #define P_USE_LANGINFO
271 #define P_USE_STRFTIME
274 #include <sys/stat.h>
275 #include <sys/statfs.h>
277 #elif defined(P_SOLARIS)
278 #define P_USE_LANGINFO
279 #include <sys/timeb.h>
280 #include <sys/statvfs.h>
281 #include <sys/mnttab.h>
283 #elif defined(P_SUN4)
284 #include <sys/timeb.h>
286 #elif defined(__BEOS__)
287 #define P_USE_STRFTIME
289 #elif defined(P_IRIX)
290 #define P_USE_LANGINFO
291 #include <sys/stat.h>
292 #include <sys/statfs.h>
296 #elif defined(P_VXWORKS)
297 #define P_USE_STRFTIME
299 #elif defined(P_RTEMS)
300 #define P_USE_STRFTIME
303 #define random() rand()
304 #define srandom(a) srand(a)
307 #include <sys/dcmd_blk.h>
308 #include <sys/statvfs.h>
309 #define P_USE_STRFTIME
312 #ifdef P_USE_LANGINFO
313 #include <langinfo.h>
316 #define LINE_SIZE_STEP 100
318 #define DEFAULT_FILE_MODE (S_IRUSR|S_IWUSR|S_IROTH|S_IRGRP)
320 #include <ptlib/pprocess.h>
323 #include "ptlib/osutil.inl"
325 #include "ptlib/win32/ptlib/ptlib.inl"
327 #include "ptlib/unix/ptlib/ptlib.inl"
333 int on_exit(void (*f
)(void), caddr_t
);
334 int atexit(void (*f
)(void))
336 return on_exit(f
, 0);
338 static char *tzname
[2] = { "STD", "DST" };
345 static PMutex waterMarkMutex
;
346 static int lowWaterMark
= INT_MAX
;
347 static int highWaterMark
= 0;
349 int PX_NewHandle(const char * clsName
, int fd
)
354 PWaitAndSignal
m(waterMarkMutex
);
356 if (fd
> highWaterMark
) {
360 int maxHandles
= PProcess::Current().GetMaxHandles();
361 if (fd
< (maxHandles
-maxHandles
/20))
362 PTRACE(4, "PWLib\tFile handle high water mark set: " << fd
<< ' ' << clsName
);
364 PTRACE(1, "PWLib\tFile handle high water mark within 5% of maximum: " << fd
<< ' ' << clsName
);
367 if (fd
< lowWaterMark
) {
369 PTRACE(4, "PWLib\tFile handle low water mark set: " << fd
<< ' ' << clsName
);
376 static PString
CanonicaliseDirectory (const PString
& path
)
379 PString canonical_path
;
382 canonical_path
= '/';
384 char *p
= getcwd(canonical_path
.GetPointer(P_MAX_PATH
), P_MAX_PATH
);
385 PAssertOS (p
!= NULL
);
387 // if the path doesn't end in a slash, add one
388 if (canonical_path
[canonical_path
.GetLength()-1] != '/')
389 canonical_path
+= '/';
392 const char * ptr
= path
;
397 while (*ptr
== '/' && *ptr
!= '\0')
400 // finished if end of string
404 // collect non-slash characters
406 while (*end
!= '/' && *end
!= '\0')
409 // make a string out of the element
410 PString
element(ptr
, end
- ptr
);
412 if (element
== "..") {
413 PINDEX last_char
= canonical_path
.GetLength()-1;
415 canonical_path
= canonical_path
.Left(canonical_path
.FindLast('/', last_char
-1)+1);
416 } else if (element
== "." || element
== "") {
418 canonical_path
+= element
;
419 canonical_path
+= '/';
424 return canonical_path
;
428 static PString
CanonicaliseFilename(const PString
& filename
)
430 if (filename
.IsEmpty())
436 // if there is a slash in the string, extract the dirname
437 if ((p
= filename
.FindLast('/')) != P_MAX_INDEX
) {
438 dirname
= filename(0,p
);
439 while (filename
[p
] == '/')
444 return CanonicaliseDirectory(dirname
) + filename(p
, P_MAX_INDEX
);
448 PInt64
PString::AsInt64(unsigned base
) const
451 #if defined(P_SOLARIS) || defined(__BEOS__) || defined (P_AIX) || defined(P_IRIX) || defined (P_QNX)
452 return strtoll(theArray
, &dummy
, base
);
453 #elif defined(P_VXWORKS) || defined(P_RTEMS)
454 return strtol(theArray
, &dummy
, base
);
456 return strtoq(theArray
, &dummy
, base
);
460 PUInt64
PString::AsUnsigned64(unsigned base
) const
463 #if defined(P_SOLARIS) || defined(__BEOS__) || defined (P_AIX) || defined (P_IRIX) || defined (P_QNX)
464 return strtoull(theArray
, &dummy
, base
);
465 #elif defined(P_VXWORKS) || defined(P_RTEMS)
466 return strtoul(theArray
, &dummy
, base
);
468 return strtouq(theArray
, &dummy
, base
);
473 ///////////////////////////////////////////////////////////////////////////////
478 PTimeInterval
PTimer::Tick()
483 clock_gettime(0,&ts
);
484 return (int)(ts
.tv_sec
*10000) + ts
.tv_nsec
/100000L;
487 ::gettimeofday (&tv
, NULL
);
488 return (PInt64
)(tv
.tv_sec
) * 1000 + tv
.tv_usec
/1000L;
494 ///////////////////////////////////////////////////////////////////////////////
499 void PDirectory::CopyContents(const PDirectory
& d
)
501 if (d
.entryInfo
== NULL
)
504 entryInfo
= new PFileInfo
;
505 *entryInfo
= *d
.entryInfo
;
511 void PDirectory::Close()
513 if (directory
!= NULL
) {
514 PAssert(closedir(directory
) == 0, POperatingSystemError
);
518 if (entryBuffer
!= NULL
) {
523 if (entryInfo
!= NULL
) {
529 void PDirectory::Construct ()
535 PString::AssignContents(CanonicaliseDirectory(*this));
538 BOOL
PDirectory::Open(int ScanMask
)
541 if (directory
!= NULL
)
546 if ((directory
= opendir(theArray
)) == NULL
)
549 entryBuffer
= (struct dirent
*)malloc(sizeof(struct dirent
) + P_MAX_PATH
);
550 entryInfo
= new PFileInfo
;
560 BOOL
PDirectory::Next()
562 if (directory
== NULL
)
567 struct dirent
* entryPtr
;
568 entryBuffer
->d_name
[0] = '\0';
569 #if P_HAS_POSIX_READDIR_R == 3
570 if (::readdir_r(directory
, entryBuffer
, &entryPtr
) != 0)
572 if (entryPtr
!= entryBuffer
)
574 #elif P_HAS_POSIX_READDIR_R == 2
575 entryPtr
= ::readdir_r(directory
, entryBuffer
);
576 if (entryPtr
== NULL
)
579 if ((entryPtr
= ::readdir(directory
)) == NULL
)
581 *entryBuffer
= *entryPtr
;
582 strcpy(entryBuffer
->d_name
, entryPtr
->d_name
);
584 } while (strcmp(entryBuffer
->d_name
, "." ) == 0 || strcmp(entryBuffer
->d_name
, "..") == 0);
586 /* Ignore this file if we can't get info about it */
587 if (PFile::GetInfo(*this+entryBuffer
->d_name
, *entryInfo
) == 0)
590 if (scanMask
== PFileInfo::AllPermissions
)
592 } while ((entryInfo
->type
& scanMask
) == 0);
598 BOOL
PDirectory::IsSubDir() const
600 if (entryInfo
== NULL
)
603 return entryInfo
->type
== PFileInfo::SubDirectory
;
606 BOOL
PDirectory::Restart(int newScanMask
)
608 scanMask
= newScanMask
;
609 if (directory
!= NULL
)
610 rewinddir(directory
);
614 PString
PDirectory::GetEntryName() const
616 if (entryBuffer
== NULL
)
619 return entryBuffer
->d_name
;
623 BOOL
PDirectory::GetInfo(PFileInfo
& info
) const
625 if (entryInfo
== NULL
)
633 BOOL
PDirectory::Exists(const PString
& p
)
636 if (stat((const char *)p
, &sbuf
) != 0)
639 return S_ISDIR(sbuf
.st_mode
);
643 BOOL
PDirectory::Create(const PString
& p
, int perm
)
645 PAssert(!p
.IsEmpty(), "attempt to create dir with empty name");
646 PINDEX last
= p
.GetLength()-1;
651 return mkdir(str
) == 0;
653 return mkdir(str
, perm
) == 0;
657 BOOL
PDirectory::Remove(const PString
& p
)
659 PAssert(!p
.IsEmpty(), "attempt to remove dir with empty name");
660 PString str
= p
.Left(p
.GetLength()-1);
661 return rmdir(str
) == 0;
664 PString
PDirectory::GetVolume() const
672 if ((fd
= open(operator+("."), O_RDONLY
)) != -1) {
674 devctl(fd
, DCMD_FSYS_MOUNTED_ON
, mounton
, 256, 0);
676 volume
= strdup(mounton
);
681 if (stat(operator+("."), &status
) != -1) {
682 dev_t my_dev
= status
.st_dev
;
684 #if defined(P_LINUX) || defined(P_IRIX)
686 FILE * fp
= setmntent(MOUNTED
, "r");
689 while ((mnt
= getmntent(fp
)) != NULL
) {
690 if (stat(mnt
->mnt_dir
, &status
) != -1 && status
.st_dev
== my_dev
) {
691 volume
= mnt
->mnt_fsname
;
698 #elif defined(P_SOLARIS)
700 FILE * fp
= fopen("/etc/mnttab", "r");
703 while (getmntent(fp
, &mnt
) == 0) {
704 if (stat(mnt
.mnt_mountp
, &status
) != -1 && status
.st_dev
== my_dev
) {
705 volume
= mnt
.mnt_special
;
712 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS)
715 int count
= getmntinfo(&mnt
, MNT_NOWAIT
);
716 for (int i
= 0; i
< count
; i
++) {
717 if (stat(mnt
[i
].f_mntonname
, &status
) != -1 && status
.st_dev
== my_dev
) {
718 volume
= mnt
[i
].f_mntfromname
;
723 #elif defined (P_AIX)
727 while ((fs
= getfsent()) != NULL
) {
728 if (stat(fs
->fs_file
, &status
) != -1 && status
.st_dev
== my_dev
) {
729 volume
= fs
->fs_spec
;
735 #elif defined (P_VXWORKS)
737 PAssertAlways("Get Volume - not implemented for VxWorks");
738 return PString::Empty();
741 #warning Platform requires implemetation of GetVolume()
750 BOOL
PDirectory::GetVolumeSpace(PInt64
& total
, PInt64
& free
, DWORD
& clusterSize
) const
752 #if defined(P_LINUX) || defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS)
756 if (statfs(operator+("."), &fs
) == -1)
759 clusterSize
= fs
.f_bsize
;
760 total
= fs
.f_blocks
*(PInt64
)fs
.f_bsize
;
761 free
= fs
.f_bavail
*(PInt64
)fs
.f_bsize
;
764 #elif defined(P_AIX) || defined(P_VXWORKS)
767 if (statfs((char *) ((const char *)operator+(".") ), &fs
) == -1)
770 clusterSize
= fs
.f_bsize
;
771 total
= fs
.f_blocks
*(PInt64
)fs
.f_bsize
;
772 free
= fs
.f_bavail
*(PInt64
)fs
.f_bsize
;
775 #elif defined(P_SOLARIS)
778 if (statvfs(operator+("."), &buf
) != 0)
781 clusterSize
= buf
.f_frsize
;
782 total
= buf
.f_blocks
* buf
.f_frsize
;
783 free
= buf
.f_bfree
* buf
.f_frsize
;
787 #elif defined(P_IRIX)
791 if (statfs(operator+("."), &fs
, sizeof(struct statfs
), 0) == -1)
794 clusterSize
= fs
.f_bsize
;
795 total
= fs
.f_blocks
*(PInt64
)fs
.f_bsize
;
796 free
= fs
.f_bfree
*(PInt64
)fs
.f_bsize
;
803 if (statvfs(operator+("."), &fs
) == -1)
806 clusterSize
= fs
.f_bsize
;
807 total
= fs
.f_blocks
*(PInt64
)fs
.f_bsize
;
808 free
= fs
.f_bavail
*(PInt64
)fs
.f_bsize
;
813 #warning Platform requires implemetation of GetVolumeSpace()
819 PDirectory
PDirectory::GetParent() const
827 PStringArray
PDirectory::GetPath() const
834 PStringArray tokens
= Tokenise("/");
836 path
.SetSize(tokens
.GetSize()+1);
838 PINDEX count
= 1; // First path field is volume name, empty under unix
839 for (PINDEX i
= 0; i
< tokens
.GetSize(); i
++) {
841 path
[count
++] = tokens
[i
];
850 ///////////////////////////////////////////////////////////////////////////////
855 void PFile::SetFilePath(const PString
& newName
)
859 if ((p
= newName
.FindLast('/')) == P_MAX_INDEX
)
860 path
= CanonicaliseDirectory("") + newName
;
862 path
= CanonicaliseDirectory(newName(0,p
)) + newName(p
+1, P_MAX_INDEX
);
866 BOOL
PFile::Open(OpenMode mode
, int opt
)
873 removeOnClose
= (opt
& Temporary
) != 0;
875 if (path
.IsEmpty()) {
876 char templateStr
[3+6+1];
877 strcpy(templateStr
, "PWLXXXXXX");
881 memset(&_reent_data
, 0, sizeof(_reent_data
));
882 os_handle
= _mkstemp_r(&_reent_data
, templateStr
);
884 os_handle
= mkstemp(templateStr
);
886 if (!ConvertOSError(os_handle
))
891 static int number
= 0;
892 sprintf(templateStr
+3, "%06d", number
++);
901 if (opt
== ModeDefault
)
906 if (opt
== ModeDefault
)
907 opt
= Create
|Truncate
;
911 if (opt
== ModeDefault
)
916 PAssertAlways(PInvalidParameter
);
918 if ((opt
&Create
) != 0)
920 if ((opt
&Exclusive
) != 0)
922 if ((opt
&Truncate
) != 0)
926 if (!ConvertOSError(os_handle
= PX_NewHandle(GetClass(), ::open(path
, oflags
, DEFAULT_FILE_MODE
))))
931 return ConvertOSError(::fcntl(os_handle
, F_SETFD
, 1));
938 BOOL
PFile::SetLength(off_t len
)
940 return ConvertOSError(ftruncate(GetHandle(), len
));
944 BOOL
PFile::Rename(const PFilePath
& oldname
, const PString
& newname
, BOOL force
)
946 if (newname
.Find('/') != P_MAX_INDEX
) {
951 if (rename(oldname
, oldname
.GetPath() + newname
) == 0)
954 if (!force
|| errno
== ENOENT
|| !Exists(newname
))
957 if (!Remove(newname
, TRUE
))
960 return rename(oldname
, oldname
.GetPath() + newname
) == 0;
964 BOOL
PFile::Move(const PFilePath
& oldname
, const PFilePath
& newname
, BOOL force
)
966 PFilePath from
= oldname
.GetDirectory() + oldname
.GetFileName();
967 PFilePath to
= newname
.GetDirectory() + newname
.GetFileName();
969 if (rename(from
, to
) == 0)
973 return Copy(from
, to
, force
) && Remove(from
);
975 if (force
&& errno
== EEXIST
)
976 if (Remove(to
, TRUE
))
977 if (rename(from
, to
) == 0)
984 BOOL
PFile::Exists(const PFilePath
& name
)
987 // access function not defined for VxWorks
988 // as workaround, open the file in read-only mode
989 // if it succeeds, the file exists
990 PFile
file(name
, ReadOnly
, MustExist
);
991 BOOL exists
= file
.IsOpen();
996 return access(name
, 0) == 0;
1001 BOOL
PFile::Access(const PFilePath
& name
, OpenMode mode
)
1004 // access function not defined for VxWorks
1005 // as workaround, open the file in specified mode
1006 // if it succeeds, the access is allowed
1007 PFile
file(name
, mode
, ModeDefault
);
1008 BOOL access
= file
.IsOpen();
1025 accmode
= R_OK
| W_OK
;
1028 return access(name
, accmode
) == 0;
1033 BOOL
PFile::GetInfo(const PFilePath
& name
, PFileInfo
& status
)
1035 status
.type
= PFileInfo::UnknownFileType
;
1039 if (stat(name
, &s
) != OK
)
1041 if (lstat(name
, &s
) != 0)
1046 if (S_ISLNK(s
.st_mode
)) {
1047 status
.type
= PFileInfo::SymbolicLink
;
1048 if (stat(name
, &s
) != 0) {
1050 status
.modified
= 0;
1051 status
.accessed
= 0;
1053 status
.permissions
= PFileInfo::AllPermissions
;
1058 #endif // !P_VXWORKS
1059 if (S_ISREG(s
.st_mode
))
1060 status
.type
= PFileInfo::RegularFile
;
1061 else if (S_ISDIR(s
.st_mode
))
1062 status
.type
= PFileInfo::SubDirectory
;
1063 else if (S_ISFIFO(s
.st_mode
))
1064 status
.type
= PFileInfo::Fifo
;
1065 else if (S_ISCHR(s
.st_mode
))
1066 status
.type
= PFileInfo::CharDevice
;
1067 else if (S_ISBLK(s
.st_mode
))
1068 status
.type
= PFileInfo::BlockDevice
;
1069 #if !defined(__BEOS__) && !defined(P_VXWORKS)
1070 else if (S_ISSOCK(s
.st_mode
))
1071 status
.type
= PFileInfo::SocketDevice
;
1072 #endif // !__BEOS__ || !P_VXWORKS
1074 status
.created
= s
.st_ctime
;
1075 status
.modified
= s
.st_mtime
;
1076 status
.accessed
= s
.st_atime
;
1077 status
.size
= s
.st_size
;
1078 status
.permissions
= s
.st_mode
& PFileInfo::AllPermissions
;
1084 BOOL
PFile::SetPermissions(const PFilePath
& name
, int permissions
)
1092 if (permissions
& PFileInfo::WorldExecute
)
1094 if (permissions
& PFileInfo::WorldWrite
)
1096 if (permissions
& PFileInfo::WorldRead
)
1099 if (permissions
& PFileInfo::GroupExecute
)
1101 if (permissions
& PFileInfo::GroupWrite
)
1103 if (permissions
& PFileInfo::GroupRead
)
1106 if (permissions
& PFileInfo::UserExecute
)
1108 if (permissions
& PFileInfo::UserWrite
)
1110 if (permissions
& PFileInfo::UserRead
)
1114 PFile
file(name
, ReadOnly
, MustExist
);
1116 return (::ioctl(file
.GetHandle(), FIOATTRIBSET
, mode
) >= 0);
1120 return chmod ((const char *)name
, mode
) == 0;
1124 ///////////////////////////////////////////////////////////////////////////////
1127 BOOL
PTextFile::WriteLine (const PString
& line
)
1130 if (!Write((const char *)line
, line
.GetLength()))
1134 return Write(&ch
, 1);
1138 BOOL
PTextFile::ReadLine (PString
& line
)
1146 len
+= LINE_SIZE_STEP
;
1147 ptr
= base
= line
.GetPointer(len
) + len
- LINE_SIZE_STEP
;
1148 while ((ptr
- base
) < LINE_SIZE_STEP
-1) {
1149 if ((ch
= ReadChar()) < 0) {
1150 ConvertOSError(errno
);
1155 line
.MakeMinimumSize();
1163 ///////////////////////////////////////////////////////////////////////////////
1166 PFilePath::PFilePath(const PString
& str
)
1167 : PString(CanonicaliseFilename(str
))
1172 PFilePath::PFilePath(const char * cstr
)
1173 : PString(CanonicaliseFilename(cstr
))
1178 PFilePath::PFilePath(const char * prefix
, const char * dir
)
1186 s
= PDirectory("/tmp");
1191 *this = s
+ prefix
+ psprintf("%06x", number
++);
1192 if (!PFile::Exists(*this))
1199 *this = s
+ prefix
+ psprintf("%i_%06x", getpid(), random() % 1000000);
1200 if (!PFile::Exists(*this))
1207 void PFilePath::AssignContents(const PContainer
& cont
)
1209 PString::AssignContents(cont
);
1210 PString::AssignContents(CanonicaliseFilename(*this));
1214 PString
PFilePath::GetPath() const
1219 PAssert((i
= FindLast('/')) != P_MAX_INDEX
, PInvalidArrayIndex
);
1224 PString
PFilePath::GetTitle() const
1227 PString
fn(GetFileName());
1228 return fn(0, fn
.FindLast('.')-1);
1232 PString
PFilePath::GetType() const
1235 int p
= FindLast('.');
1236 int l
= (p
== P_MAX_INDEX
) ? 0 : (GetLength() - p
);
1241 return (*this)(p
, P_MAX_INDEX
);
1245 void PFilePath::SetType(const PString
& type
)
1247 PINDEX dot
= Find('.', FindLast('/'));
1248 if (dot
!= P_MAX_INDEX
)
1249 Splice(type
, dot
, GetLength()-dot
);
1255 PString
PFilePath::GetFileName() const
1260 if ((i
= FindLast('/')) == P_MAX_INDEX
)
1263 return Right(GetLength()-i
-1);
1267 PDirectory
PFilePath::GetDirectory() const
1271 if ((i
= FindLast('/')) == P_MAX_INDEX
)
1278 BOOL
PFilePath::IsValid(char c
)
1284 BOOL
PFilePath::IsValid(const PString
& str
)
1286 return str
.Find('/') == P_MAX_INDEX
;
1290 ///////////////////////////////////////////////////////////////////////////////
1293 PConsoleChannel::PConsoleChannel()
1298 PConsoleChannel::PConsoleChannel(ConsoleType type
)
1304 BOOL
PConsoleChannel::Open(ConsoleType type
)
1307 case StandardInput
:
1311 case StandardOutput
:
1315 case StandardError
:
1324 PString
PConsoleChannel::GetName() const
1327 PAssertAlways("PConsoleChannel::GetName - Not implemented for VxWorks");
1328 return PString("Not Implemented");
1330 return ttyname(os_handle
);
1335 BOOL
PConsoleChannel::Close()
1342 //////////////////////////////////////////////////////
1351 clock_gettime(0,&ts
);
1352 theTime
= ts
.tv_sec
;
1353 microseconds
= ts
.tv_sec
*10000 + ts
.tv_nsec
/100000L;
1356 gettimeofday(&tv
, NULL
);
1357 theTime
= tv
.tv_sec
;
1358 microseconds
= tv
.tv_usec
;
1363 BOOL
PTime::GetTimeAMPM()
1365 #if defined(P_USE_LANGINFO)
1366 return strstr(nl_langinfo(T_FMT
), "%p") != NULL
;
1367 #elif defined(P_USE_STRFTIME)
1370 memset(&t
, 0, sizeof(t
));
1374 strftime(buf
, sizeof(buf
), "%X", &t
);
1375 return strstr(buf
, "20") != NULL
;
1377 #warning No AMPM implementation
1383 PString
PTime::GetTimeAM()
1385 #if defined(P_USE_LANGINFO)
1386 return PString(nl_langinfo(AM_STR
));
1387 #elif defined(P_USE_STRFTIME)
1390 memset(&t
, 0, sizeof(t
));
1394 strftime(buf
, sizeof(buf
), "%p", &t
);
1397 #warning Using default AM string
1403 PString
PTime::GetTimePM()
1405 #if defined(P_USE_LANGINFO)
1406 return PString(nl_langinfo(PM_STR
));
1407 #elif defined(P_USE_STRFTIME)
1410 memset(&t
, 0, sizeof(t
));
1414 strftime(buf
, sizeof(buf
), "%p", &t
);
1417 #warning Using default PM string
1423 PString
PTime::GetTimeSeparator()
1425 #if defined(P_LINUX) || defined(P_HPUX9) || defined(P_SOLARIS) || defined(P_IRIX)
1426 # if defined(P_USE_LANGINFO)
1427 char * p
= nl_langinfo(T_FMT
);
1428 # elif defined(P_LINUX)
1429 char * p
= _time_info
->time
;
1432 while (*p
== '%' || isalpha(*p
))
1436 return PString(buffer
);
1437 #elif defined(P_USE_STRFTIME)
1440 memset(&t
, 0, sizeof(t
));
1444 strftime(buf
, sizeof(buf
), "%X", &t
);
1445 char * sp
= strstr(buf
, "11") + 2;
1447 while (*ep
!= '\0' && !isdigit(*ep
))
1449 return PString(sp
, ep
-sp
);
1451 #warning Using default time separator
1456 PTime::DateOrder
PTime::GetDateOrder()
1458 #if defined(P_USE_LANGINFO) || defined(P_LINUX)
1459 # if defined(P_USE_LANGINFO)
1460 char * p
= nl_langinfo(D_FMT
);
1462 char * p
= _time_info
->date
;
1467 switch (tolower(*p
)) {
1469 return DayMonthYear
;
1471 return YearMonthDay
;
1476 return MonthDayYear
;
1478 #elif defined(P_USE_STRFTIME)
1481 memset(&t
, 0, sizeof(t
));
1485 strftime(buf
, sizeof(buf
), "%x", &t
);
1486 char * day_pos
= strstr(buf
, "22");
1487 char * mon_pos
= strstr(buf
, "11");
1488 char * yr_pos
= strstr(buf
, "99");
1489 if (yr_pos
< day_pos
)
1490 return YearMonthDay
;
1491 if (day_pos
< mon_pos
)
1492 return DayMonthYear
;
1493 return MonthDayYear
;
1495 #warning Using default date order
1496 return DayMonthYear
;
1500 PString
PTime::GetDateSeparator()
1502 #if defined(P_USE_LANGINFO) || defined(P_LINUX)
1503 # if defined(P_USE_LANGINFO)
1504 char * p
= nl_langinfo(D_FMT
);
1506 char * p
= _time_info
->date
;
1509 while (*p
== '%' || isalpha(*p
))
1513 return PString(buffer
);
1514 #elif defined(P_USE_STRFTIME)
1517 memset(&t
, 0, sizeof(t
));
1521 strftime(buf
, sizeof(buf
), "%x", &t
);
1522 char * sp
= strstr(buf
, "22") + 2;
1524 while (*ep
!= '\0' && !isdigit(*ep
))
1526 return PString(sp
, ep
-sp
);
1528 #warning Using default date separator
1533 PString
PTime::GetDayName(PTime::Weekdays day
, NameType type
)
1535 #if defined(P_USE_LANGINFO)
1537 (type
== Abbreviated
) ? nl_langinfo((nl_item
)(ABDAY_1
+(int)day
)) :
1538 nl_langinfo((nl_item
)(DAY_1
+(int)day
))
1541 #elif defined(P_LINUX)
1542 return (type
== Abbreviated
) ? PString(_time_info
->abbrev_wkday
[(int)day
]) :
1543 PString(_time_info
->full_wkday
[(int)day
]);
1545 #elif defined(P_USE_STRFTIME)
1548 memset(&t
, 0, sizeof(t
));
1550 strftime(buf
, sizeof(buf
), type
== Abbreviated
? "%a" : "%A", &t
);
1553 #warning Using default day names
1554 static char *defaultNames
[] = {
1555 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
1559 static char *defaultAbbrev
[] = {
1560 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1562 return (type
== Abbreviated
) ? PString(defaultNames
[(int)day
]) :
1563 PString(defaultAbbrev
[(int)day
]);
1567 PString
PTime::GetMonthName(PTime::Months month
, NameType type
)
1569 #if defined(P_USE_LANGINFO)
1571 (type
== Abbreviated
) ? nl_langinfo((nl_item
)(ABMON_1
+(int)month
-1)) :
1572 nl_langinfo((nl_item
)(MON_1
+(int)month
-1))
1574 #elif defined(P_LINUX)
1575 return (type
== Abbreviated
) ? PString(_time_info
->abbrev_month
[(int)month
-1]) :
1576 PString(_time_info
->full_month
[(int)month
-1]);
1577 #elif defined(P_USE_STRFTIME)
1580 memset(&t
, 0, sizeof(t
));
1582 strftime(buf
, sizeof(buf
), type
== Abbreviated
? "%b" : "%B", &t
);
1585 #warning Using default monthnames
1586 static char *defaultNames
[] = {
1587 "January", "February", "March", "April", "May", "June", "July", "August",
1588 "September", "October", "November", "December" };
1590 static char *defaultAbbrev
[] = {
1591 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
1592 "Sep", "Oct", "Nov", "Dec" };
1594 return (type
== Abbreviated
) ? PString(defaultNames
[(int)month
-1]) :
1595 PString(defaultAbbrev
[(int)month
-1]);
1600 BOOL
PTime::IsDaylightSavings()
1602 time_t theTime
= ::time(NULL
);
1604 return os_localtime(&theTime
, &ts
)->tm_isdst
!= 0;
1607 int PTime::GetTimeZone(PTime::TimeZoneType type
)
1609 #if defined(P_LINUX) || defined(P_SOLARIS) || defined (P_AIX) || defined(P_IRIX)
1610 long tz
= -::timezone
/60;
1611 if (type
== StandardTime
)
1614 return tz
+ ::daylight
*60;
1615 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS) || defined(__BEOS__) || defined(P_QNX)
1619 struct tm
* tm
= os_localtime(&t
, &ts
);
1620 int tz
= tm
->tm_gmtoff
/60;
1621 if (type
== StandardTime
&& tm
->tm_isdst
)
1623 if (type
!= StandardTime
&& !tm
->tm_isdst
)
1626 #elif defined(P_SUN4)
1629 if (type
== StandardTime
|| tb
.dstflag
== 0)
1630 return -tb
.timezone
;
1632 return -tb
.timezone
+ 60;
1634 #warning No timezone information
1639 PString
PTime::GetTimeZoneString(PTime::TimeZoneType type
)
1641 #if defined(P_LINUX) || defined(P_SUN4) || defined(P_SOLARIS) || defined (P_AIX) || defined(P_IRIX) || defined(P_QNX)
1642 const char * str
= (type
== StandardTime
) ? ::tzname
[0] : ::tzname
[1];
1646 #elif defined(P_USE_STRFTIME)
1649 memset(&t
, 0, sizeof(t
));
1650 t
.tm_isdst
= type
!= StandardTime
;
1651 strftime(buf
, sizeof(buf
), "%Z", &t
);
1654 #warning No timezone name information
1659 // note that PX_tm is local storage inside the PTime instance
1662 struct tm
* PTime::os_localtime(const time_t * clock
, struct tm
* ts
)
1664 return ::localtime_r(clock
, ts
);
1667 struct tm
* PTime::os_localtime(const time_t * clock
, struct tm
*)
1669 return ::localtime(clock
);
1674 struct tm
* PTime::os_gmtime(const time_t * clock
, struct tm
* ts
)
1676 return ::gmtime_r(clock
, ts
);
1679 struct tm
* PTime::os_gmtime(const time_t * clock
, struct tm
*)
1681 return ::gmtime(clock
);
1685 // End Of File ///////////////////////////////////////////////////////////////