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.81 2004/04/01 12:51:11 csoutheren
31 * Fixed problem with args to access, thanks to Borko Jandras
33 * Revision 1.80 2004/01/07 21:30:30 dsandras
34 * Applied patch from Miguel Rodriguez Perez <migrax@terra.es> to remove problematic PAssert failing in cases where it shouldn't.
36 * Revision 1.79 2003/09/17 01:18:04 csoutheren
37 * Removed recursive include file system and removed all references
38 * to deprecated coooperative threading support
40 * Revision 1.78 2003/05/01 06:08:36 robertj
41 * Fixed concurrency problem with some time functions, thanks chad@broadmind.com
43 * Revision 1.77 2003/01/24 10:21:06 robertj
44 * Fixed issues in RTEMS support, thanks Vladimir Nesic
46 * Revision 1.76 2002/11/22 10:14:07 robertj
47 * QNX port, thanks Xiaodan Tang
49 * Revision 1.75 2002/11/20 01:55:06 robertj
50 * Fixed to follow new semantics of GetPath(), first entry is volume which on
51 * UNix machines is always an empty string. Also collapses consecutive
52 * slashes as they are meaningless.
54 * Revision 1.74 2002/11/19 11:21:30 robertj
55 * Changed PFilePath so can be empty string, indicating illegal path.
56 * Added function to extract a path as an array of directories components.
58 * Revision 1.73 2002/10/22 07:42:52 robertj
59 * Added extra debugging for file handle and thread leak detection.
61 * Revision 1.72 2002/10/17 13:44:27 robertj
62 * Port to RTEMS, thanks Vladimir Nesic.
64 * Revision 1.71 2002/10/17 12:57:24 robertj
65 * Added ability to increase maximum file handles on a process.
67 * Revision 1.70 2002/10/10 04:43:44 robertj
68 * VxWorks port, thanks Martijn Roest
70 * Revision 1.69 2002/06/06 09:28:42 robertj
71 * Fixed problems with canonicalising directories now PINDEX is signed.
73 * Revision 1.68 2002/02/11 02:26:54 craigs
74 * Fixed problem with reading lines of length > 100 chares from text files
75 * Thanks to Ohnuma Masato
77 * Revision 1.67 2002/01/26 23:58:15 craigs
78 * Changed for GCC 3.0 compatibility, thanks to manty@manty.net
80 * Revision 1.66 2001/10/11 02:20:54 robertj
81 * Added IRIX support (no audio/video), thanks Andre Schulze.
83 * Revision 1.65 2001/09/18 05:56:03 robertj
84 * Fixed numerous problems with thread suspend/resume and signals handling.
86 * Revision 1.64 2001/09/04 04:15:44 robertj
87 * Fixed PFileInfo (stat) of file name that is dangling symlink.
89 * Revision 1.63 2001/08/11 15:38:43 rogerh
90 * Add Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
92 * Revision 1.62 2001/06/30 06:59:07 yurik
93 * Jac Goudsmit from Be submit these changes 6/28. Implemented by Yuri Kiryanov
95 * Revision 1.61 2001/05/29 03:35:16 craigs
96 * Changed to not tempnam to avoid linker warning on new Linux systems
98 * Revision 1.60 2001/03/12 02:35:20 robertj
99 * Fixed PDirectory::Exists so only returns TRUE if a directory and not file.
101 * Revision 1.59 2001/02/23 07:16:36 rogerh
102 * Darwin (MACOS X) does not have thread safe localtime_t() and gmtime_r()
103 * functions. Use the unsafe localtime() and gmtime() calls for now.
105 * Revision 1.58 2001/02/13 06:59:57 robertj
106 * Fixed problem with operator= in PDirectory class, part of larger change previously made.
108 * Revision 1.57 2001/02/13 05:15:31 robertj
109 * Fixed problem with operator= in container classes. Some containers will
110 * break unless the copy is virtual (eg PStringStream's buffer pointers) so
111 * needed to add a new AssignContents() function to all containers.
113 * Revision 1.56 2000/09/11 22:49:31 robertj
114 * Fixed bug where last char was always removed in mkdir() instead of only if '/'.
116 * Revision 1.55 2000/06/21 01:01:22 robertj
117 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
119 * Revision 1.54 2000/04/19 00:13:53 robertj
122 * Revision 1.53 2000/04/09 18:19:23 rogerh
123 * Add my changes for NetBSD support.
125 * Revision 1.52 2000/04/06 12:11:32 rogerh
126 * MacOS X support submitted by Kevin Packard
128 * Revision 1.51 2000/04/05 02:55:11 robertj
129 * Added microseconds to PTime class.
131 * Revision 1.50 2000/03/08 12:17:09 rogerh
132 * Add OpenBSD support
134 * Revision 1.49 2000/02/24 11:03:49 robertj
135 * Fixed warning on Linux systems about _REENTRANT
137 * Revision 1.48 1999/08/17 07:37:36 robertj
138 * Fixed inlines so are inlined for optimised version
140 * Revision 1.47 1999/06/28 09:28:02 robertj
141 * Portability issues, especially n BeOS (thanks Yuri!)
143 * Revision 1.46 1999/06/26 08:21:12 robertj
144 * Fixed bug in PFilePath::SetType finding dots outside of file name in path.
146 * Revision 1.45 1999/06/14 08:39:57 robertj
147 * Added PConsoleChannel class for access to stdin/stdout/stderr
149 * Revision 1.44 1999/06/09 04:08:46 robertj
150 * Added support for opening stdin/stdout/stderr as PFile objects.
152 * Revision 1.43 1999/02/22 13:26:53 robertj
155 * Revision 1.42 1998/12/12 01:06:24 robertj
156 * Fixed off by one error in month on FreeBSD platform
158 * Revision 1.41 1998/11/30 21:51:43 robertj
159 * New directory structure.
161 * Revision 1.40 1998/11/26 11:54:16 robertj
162 * Fixed error return on PFile::GetInfo
164 * Revision 1.39 1998/11/24 09:39:09 robertj
167 * Revision 1.38 1998/11/10 13:00:52 robertj
168 * Fixed strange problems with readdir_r usage.
170 * Revision 1.37 1998/11/06 04:44:46 robertj
171 * Solaris compatibility
173 * Revision 1.36 1998/11/05 12:03:13 robertj
174 * Fixed solaris compatibility and Linux warning on readdir_r function.
176 * Revision 1.35 1998/11/05 09:05:55 craigs
177 * Changed directory routines to use reenttrant functions, and added PDirectory::GetParent
179 * Revision 1.34 1998/09/24 07:39:49 robertj
180 * Removed file that only had #pragma implmentation for PTextFile and nothing else.
182 * Revision 1.33 1998/09/24 04:12:12 robertj
183 * Added open software license.
189 #pragma implementation "timer.h"
190 #pragma implementation "pdirect.h"
191 #pragma implementation "file.h"
192 #pragma implementation "textfile.h"
193 #pragma implementation "conchan.h"
194 #pragma implementation "ptime.h"
195 #pragma implementation "timeint.h"
196 #pragma implementation "filepath.h"
197 #pragma implementation "lists.h"
198 #pragma implementation "pstring.h"
199 #pragma implementation "dict.h"
200 #pragma implementation "array.h"
201 #pragma implementation "object.h"
202 #pragma implementation "contain.h"
208 #elif defined(P_SOLARIS)
209 #define _POSIX_PTHREAD_SEMANTICS
217 #include <sys/times.h>
220 #include <sys/time.h>
229 #define P_HAS_READDIR_R
231 #if (__GNUC_MINOR__ < 7 && __GNUC__ < 3)
232 #include <localeinfo.h>
234 #define P_USE_LANGINFO
237 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS)
238 #define P_USE_STRFTIME
240 #include <sys/param.h>
241 #include <sys/mount.h>
243 #elif defined(P_HPUX9)
244 #define P_USE_LANGINFO
247 #define P_USE_STRFTIME
250 #include <sys/stat.h>
251 #include <sys/statfs.h>
253 #elif defined(P_SOLARIS)
254 #define P_HAS_READDIR_R
255 #define P_USE_LANGINFO
256 #include <sys/timeb.h>
257 #include <sys/statvfs.h>
258 #include <sys/mnttab.h>
260 #elif defined(P_SUN4)
261 #include <sys/timeb.h>
263 #elif defined(__BEOS__)
264 #define P_USE_STRFTIME
266 #elif defined(P_IRIX)
267 #define P_USE_LANGINFO
268 #include <sys/stat.h>
269 #include <sys/statfs.h>
273 #elif defined(P_VXWORKS)
274 #define P_USE_STRFTIME
276 #elif defined(P_RTEMS)
277 #define P_USE_STRFTIME
280 #define random() rand()
281 #define srandom(a) srand(a)
284 #include <sys/dcmd_blk.h>
285 #include <sys/statvfs.h>
286 #define P_USE_STRFTIME
289 #ifdef P_USE_LANGINFO
290 #include <langinfo.h>
293 #define LINE_SIZE_STEP 100
295 #define DEFAULT_FILE_MODE (S_IRUSR|S_IWUSR|S_IROTH|S_IRGRP)
298 #include "ptlib/osutil.inl"
300 #include "ptlib/win32/ptlib/ptlib.inl"
302 #include "ptlib/unix/ptlib/ptlib.inl"
308 int on_exit(void (*f
)(void), caddr_t
);
309 int atexit(void (*f
)(void))
311 return on_exit(f
, 0);
313 static char *tzname
[2] = { "STD", "DST" };
320 int PX_NewHandle(const char * clsName
, int fd
)
325 static int lowWaterMark
= INT_MAX
;
326 static int highWaterMark
= 0;
327 if (fd
> highWaterMark
) {
331 int maxHandles
= PProcess::Current().GetMaxHandles();
332 if (fd
< (maxHandles
-maxHandles
/20))
333 PTRACE(4, "PWLib\tFile handle high water mark set: " << fd
<< ' ' << clsName
);
335 PTRACE(1, "PWLib\tFile handle high water mark within 5% of maximum: " << fd
<< ' ' << clsName
);
338 if (fd
< lowWaterMark
) {
340 PTRACE(4, "PWLib\tFile handle low water mark set: " << fd
<< ' ' << clsName
);
347 static PString
CanonicaliseDirectory (const PString
& path
)
350 PString canonical_path
;
353 canonical_path
= '/';
355 char *p
= getcwd(canonical_path
.GetPointer(P_MAX_PATH
), P_MAX_PATH
);
356 PAssertOS (p
!= NULL
);
358 // if the path doesn't end in a slash, add one
359 if (canonical_path
[canonical_path
.GetLength()-1] != '/')
360 canonical_path
+= '/';
363 const char * ptr
= path
;
368 while (*ptr
== '/' && *ptr
!= '\0')
371 // finished if end of string
375 // collect non-slash characters
377 while (*end
!= '/' && *end
!= '\0')
380 // make a string out of the element
381 PString
element(ptr
, end
- ptr
);
383 if (element
== "..") {
384 PINDEX last_char
= canonical_path
.GetLength()-1;
386 canonical_path
= canonical_path
.Left(canonical_path
.FindLast('/', last_char
-1)+1);
387 } else if (element
== "." || element
== "") {
389 canonical_path
+= element
;
390 canonical_path
+= '/';
395 return canonical_path
;
399 static PString
CanonicaliseFilename(const PString
& filename
)
401 if (filename
.IsEmpty())
407 // if there is a slash in the string, extract the dirname
408 if ((p
= filename
.FindLast('/')) != P_MAX_INDEX
) {
409 dirname
= filename(0,p
);
410 while (filename
[p
] == '/')
415 return CanonicaliseDirectory(dirname
) + filename(p
, P_MAX_INDEX
);
419 PInt64
PString::AsInt64(unsigned base
) const
422 #if defined(P_SOLARIS) || defined(__BEOS__) || defined (P_AIX) || defined(P_IRIX) || defined (P_QNX)
423 return strtoll(theArray
, &dummy
, base
);
424 #elif defined(P_VXWORKS) || defined(P_RTEMS)
425 return strtol(theArray
, &dummy
, base
);
427 return strtoq(theArray
, &dummy
, base
);
431 PUInt64
PString::AsUnsigned64(unsigned base
) const
434 #if defined(P_SOLARIS) || defined(__BEOS__) || defined (P_AIX) || defined (P_IRIX) || defined (P_QNX)
435 return strtoull(theArray
, &dummy
, base
);
436 #elif defined(P_VXWORKS) || defined(P_RTEMS)
437 return strtoul(theArray
, &dummy
, base
);
439 return strtouq(theArray
, &dummy
, base
);
444 ///////////////////////////////////////////////////////////////////////////////
449 PTimeInterval
PTimer::Tick()
454 clock_gettime(0,&ts
);
455 return (int)(ts
.tv_sec
*10000) + ts
.tv_nsec
/100000L;
458 ::gettimeofday (&tv
, NULL
);
459 return (PInt64
)(tv
.tv_sec
) * 1000 + tv
.tv_usec
/1000L;
465 ///////////////////////////////////////////////////////////////////////////////
470 void PDirectory::CopyContents(const PDirectory
& d
)
472 if (d
.entryInfo
== NULL
)
475 entryInfo
= new PFileInfo
;
476 *entryInfo
= *d
.entryInfo
;
482 void PDirectory::Close()
484 if (directory
!= NULL
) {
485 PAssert(closedir(directory
) == 0, POperatingSystemError
);
489 if (entryBuffer
!= NULL
) {
494 if (entryInfo
!= NULL
) {
500 void PDirectory::Construct ()
507 PString::AssignContents(CanonicaliseDirectory(*this));
510 BOOL
PDirectory::Open(int ScanMask
)
513 if (directory
!= NULL
)
518 if ((directory
= opendir(theArray
)) == NULL
)
521 entryBuffer
= (struct dirent
*)malloc(sizeof(struct dirent
) + P_MAX_PATH
);
522 entryInfo
= new PFileInfo
;
532 BOOL
PDirectory::Next()
534 if (directory
== NULL
)
539 struct dirent
* entryPtr
;
540 entryBuffer
->d_name
[0] = '\0';
541 #ifdef P_HAS_READDIR_R
542 if (::readdir_r(directory
, entryBuffer
, &entryPtr
) != 0)
544 if (entryPtr
!= entryBuffer
)
547 if ((entryPtr
= readdir(directory
)) == NULL
)
549 *entryBuffer
= *entryPtr
;
550 strcpy(entryBuffer
->d_name
, entryPtr
->d_name
);
552 } while (strcmp(entryBuffer
->d_name
, "." ) == 0 || strcmp(entryBuffer
->d_name
, "..") == 0);
554 /* Ignore this file if we can't get info about it */
555 if (PFile::GetInfo(*this+entryBuffer
->d_name
, *entryInfo
) == 0)
558 if (scanMask
== PFileInfo::AllPermissions
)
560 } while ((entryInfo
->type
& scanMask
) == 0);
566 BOOL
PDirectory::IsSubDir() const
568 if (entryInfo
== NULL
)
571 return entryInfo
->type
== PFileInfo::SubDirectory
;
574 BOOL
PDirectory::Restart(int newScanMask
)
576 scanMask
= newScanMask
;
577 if (directory
!= NULL
)
578 rewinddir(directory
);
582 PString
PDirectory::GetEntryName() const
584 if (entryBuffer
== NULL
)
587 return entryBuffer
->d_name
;
591 BOOL
PDirectory::GetInfo(PFileInfo
& info
) const
598 BOOL
PDirectory::Exists(const PString
& p
)
601 if (stat((const char *)p
, &sbuf
) != 0)
604 return S_ISDIR(sbuf
.st_mode
);
608 BOOL
PDirectory::Create(const PString
& p
, int perm
)
610 PAssert(!p
.IsEmpty(), "attempt to create dir with empty name");
611 PINDEX last
= p
.GetLength()-1;
616 return mkdir(str
) == 0;
618 return mkdir(str
, perm
) == 0;
622 BOOL
PDirectory::Remove(const PString
& p
)
624 PAssert(!p
.IsEmpty(), "attempt to remove dir with empty name");
625 PString str
= p
.Left(p
.GetLength()-1);
626 return rmdir(str
) == 0;
629 PString
PDirectory::GetVolume() const
637 if ((fd
= open(operator+("."), O_RDONLY
)) != -1) {
639 devctl(fd
, DCMD_FSYS_MOUNTED_ON
, mounton
, 256, 0);
641 volume
= strdup(mounton
);
646 if (stat(operator+("."), &status
) != -1) {
647 dev_t my_dev
= status
.st_dev
;
649 #if defined(P_LINUX) || defined(P_IRIX)
651 FILE * fp
= setmntent(MOUNTED
, "r");
654 while ((mnt
= getmntent(fp
)) != NULL
) {
655 if (stat(mnt
->mnt_dir
, &status
) != -1 && status
.st_dev
== my_dev
) {
656 volume
= mnt
->mnt_fsname
;
663 #elif defined(P_SOLARIS)
665 FILE * fp
= fopen("/etc/mnttab", "r");
668 while (getmntent(fp
, &mnt
) == 0) {
669 if (stat(mnt
.mnt_mountp
, &status
) != -1 && status
.st_dev
== my_dev
) {
670 volume
= mnt
.mnt_special
;
677 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS)
680 int count
= getmntinfo(&mnt
, MNT_NOWAIT
);
681 for (int i
= 0; i
< count
; i
++) {
682 if (stat(mnt
[i
].f_mntonname
, &status
) != -1 && status
.st_dev
== my_dev
) {
683 volume
= mnt
[i
].f_mntfromname
;
688 #elif defined (P_AIX)
692 while ((fs
= getfsent()) != NULL
) {
693 if (stat(fs
->fs_file
, &status
) != -1 && status
.st_dev
== my_dev
) {
694 volume
= fs
->fs_spec
;
700 #elif defined (P_VXWORKS)
702 PAssertAlways("Get Volume - not implemented for VxWorks");
703 return PString::Empty();
706 #warning Platform requires implemetation of GetVolume()
715 BOOL
PDirectory::GetVolumeSpace(PInt64
& total
, PInt64
& free
, DWORD
& clusterSize
) const
717 #if defined(P_LINUX) || defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS)
721 if (statfs(operator+("."), &fs
) == -1)
724 clusterSize
= fs
.f_bsize
;
725 total
= fs
.f_blocks
*(PInt64
)fs
.f_bsize
;
726 free
= fs
.f_bavail
*(PInt64
)fs
.f_bsize
;
729 #elif defined(P_AIX) || defined(P_VXWORKS)
732 if (statfs((char *) ((const char *)operator+(".") ), &fs
) == -1)
735 clusterSize
= fs
.f_bsize
;
736 total
= fs
.f_blocks
*(PInt64
)fs
.f_bsize
;
737 free
= fs
.f_bavail
*(PInt64
)fs
.f_bsize
;
740 #elif defined(P_SOLARIS)
743 if (statvfs(operator+("."), &buf
) != 0)
746 clusterSize
= buf
.f_frsize
;
747 total
= buf
.f_blocks
* buf
.f_frsize
;
748 free
= buf
.f_bfree
* buf
.f_frsize
;
752 #elif defined(P_IRIX)
756 if (statfs(operator+("."), &fs
, sizeof(struct statfs
), 0) == -1)
759 clusterSize
= fs
.f_bsize
;
760 total
= fs
.f_blocks
*(PInt64
)fs
.f_bsize
;
761 free
= fs
.f_bfree
*(PInt64
)fs
.f_bsize
;
768 if (statvfs(operator+("."), &fs
) == -1)
771 clusterSize
= fs
.f_bsize
;
772 total
= fs
.f_blocks
*(PInt64
)fs
.f_bsize
;
773 free
= fs
.f_bavail
*(PInt64
)fs
.f_bsize
;
778 #warning Platform requires implemetation of GetVolumeSpace()
784 PDirectory
PDirectory::GetParent() const
792 PStringArray
PDirectory::GetPath() const
799 PStringArray tokens
= Tokenise("/");
801 path
.SetSize(tokens
.GetSize()+1);
803 PINDEX count
= 1; // First path field is volume name, empty under unix
804 for (PINDEX i
= 0; i
< tokens
.GetSize(); i
++) {
806 path
[count
++] = tokens
[i
];
815 ///////////////////////////////////////////////////////////////////////////////
820 void PFile::SetFilePath(const PString
& newName
)
824 if ((p
= newName
.FindLast('/')) == P_MAX_INDEX
)
825 path
= CanonicaliseDirectory("") + newName
;
827 path
= CanonicaliseDirectory(newName(0,p
)) + newName(p
+1, P_MAX_INDEX
);
831 BOOL
PFile::Open(OpenMode mode
, int opt
)
838 removeOnClose
= (opt
& Temporary
) != 0;
840 if (path
.IsEmpty()) {
841 char templateStr
[3+6+1];
842 strcpy(templateStr
, "PWL");
846 memset(&_reent_data
, 0, sizeof(_reent_data
));
847 os_handle
= _mkstemp_r(&_reent_data
, templateStr
);
849 os_handle
= mkstemp(templateStr
);
851 if (!ConvertOSError(os_handle
))
856 static int number
= 0;
857 sprintf(templateStr
+3, "%06d", number
++);
866 if (opt
== ModeDefault
)
871 if (opt
== ModeDefault
)
872 opt
= Create
|Truncate
;
876 if (opt
== ModeDefault
)
881 PAssertAlways(PInvalidParameter
);
883 if ((opt
&Create
) != 0)
885 if ((opt
&Exclusive
) != 0)
887 if ((opt
&Truncate
) != 0)
891 if (!ConvertOSError(os_handle
= PX_NewHandle(GetClass(), ::open(path
, oflags
, DEFAULT_FILE_MODE
))))
896 return ConvertOSError(::fcntl(os_handle
, F_SETFD
, 1));
903 BOOL
PFile::SetLength(off_t len
)
905 return ConvertOSError(ftruncate(GetHandle(), len
));
909 BOOL
PFile::Rename(const PFilePath
& oldname
, const PString
& newname
, BOOL force
)
911 if (newname
.Find('/') != P_MAX_INDEX
) {
916 if (rename(oldname
, oldname
.GetPath() + newname
) == 0)
919 if (!force
|| errno
== ENOENT
|| !Exists(newname
))
922 if (!Remove(newname
, TRUE
))
925 return rename(oldname
, oldname
.GetPath() + newname
) == 0;
929 BOOL
PFile::Move(const PFilePath
& oldname
, const PFilePath
& newname
, BOOL force
)
931 PFilePath from
= oldname
.GetDirectory() + oldname
.GetFileName();
932 PFilePath to
= newname
.GetDirectory() + newname
.GetFileName();
934 if (rename(from
, to
) == 0)
938 return Copy(from
, to
, force
) && Remove(from
);
940 if (force
&& errno
== EEXIST
)
941 if (Remove(to
, TRUE
))
942 if (rename(from
, to
) == 0)
949 BOOL
PFile::Exists(const PFilePath
& name
)
952 // access function not defined for VxWorks
953 // as workaround, open the file in read-only mode
954 // if it succeeds, the file exists
955 PFile
file(name
, ReadOnly
, MustExist
);
956 BOOL exists
= file
.IsOpen();
961 return access(name
, 0) == 0;
966 BOOL
PFile::Access(const PFilePath
& name
, OpenMode mode
)
969 // access function not defined for VxWorks
970 // as workaround, open the file in specified mode
971 // if it succeeds, the access is allowed
972 PFile
file(name
, mode
, ModeDefault
);
973 BOOL access
= file
.IsOpen();
990 accmode
= R_OK
| W_OK
;
993 return access(name
, accmode
) == 0;
998 BOOL
PFile::GetInfo(const PFilePath
& name
, PFileInfo
& status
)
1000 status
.type
= PFileInfo::UnknownFileType
;
1004 if (stat(name
, &s
) != OK
)
1006 if (lstat(name
, &s
) != 0)
1011 if (S_ISLNK(s
.st_mode
)) {
1012 status
.type
= PFileInfo::SymbolicLink
;
1013 if (stat(name
, &s
) != 0) {
1015 status
.modified
= 0;
1016 status
.accessed
= 0;
1018 status
.permissions
= PFileInfo::AllPermissions
;
1023 #endif // !P_VXWORKS
1024 if (S_ISREG(s
.st_mode
))
1025 status
.type
= PFileInfo::RegularFile
;
1026 else if (S_ISDIR(s
.st_mode
))
1027 status
.type
= PFileInfo::SubDirectory
;
1028 else if (S_ISFIFO(s
.st_mode
))
1029 status
.type
= PFileInfo::Fifo
;
1030 else if (S_ISCHR(s
.st_mode
))
1031 status
.type
= PFileInfo::CharDevice
;
1032 else if (S_ISBLK(s
.st_mode
))
1033 status
.type
= PFileInfo::BlockDevice
;
1034 #if !defined(__BEOS__) && !defined(P_VXWORKS)
1035 else if (S_ISSOCK(s
.st_mode
))
1036 status
.type
= PFileInfo::SocketDevice
;
1037 #endif // !__BEOS__ || !P_VXWORKS
1039 status
.created
= s
.st_ctime
;
1040 status
.modified
= s
.st_mtime
;
1041 status
.accessed
= s
.st_atime
;
1042 status
.size
= s
.st_size
;
1043 status
.permissions
= s
.st_mode
& PFileInfo::AllPermissions
;
1049 BOOL
PFile::SetPermissions(const PFilePath
& name
, int permissions
)
1057 if (permissions
& PFileInfo::WorldExecute
)
1059 if (permissions
& PFileInfo::WorldWrite
)
1061 if (permissions
& PFileInfo::WorldRead
)
1064 if (permissions
& PFileInfo::GroupExecute
)
1066 if (permissions
& PFileInfo::GroupWrite
)
1068 if (permissions
& PFileInfo::GroupRead
)
1071 if (permissions
& PFileInfo::UserExecute
)
1073 if (permissions
& PFileInfo::UserWrite
)
1075 if (permissions
& PFileInfo::UserRead
)
1079 PFile
file(name
, ReadOnly
, MustExist
);
1081 return (::ioctl(file
.GetHandle(), FIOATTRIBSET
, mode
) >= 0);
1085 return chmod ((const char *)name
, mode
) == 0;
1089 ///////////////////////////////////////////////////////////////////////////////
1092 BOOL
PTextFile::WriteLine (const PString
& line
)
1095 if (!Write((const char *)line
, line
.GetLength()))
1099 return Write(&ch
, 1);
1103 BOOL
PTextFile::ReadLine (PString
& line
)
1111 len
+= LINE_SIZE_STEP
;
1112 ptr
= base
= line
.GetPointer(len
) + len
- LINE_SIZE_STEP
;
1113 while ((ptr
- base
) < LINE_SIZE_STEP
-1) {
1114 if ((ch
= ReadChar()) < 0) {
1115 ConvertOSError(errno
);
1120 line
.MakeMinimumSize();
1128 ///////////////////////////////////////////////////////////////////////////////
1131 PFilePath::PFilePath(const PString
& str
)
1132 : PString(CanonicaliseFilename(str
))
1137 PFilePath::PFilePath(const char * cstr
)
1138 : PString(CanonicaliseFilename(cstr
))
1143 PFilePath::PFilePath(const char * prefix
, const char * dir
)
1151 s
= PDirectory("/tmp");
1156 *this = s
+ prefix
+ psprintf("%06x", number
++);
1157 if (!PFile::Exists(*this))
1164 *this = s
+ prefix
+ psprintf("%i_%06x", getpid(), random() % 1000000);
1165 if (!PFile::Exists(*this))
1172 void PFilePath::AssignContents(const PContainer
& cont
)
1174 PString::AssignContents(cont
);
1175 PString::AssignContents(CanonicaliseFilename(*this));
1179 PString
PFilePath::GetPath() const
1184 PAssert((i
= FindLast('/')) != P_MAX_INDEX
, PInvalidArrayIndex
);
1189 PString
PFilePath::GetTitle() const
1192 PString
fn(GetFileName());
1193 return fn(0, fn
.FindLast('.')-1);
1197 PString
PFilePath::GetType() const
1200 int p
= FindLast('.');
1201 int l
= (p
== P_MAX_INDEX
) ? 0 : (GetLength() - p
);
1206 return (*this)(p
, P_MAX_INDEX
);
1210 void PFilePath::SetType(const PString
& type
)
1212 PINDEX dot
= Find('.', FindLast('/'));
1213 if (dot
!= P_MAX_INDEX
)
1214 Splice(type
, dot
, GetLength()-dot
);
1220 PString
PFilePath::GetFileName() const
1225 if ((i
= FindLast('/')) == P_MAX_INDEX
)
1228 return Right(GetLength()-i
-1);
1232 PDirectory
PFilePath::GetDirectory() const
1236 if ((i
= FindLast('/')) == P_MAX_INDEX
)
1243 BOOL
PFilePath::IsValid(char c
)
1249 BOOL
PFilePath::IsValid(const PString
& str
)
1251 return str
.Find('/') == P_MAX_INDEX
;
1255 ///////////////////////////////////////////////////////////////////////////////
1258 PConsoleChannel::PConsoleChannel()
1263 PConsoleChannel::PConsoleChannel(ConsoleType type
)
1269 BOOL
PConsoleChannel::Open(ConsoleType type
)
1272 case StandardInput
:
1276 case StandardOutput
:
1280 case StandardError
:
1289 PString
PConsoleChannel::GetName() const
1292 PAssertAlways("PConsoleChannel::GetName - Not implemented for VxWorks");
1293 return PString("Not Implemented");
1295 return ttyname(os_handle
);
1300 BOOL
PConsoleChannel::Close()
1307 //////////////////////////////////////////////////////
1316 clock_gettime(0,&ts
);
1317 theTime
= ts
.tv_sec
;
1318 microseconds
= ts
.tv_sec
*10000 + ts
.tv_nsec
/100000L;
1321 gettimeofday(&tv
, NULL
);
1322 theTime
= tv
.tv_sec
;
1323 microseconds
= tv
.tv_usec
;
1328 BOOL
PTime::GetTimeAMPM()
1330 #if defined(P_USE_LANGINFO)
1331 return strstr(nl_langinfo(T_FMT
), "%p") != NULL
;
1332 #elif defined(P_USE_STRFTIME)
1335 memset(&t
, 0, sizeof(t
));
1339 strftime(buf
, sizeof(buf
), "%X", &t
);
1340 return strstr(buf
, "20") != NULL
;
1342 #warning No AMPM implementation
1348 PString
PTime::GetTimeAM()
1350 #if defined(P_USE_LANGINFO)
1351 return PString(nl_langinfo(AM_STR
));
1352 #elif defined(P_USE_STRFTIME)
1355 memset(&t
, 0, sizeof(t
));
1359 strftime(buf
, sizeof(buf
), "%p", &t
);
1362 #warning Using default AM string
1368 PString
PTime::GetTimePM()
1370 #if defined(P_USE_LANGINFO)
1371 return PString(nl_langinfo(PM_STR
));
1372 #elif defined(P_USE_STRFTIME)
1375 memset(&t
, 0, sizeof(t
));
1379 strftime(buf
, sizeof(buf
), "%p", &t
);
1382 #warning Using default PM string
1388 PString
PTime::GetTimeSeparator()
1390 #if defined(P_LINUX) || defined(P_HPUX9) || defined(P_SOLARIS) || defined(P_IRIX)
1391 # if defined(P_USE_LANGINFO)
1392 char * p
= nl_langinfo(T_FMT
);
1393 # elif defined(P_LINUX)
1394 char * p
= _time_info
->time
;
1397 while (*p
== '%' || isalpha(*p
))
1401 return PString(buffer
);
1402 #elif defined(P_USE_STRFTIME)
1405 memset(&t
, 0, sizeof(t
));
1409 strftime(buf
, sizeof(buf
), "%X", &t
);
1410 char * sp
= strstr(buf
, "11") + 2;
1412 while (*ep
!= '\0' && !isdigit(*ep
))
1414 return PString(sp
, ep
-sp
);
1416 #warning Using default time separator
1421 PTime::DateOrder
PTime::GetDateOrder()
1423 #if defined(P_USE_LANGINFO) || defined(P_LINUX)
1424 # if defined(P_USE_LANGINFO)
1425 char * p
= nl_langinfo(D_FMT
);
1427 char * p
= _time_info
->date
;
1432 switch (tolower(*p
)) {
1434 return DayMonthYear
;
1436 return YearMonthDay
;
1441 return MonthDayYear
;
1443 #elif defined(P_USE_STRFTIME)
1446 memset(&t
, 0, sizeof(t
));
1450 strftime(buf
, sizeof(buf
), "%x", &t
);
1451 char * day_pos
= strstr(buf
, "22");
1452 char * mon_pos
= strstr(buf
, "11");
1453 char * yr_pos
= strstr(buf
, "99");
1454 if (yr_pos
< day_pos
)
1455 return YearMonthDay
;
1456 if (day_pos
< mon_pos
)
1457 return DayMonthYear
;
1458 return MonthDayYear
;
1460 #warning Using default date order
1461 return DayMonthYear
;
1465 PString
PTime::GetDateSeparator()
1467 #if defined(P_USE_LANGINFO) || defined(P_LINUX)
1468 # if defined(P_USE_LANGINFO)
1469 char * p
= nl_langinfo(D_FMT
);
1471 char * p
= _time_info
->date
;
1474 while (*p
== '%' || isalpha(*p
))
1478 return PString(buffer
);
1479 #elif defined(P_USE_STRFTIME)
1482 memset(&t
, 0, sizeof(t
));
1486 strftime(buf
, sizeof(buf
), "%x", &t
);
1487 char * sp
= strstr(buf
, "22") + 2;
1489 while (*ep
!= '\0' && !isdigit(*ep
))
1491 return PString(sp
, ep
-sp
);
1493 #warning Using default date separator
1498 PString
PTime::GetDayName(PTime::Weekdays day
, NameType type
)
1500 #if defined(P_USE_LANGINFO)
1502 (type
== Abbreviated
) ? nl_langinfo((nl_item
)(ABDAY_1
+(int)day
)) :
1503 nl_langinfo((nl_item
)(DAY_1
+(int)day
))
1506 #elif defined(P_LINUX)
1507 return (type
== Abbreviated
) ? PString(_time_info
->abbrev_wkday
[(int)day
]) :
1508 PString(_time_info
->full_wkday
[(int)day
]);
1510 #elif defined(P_USE_STRFTIME)
1513 memset(&t
, 0, sizeof(t
));
1515 strftime(buf
, sizeof(buf
), type
== Abbreviated
? "%a" : "%A", &t
);
1518 #warning Using default day names
1519 static char *defaultNames
[] = {
1520 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
1524 static char *defaultAbbrev
[] = {
1525 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1527 return (type
== Abbreviated
) ? PString(defaultNames
[(int)day
]) :
1528 PString(defaultAbbrev
[(int)day
]);
1532 PString
PTime::GetMonthName(PTime::Months month
, NameType type
)
1534 #if defined(P_USE_LANGINFO)
1536 (type
== Abbreviated
) ? nl_langinfo((nl_item
)(ABMON_1
+(int)month
-1)) :
1537 nl_langinfo((nl_item
)(MON_1
+(int)month
-1))
1539 #elif defined(P_LINUX)
1540 return (type
== Abbreviated
) ? PString(_time_info
->abbrev_month
[(int)month
-1]) :
1541 PString(_time_info
->full_month
[(int)month
-1]);
1542 #elif defined(P_USE_STRFTIME)
1545 memset(&t
, 0, sizeof(t
));
1547 strftime(buf
, sizeof(buf
), type
== Abbreviated
? "%b" : "%B", &t
);
1550 #warning Using default monthnames
1551 static char *defaultNames
[] = {
1552 "January", "February", "March", "April", "May", "June", "July", "August",
1553 "September", "October", "November", "December" };
1555 static char *defaultAbbrev
[] = {
1556 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
1557 "Sep", "Oct", "Nov", "Dec" };
1559 return (type
== Abbreviated
) ? PString(defaultNames
[(int)month
-1]) :
1560 PString(defaultAbbrev
[(int)month
-1]);
1565 BOOL
PTime::IsDaylightSavings()
1567 time_t theTime
= ::time(NULL
);
1569 return os_localtime(&theTime
, &ts
)->tm_isdst
!= 0;
1572 int PTime::GetTimeZone(PTime::TimeZoneType type
)
1574 #if defined(P_LINUX) || defined(P_SOLARIS) || defined (P_AIX) || defined(P_IRIX)
1575 long tz
= -::timezone
/60;
1576 if (type
== StandardTime
)
1579 return tz
+ ::daylight
*60;
1580 #elif defined(P_FREEBSD) || defined(P_OPENBSD) || defined(P_NETBSD) || defined(P_MACOSX) || defined(P_MACOS) || defined(__BEOS__) || defined(P_QNX)
1584 struct tm
* tm
= os_localtime(&t
, &ts
);
1585 int tz
= tm
->tm_gmtoff
/60;
1586 if (type
== StandardTime
&& tm
->tm_isdst
)
1588 if (type
!= StandardTime
&& !tm
->tm_isdst
)
1591 #elif defined(P_SUN4)
1594 if (type
== StandardTime
|| tb
.dstflag
== 0)
1595 return -tb
.timezone
;
1597 return -tb
.timezone
+ 60;
1599 #warning No timezone information
1604 PString
PTime::GetTimeZoneString(PTime::TimeZoneType type
)
1606 #if defined(P_LINUX) || defined(P_SUN4) || defined(P_SOLARIS) || defined (P_AIX) || defined(P_IRIX) || defined(P_QNX)
1607 const char * str
= (type
== StandardTime
) ? ::tzname
[0] : ::tzname
[1];
1611 #elif defined(P_USE_STRFTIME)
1614 memset(&t
, 0, sizeof(t
));
1615 t
.tm_isdst
= type
!= StandardTime
;
1616 strftime(buf
, sizeof(buf
), "%Z", &t
);
1619 #warning No timezone name information
1624 // note that PX_tm is local storage inside the PTime instance
1627 struct tm
* PTime::os_localtime(const time_t * clock
, struct tm
* ts
)
1630 #warning LOCALTIME_R NOT DEFINED
1631 return ::localtime(clock
);
1633 return ::localtime_r(clock
, ts
);
1637 struct tm
* PTime::os_localtime(const time_t * clock
, struct tm
*)
1639 return ::localtime(clock
);
1644 struct tm
* PTime::os_gmtime(const time_t * clock
, struct tm
* ts
)
1647 #warning GMTIME_R NOT DEFINED
1648 return ::gmtime(clock
);
1650 return ::gmtime_r(clock
, ts
);
1654 struct tm
* PTime::os_gmtime(const time_t * clock
, struct tm
*)
1656 return ::gmtime(clock
);
1660 // End Of File ///////////////////////////////////////////////////////////////